@tienne/gestalt 0.51.0 → 0.53.0

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 (69) hide show
  1. package/CLAUDE.md +7 -4
  2. package/dist/package.json +4 -3
  3. package/dist/plugin/review-agents/quality-reviewer/AGENT.md +30 -3
  4. package/dist/plugin/role-agents/_shared/references/README.md +13 -0
  5. package/dist/plugin/role-agents/_shared/references/ai-tell-quick-rules.md +66 -15
  6. package/dist/plugin/role-agents/_shared/references/style-guide.md +40 -0
  7. package/dist/plugin/role-agents/code-review-responder/AGENT.md +1 -1
  8. package/dist/plugin/role-agents/code-review-writer/AGENT.md +1 -1
  9. package/dist/plugin/role-agents/harness-architect/AGENT.md +1 -1
  10. package/dist/plugin/role-agents/humanize-monolith/AGENT.md +20 -2
  11. package/dist/plugin/role-agents/jira-writer/AGENT.md +11 -11
  12. package/dist/plugin/role-agents/slack-messenger/AGENT.md +1 -1
  13. package/dist/plugin/skills/dispatch/SKILL.md +3 -3
  14. package/dist/plugin/skills/execute/SKILL.md +1 -1
  15. package/dist/plugin/skills/jira-create/SKILL.md +5 -5
  16. package/dist/plugin/skills/presentation/SKILL.md +6 -6
  17. package/dist/plugin/skills/review-reply/SKILL.md +3 -3
  18. package/dist/plugin/skills/slack-send/SKILL.md +2 -2
  19. package/dist/src/cli/commands/humanize-check.d.ts +8 -0
  20. package/dist/src/cli/commands/humanize-check.d.ts.map +1 -0
  21. package/dist/src/cli/commands/humanize-check.js +29 -0
  22. package/dist/src/cli/commands/humanize-check.js.map +1 -0
  23. package/dist/src/cli/index.d.ts.map +1 -1
  24. package/dist/src/cli/index.js +11 -0
  25. package/dist/src/cli/index.js.map +1 -1
  26. package/dist/src/code-graph/rrf.d.ts +4 -4
  27. package/dist/src/code-graph/rrf.js +4 -4
  28. package/dist/src/execute/parallel-groups.d.ts +1 -1
  29. package/dist/src/execute/parallel-groups.js +1 -1
  30. package/dist/src/gestalt/surface-labels.d.ts +3 -3
  31. package/dist/src/gestalt/surface-labels.js +1 -1
  32. package/dist/src/humanize/change-rate.d.ts +13 -0
  33. package/dist/src/humanize/change-rate.d.ts.map +1 -0
  34. package/dist/src/humanize/change-rate.js +86 -0
  35. package/dist/src/humanize/change-rate.js.map +1 -0
  36. package/dist/src/humanize/check.d.ts +39 -0
  37. package/dist/src/humanize/check.d.ts.map +1 -0
  38. package/dist/src/humanize/check.js +150 -0
  39. package/dist/src/humanize/check.js.map +1 -0
  40. package/dist/src/humanize/detectors.d.ts +28 -0
  41. package/dist/src/humanize/detectors.d.ts.map +1 -0
  42. package/dist/src/humanize/detectors.js +134 -0
  43. package/dist/src/humanize/detectors.js.map +1 -0
  44. package/dist/src/humanize/index.d.ts +5 -0
  45. package/dist/src/humanize/index.d.ts.map +1 -0
  46. package/dist/src/humanize/index.js +5 -0
  47. package/dist/src/humanize/index.js.map +1 -0
  48. package/dist/src/humanize/rules.d.ts +34 -0
  49. package/dist/src/humanize/rules.d.ts.map +1 -0
  50. package/dist/src/humanize/rules.js +95 -0
  51. package/dist/src/humanize/rules.js.map +1 -0
  52. package/package.json +4 -3
  53. package/plugin/.codex-plugin/plugin.json +1 -1
  54. package/plugin/review-agents/quality-reviewer/AGENT.md +30 -3
  55. package/plugin/role-agents/_shared/references/README.md +13 -0
  56. package/plugin/role-agents/_shared/references/ai-tell-quick-rules.md +66 -15
  57. package/plugin/role-agents/_shared/references/style-guide.md +40 -0
  58. package/plugin/role-agents/code-review-responder/AGENT.md +1 -1
  59. package/plugin/role-agents/code-review-writer/AGENT.md +1 -1
  60. package/plugin/role-agents/harness-architect/AGENT.md +1 -1
  61. package/plugin/role-agents/humanize-monolith/AGENT.md +20 -2
  62. package/plugin/role-agents/jira-writer/AGENT.md +11 -11
  63. package/plugin/role-agents/slack-messenger/AGENT.md +1 -1
  64. package/plugin/skills/dispatch/SKILL.md +3 -3
  65. package/plugin/skills/execute/SKILL.md +1 -1
  66. package/plugin/skills/jira-create/SKILL.md +5 -5
  67. package/plugin/skills/presentation/SKILL.md +6 -6
  68. package/plugin/skills/review-reply/SKILL.md +3 -3
  69. package/plugin/skills/slack-send/SKILL.md +2 -2
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: presentation
3
3
  version: "1.0.0"
4
- description: "발표 자료를 콘텐츠와 디자인으로 나눠 만드는 스킬. presentation-writer가 슬라이드 콘텐츠를 쓰고 presentation-designer가 Reveal.js HTML로 조립하며, 승인 게이트를 거쳐 산출한다. '발표자료 만들어줘', '슬라이드 만들어줘', '프레젠테이션 제작', '덱 만들어줘', '피치덱' 요청에 반드시 사용. 콘텐츠 자문만 필요하면 presentation-writer, 디자인 자문만 필요하면 presentation-designer를 직접 호출."
4
+ description: "발표 자료를 콘텐츠와 디자인으로 나눠 만드는 스킬. presentation-writer가 슬라이드 콘텐츠를 쓰고 presentation-designer가 Reveal.js HTML로 조립하며, 승인 단계를 거쳐 산출한다. '발표자료 만들어줘', '슬라이드 만들어줘', '프레젠테이션 제작', '덱 만들어줘', '피치덱' 요청에 반드시 사용. 콘텐츠 자문만 필요하면 presentation-writer, 디자인 자문만 필요하면 presentation-designer를 직접 호출."
5
5
  triggers:
6
6
  - "발표자료 만들"
7
7
  - "발표 자료 만들"
@@ -35,9 +35,9 @@ outputs:
35
35
 
36
36
  > **에이전트 tier로 모델 고르기** → [`../_shared/agent-model.md`](../_shared/agent-model.md)
37
37
  발표 자료를 **콘텐츠 먼저, 디자인 나중** 순서로 만드는 파이프라인.
38
- `presentation-writer`(슬라이드 콘텐츠)와 `presentation-designer`(Reveal.js HTML)를 잇고, 산출 전 승인 게이트를 둔다.
38
+ `presentation-writer`(슬라이드 콘텐츠)와 `presentation-designer`(Reveal.js HTML)를 잇고, 산출 전 승인 단계를 둔다.
39
39
 
40
- > **불변 규칙: 승인 없이는 최종 HTML을 산출하지 않는다.** 콘텐츠 개요를 미리보기로 보여주고 사용자의 명시적 "OK"를 받은 뒤에만 디자인·HTML 생성으로 넘어간다. 디자인에 워딩을 끼워 맞추는 실수, 방향이 어긋난 발표를 통째로 다시 그리는 낭비를 막는 게 이 게이트의 이유다.
40
+ > **불변 규칙: 승인 없이는 최종 HTML을 산출하지 않는다.** 콘텐츠 개요를 미리보기로 보여주고 사용자의 명시적 "OK"를 받은 뒤에만 디자인·HTML 생성으로 넘어간다. 디자인에 워딩을 끼워 맞추는 실수, 방향이 어긋난 발표를 통째로 다시 그리는 낭비를 막는 게 이 단계의 이유다.
41
41
 
42
42
  ## 파이프라인
43
43
 
@@ -57,7 +57,7 @@ outputs:
57
57
 
58
58
  산출은 슬라이드 번호별 콘텐츠 블록(제목 / 핵심 메시지 / 본문 포인트 / 데이터+맥락 / 발표 노트 / 제안 슬라이드 성격). 수치가 없으면 지어내지 않고 `[데이터 필요: ...]`로 남겨 작성자에게 요청한다.
59
59
 
60
- ### 3. 승인 게이트 (필수)
60
+ ### 3. 승인 단계 (필수)
61
61
 
62
62
  콘텐츠 개요를 한 화면에 모아 보여주고 명시적 승인을 받는다.
63
63
 
@@ -119,6 +119,6 @@ outputs:
119
119
 
120
120
  **정상 흐름**: `/presentation "3분기 성과 발표" audience=exec` → 주제·청중·분량 확정 → presentation-writer 콘텐츠 블록 → 콘텐츠 개요 미리보기 → 사용자 "OK" → presentation-designer가 Signal 템플릿으로 HTML 생성 → 경로 반환.
121
121
 
122
- **입력 부족 흐름**: `/presentation` 만 입력 → 주제·청중·분량을 미니 인터뷰로 확정 → 수치가 없는 슬라이드는 `[데이터 필요]`로 남기고 요청 → 콘텐츠 확정 후 승인 게이트.
122
+ **입력 부족 흐름**: `/presentation` 만 입력 → 주제·청중·분량을 미니 인터뷰로 확정 → 수치가 없는 슬라이드는 `[데이터 필요]`로 남기고 요청 → 콘텐츠 확정 후 승인 단계.
123
123
 
124
- **승인 게이트 흐름**: 콘텐츠 개요 제시 후 사용자가 "3번 슬라이드 메시지 바꿔줘" → 2단계로 돌아가 콘텐츠 수정 → 재확인 → 승인 후에만 HTML 생성.
124
+ **승인 단계 흐름**: 콘텐츠 개요 제시 후 사용자가 "3번 슬라이드 메시지 바꿔줘" → 2단계로 돌아가 콘텐츠 수정 → 재확인 → 승인 후에만 HTML 생성.
@@ -126,7 +126,7 @@ gh api repos/<owner>/<repo>/issues/<number>/comments --jq '.[] | {id, user: .use
126
126
  - 리뷰 이후 그 부분이 이미 바뀌었으면 기록해둔다 — 답변 유형이 accept가 아니라 "이미 처리됨"이 된다.
127
127
  - 코멘트가 여러 파일에 걸친 구조적인 내용이면 관련 파일까지 읽는다. 영향범위가 불확실하면 `ges_code_graph { action: "blast_radius" }`를 쓴다.
128
128
 
129
- ### 3단계: 유형 분류 + 승인 게이트 1 (필수)
129
+ ### 3단계: 유형 분류 + 승인 단계 1 (필수)
130
130
 
131
131
  스레드마다 처리 방향을 제안한다. 분류는 `code-review-responder`의 네 유형을 쓴다.
132
132
 
@@ -137,7 +137,7 @@ gh api repos/<owner>/<repo>/issues/<number>/comments --jq '.[] | {id, user: .use
137
137
  | `defer` | 지금은 안 고치는 편이 낫다 | 없음 |
138
138
  | `clarify` | 의도를 못 잡았다 — 되묻는다 | 없음 |
139
139
 
140
- 분류표를 보여주고 **사용자가 확정**하게 한다. 이 게이트가 스킬의 핵심이다 — 무엇을 수용하고 무엇을 반박할지는 코드가 아니라 사람이 정한다.
140
+ 분류표를 보여주고 **사용자가 확정**하게 한다. 이 단계가 스킬의 핵심이다 — 무엇을 수용하고 무엇을 반박할지는 코드가 아니라 사람이 정한다.
141
141
 
142
142
  ```
143
143
  받은 코멘트 4건의 처리 방향을 이렇게 봤어요. 바꿀 게 있으면 말씀해주세요.
@@ -178,7 +178,7 @@ gh pr view <number> --json url --jq .url # 커밋 링크 조립용 base
178
178
  git status -sb # ahead/behind 확인
179
179
  ```
180
180
 
181
- ### 5단계: 답글 작성 (code-review-responder) + 승인 게이트 2 (필수)
181
+ ### 5단계: 답글 작성 (code-review-responder) + 승인 단계 2 (필수)
182
182
 
183
183
  답글 본문은 반드시 `code-review-responder` 에이전트가 쓴다. Claude가 즉흥으로 쓰지 않는다 — 그래야 어투가 매번 일정하다.
184
184
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: slack-send
3
3
  version: "1.0.0"
4
- description: "슬랙 메시지를 권윤학님 어투로 다듬어 승인 게이트를 거친 뒤 전송하거나 예약한다. 메시지를 '보내달라/전달해달라/공지해달라/예약 발송해달라'는 요청 시 자동 발동. slack-messenger로 초안 → 채널과 발송 시각 확인 → 미리보기 승인 → slack_send_message/slack_schedule_message. 전송까지 하는 스킬이다. 문구만 다듬고 보내지는 않으려면 slack-messenger를 호출한다."
4
+ description: "슬랙 메시지를 권윤학님 어투로 다듬어 승인 단계를 거친 뒤 전송하거나 예약한다. 메시지를 '보내달라/전달해달라/공지해달라/예약 발송해달라'는 요청 시 자동 발동. slack-messenger로 초안 → 채널과 발송 시각 확인 → 미리보기 승인 → slack_send_message/slack_schedule_message. 전송까지 하는 스킬이다. 문구만 다듬고 보내지는 않으려면 slack-messenger를 호출한다."
5
5
  triggers:
6
6
  # 전송 의도
7
7
  - "슬랙 보내"
@@ -74,7 +74,7 @@ outputs:
74
74
  - DM: `slack_search_users`로 상대 → `user_id`(그대로 channel_id로 사용).
75
75
  - 확정한 채널명·ID를 사용자에게 노출해 **대상이 맞는지 확인**한다.
76
76
 
77
- ### 4. 미리보기 + 승인 게이트 (필수)
77
+ ### 4. 미리보기 + 승인 단계 (필수)
78
78
 
79
79
  아래를 한 화면에 모아 보여주고 명시적 승인을 받는다.
80
80
 
@@ -0,0 +1,8 @@
1
+ export interface HumanizeCheckOptions {
2
+ before: string;
3
+ after: string;
4
+ register?: string;
5
+ json?: boolean;
6
+ }
7
+ export declare function humanizeCheckCommand(options: HumanizeCheckOptions): void;
8
+ //# sourceMappingURL=humanize-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"humanize-check.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/humanize-check.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAWD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAmBxE"}
@@ -0,0 +1,29 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import { formatReport, runCheck, EXIT_CODE } from '../../humanize/index.js';
4
+ function read(label, path) {
5
+ const full = resolve(process.cwd(), path);
6
+ if (!existsSync(full)) {
7
+ console.error(`${label} 파일이 없습니다: ${full}`);
8
+ process.exit(EXIT_CODE.unknown);
9
+ }
10
+ return readFileSync(full, 'utf-8');
11
+ }
12
+ export function humanizeCheckCommand(options) {
13
+ const register = options.register === 'chat' ? 'chat' : 'doc';
14
+ const before = read('원문', options.before);
15
+ const after = read('윤문본', options.after);
16
+ if (before.trim().length === 0) {
17
+ console.error('원문이 비어 있어 판정할 수 없습니다.');
18
+ process.exit(EXIT_CODE.unknown);
19
+ }
20
+ const report = runCheck(before, after, { register });
21
+ if (options.json) {
22
+ console.log(JSON.stringify(report, null, 2));
23
+ }
24
+ else {
25
+ console.log(formatReport(report));
26
+ }
27
+ process.exit(report.exitCode);
28
+ }
29
+ //# sourceMappingURL=humanize-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"humanize-check.js","sourceRoot":"","sources":["../../../../src/cli/commands/humanize-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAU5E,SAAS,IAAI,CAAC,KAAa,EAAE,IAAY;IACvC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;IAC1C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,cAAc,IAAI,EAAE,CAAC,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,OAA6B;IAChE,MAAM,QAAQ,GAAa,OAAO,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;IACxE,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAEzC,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACvC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IAED,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;IAErD,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;IACpC,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,wBAAgB,SAAS,IAAI,OAAO,CAsFnC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAapC,wBAAgB,SAAS,IAAI,OAAO,CAiGnC"}
@@ -8,6 +8,7 @@ import { initCommand } from './commands/init.js';
8
8
  import { graphVisualizeCommand } from './commands/graph-visualize.js';
9
9
  import { updateCommand } from './commands/update.js';
10
10
  import { usageReportCommand } from './commands/usage-report.js';
11
+ import { humanizeCheckCommand } from './commands/humanize-check.js';
11
12
  import { getVersion } from '../core/version.js';
12
13
  export function createCli() {
13
14
  const program = new Command();
@@ -73,6 +74,16 @@ export function createCli() {
73
74
  noBrowser: options.browser === false,
74
75
  });
75
76
  });
77
+ program
78
+ .command('humanize-check')
79
+ .description('Judge a humanized draft against the rulebook (exit 0 pass / 1 warn / 2 abort)')
80
+ .requiredOption('--before <path>', 'Original text file')
81
+ .requiredOption('--after <path>', 'Humanized text file')
82
+ .option('--register <doc|chat>', 'Register to judge against (default: doc)', 'doc')
83
+ .option('--json', 'Emit the full report as JSON')
84
+ .action((options) => {
85
+ humanizeCheckCommand(options);
86
+ });
76
87
  program
77
88
  .command('usage-report')
78
89
  .description('Show event frequency report grouped by event type')
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":"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"}
@@ -3,13 +3,13 @@ export interface ScoredFile {
3
3
  score: number;
4
4
  }
5
5
  /**
6
- * Reciprocal Rank Fusion — 여러 랭킹 리스트를 하나로 합산한다.
6
+ * Reciprocal Rank Fusion — 여러 순위 목록을 하나로 합산한다.
7
7
  *
8
- * 각 리스트의 항목에 대해 1/(k + rank) 점수를 누적하고,
8
+ * 각 목록의 항목마다 1/(k + rank) 점수를 누적하고,
9
9
  * 내림차순으로 정렬하여 반환한다.
10
10
  *
11
- * @param lists - ScoredFile 랭킹 리스트 배열 (0-based index가 rank로 사용됨)
12
- * @param k - RRF 상수 (default: 60). 높을수록 하위 랭크의 영향이 줄어든다.
11
+ * @param lists - ScoredFile 순위 목록 배열 (0-based index가 rank로 사용됨)
12
+ * @param k - RRF 상수 (default: 60). 높을수록 하위 순위의 영향이 줄어든다.
13
13
  */
14
14
  export declare function reciprocalRankFusion(lists: ScoredFile[][], k?: number): ScoredFile[];
15
15
  //# sourceMappingURL=rrf.d.ts.map
@@ -1,11 +1,11 @@
1
1
  /**
2
- * Reciprocal Rank Fusion — 여러 랭킹 리스트를 하나로 합산한다.
2
+ * Reciprocal Rank Fusion — 여러 순위 목록을 하나로 합산한다.
3
3
  *
4
- * 각 리스트의 항목에 대해 1/(k + rank) 점수를 누적하고,
4
+ * 각 목록의 항목마다 1/(k + rank) 점수를 누적하고,
5
5
  * 내림차순으로 정렬하여 반환한다.
6
6
  *
7
- * @param lists - ScoredFile 랭킹 리스트 배열 (0-based index가 rank로 사용됨)
8
- * @param k - RRF 상수 (default: 60). 높을수록 하위 랭크의 영향이 줄어든다.
7
+ * @param lists - ScoredFile 순위 목록 배열 (0-based index가 rank로 사용됨)
8
+ * @param k - RRF 상수 (default: 60). 높을수록 하위 순위의 영향이 줄어든다.
9
9
  */
10
10
  export function reciprocalRankFusion(lists, k = 60) {
11
11
  const scoreMap = new Map();
@@ -25,7 +25,7 @@ export declare function buildDepMap(tasks: AtomicTask[]): Map<string, Set<string
25
25
  export declare function computeReadyTaskIds(tasks: AtomicTask[], topologicalOrder: string[], completedTaskIds: string[]): string[];
26
26
  /**
27
27
  * DAG 위상 정렬 기반으로 병렬 실행 가능한 태스크 그룹을 계산한다.
28
- * 동일 레이어의 태스크들은 의존성이 없어 동시에 실행 가능하다.
28
+ * 같은 묶음에 있는 태스크는 의존성이 없어 동시에 실행 가능하다.
29
29
  *
30
30
  * @returns string[][] — 각 배열이 동시 실행 가능한 태스크 ID 목록
31
31
  */
@@ -47,7 +47,7 @@ export function computeReadyTaskIds(tasks, topologicalOrder, completedTaskIds) {
47
47
  }
48
48
  /**
49
49
  * DAG 위상 정렬 기반으로 병렬 실행 가능한 태스크 그룹을 계산한다.
50
- * 동일 레이어의 태스크들은 의존성이 없어 동시에 실행 가능하다.
50
+ * 같은 묶음에 있는 태스크는 의존성이 없어 동시에 실행 가능하다.
51
51
  *
52
52
  * @returns string[][] — 각 배열이 동시 실행 가능한 태스크 ID 목록
53
53
  */
@@ -1,12 +1,12 @@
1
1
  import { GestaltPrinciple } from '../core/types.js';
2
2
  /**
3
- * 표면/심층 분리 (Figure-Ground) 표면 레이어 단일 소스.
3
+ * 표면/심층 분리 (Figure-Ground)에서 표면 문자열을 정의하는 단 한 곳.
4
4
  *
5
5
  * 코드 내부는 게슈탈트 원리(GestaltPrinciple enum)와 에이전트 식별자를 그대로 쓰지만,
6
6
  * 사용자에게 돌려주는 표면 문자열에는 게슈탈트 용어가 새어 나가면 안 된다.
7
7
  * 이 모듈이 내부 식별자를 평범한 한국어·영어 문구로 잇는 유일한 매핑 지점이다.
8
8
  *
9
- * 심층 레이어(README·docs·LLM 시스템 프롬프트·내부 타입) 이 모듈을 거치지 않고
9
+ * 심층 (README, docs, LLM 시스템 프롬프트, 내부 타입) 이 모듈을 거치지 않고
10
10
  * 게슈탈트 어휘를 그대로 유지한다.
11
11
  */
12
12
  export type SurfaceLang = 'ko' | 'en';
@@ -34,7 +34,7 @@ export declare function getConsistencyHint(lang?: SurfaceLang): string;
34
34
  */
35
35
  export declare const BANNED_SURFACE_TERMS: readonly string[];
36
36
  /**
37
- * MCP 도구 응답에서 심층 레이어(LLM 지시 프롬프트) 필드 키.
37
+ * MCP 도구 응답에서 심층 (LLM 지시 프롬프트) 필드 키.
38
38
  * 이 필드들은 게슈탈트 어휘를 담은 채 유지되므로 표면 누수 검사 대상에서 제외한다.
39
39
  */
40
40
  export declare const DEEP_PROMPT_KEYS: readonly string[];
@@ -88,7 +88,7 @@ export const BANNED_SURFACE_TERMS = [
88
88
  'gestalt',
89
89
  ];
90
90
  /**
91
- * MCP 도구 응답에서 심층 레이어(LLM 지시 프롬프트) 필드 키.
91
+ * MCP 도구 응답에서 심층 (LLM 지시 프롬프트) 필드 키.
92
92
  * 이 필드들은 게슈탈트 어휘를 담은 채 유지되므로 표면 누수 검사 대상에서 제외한다.
93
93
  */
94
94
  export const DEEP_PROMPT_KEYS = [
@@ -0,0 +1,13 @@
1
+ /**
2
+ * 변경률 — 원문과 윤문본이 얼마나 달라졌는지.
3
+ *
4
+ * 어절 단위 LCS로 측정한다. 문자 단위 DP는 1만자만 넘어가도 셀이 억 단위라 못 쓰고,
5
+ * 어절 단위면 같은 글이 수천 토큰이라 DP가 그대로 돈다.
6
+ * 공식은 1 - 2·LCS / (len(a) + len(b)) — difflib.SequenceMatcher.ratio()와 같다.
7
+ */
8
+ export interface ChangeRateOptions {
9
+ /** 헤딩·불릿 산문화로 부풀려진 변경률을 걷어내고 본문만 비교 */
10
+ ignoreMarkup?: boolean;
11
+ }
12
+ export declare function changeRate(before: string, after: string, options?: ChangeRateOptions): number;
13
+ //# sourceMappingURL=change-rate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"change-rate.d.ts","sourceRoot":"","sources":["../../../src/humanize/change-rate.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,MAAM,WAAW,iBAAiB;IAChC,uCAAuC;IACvC,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAuED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,MAAM,CAWjG"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * 변경률 — 원문과 윤문본이 얼마나 달라졌는지.
3
+ *
4
+ * 어절 단위 LCS로 측정한다. 문자 단위 DP는 1만자만 넘어가도 셀이 억 단위라 못 쓰고,
5
+ * 어절 단위면 같은 글이 수천 토큰이라 DP가 그대로 돈다.
6
+ * 공식은 1 - 2·LCS / (len(a) + len(b)) — difflib.SequenceMatcher.ratio()와 같다.
7
+ */
8
+ /** 어절이 이 수를 넘으면 DP를 포기하고 순서를 무시한 겹침 비율로 떨어뜨린다 */
9
+ const TOKEN_DP_CAP = 6000;
10
+ const SUMMARY_BLOCK = /<!--\s*HUMANIZE-SUMMARY[\s\S]*?-->/g;
11
+ const MARKUP = /^\s{0,3}(?:#{1,6}\s+|[-*+]\s+|\d+\.\s+|>\s?)|[*_`~]|^\s*\|.*\|\s*$/gm;
12
+ function normalize(text, ignoreMarkup) {
13
+ let out = text.replace(SUMMARY_BLOCK, ' ');
14
+ if (ignoreMarkup)
15
+ out = out.replace(MARKUP, ' ');
16
+ return out.replace(/\s+/g, ' ').trim();
17
+ }
18
+ function tokenize(text) {
19
+ return text.split(' ').filter(Boolean);
20
+ }
21
+ function lcsLength(a, b) {
22
+ if (a.length === 0 || b.length === 0)
23
+ return 0;
24
+ // 앞뒤로 그대로인 구간은 DP에 넣을 이유가 없다
25
+ let head = 0;
26
+ while (head < a.length && head < b.length && a[head] === b[head])
27
+ head += 1;
28
+ let tail = 0;
29
+ while (tail < a.length - head &&
30
+ tail < b.length - head &&
31
+ a[a.length - 1 - tail] === b[b.length - 1 - tail]) {
32
+ tail += 1;
33
+ }
34
+ const midA = a.slice(head, a.length - tail);
35
+ const midB = b.slice(head, b.length - tail);
36
+ const common = head + tail;
37
+ if (midA.length === 0 || midB.length === 0)
38
+ return common;
39
+ const rows = midA.length + 1;
40
+ const cols = midB.length + 1;
41
+ let prev = new Uint32Array(cols);
42
+ let curr = new Uint32Array(cols);
43
+ for (let i = 1; i < rows; i += 1) {
44
+ const ai = midA[i - 1];
45
+ for (let j = 1; j < cols; j += 1) {
46
+ curr[j] = ai === midB[j - 1] ? prev[j - 1] + 1 : Math.max(prev[j], curr[j - 1]);
47
+ }
48
+ const swap = prev;
49
+ prev = curr;
50
+ curr = swap;
51
+ curr.fill(0);
52
+ }
53
+ return common + prev[cols - 1];
54
+ }
55
+ /**
56
+ * 순서를 버리고 어절 다중집합의 겹침만 센다.
57
+ * DP를 돌릴 수 없는 크기에서 쓰는 근사치라 실제보다 변경률을 낮게 본다 — 검사가
58
+ * 놓칠지언정 없는 과윤문을 만들어내지는 않는 쪽으로 틀렸다.
59
+ */
60
+ function overlapCount(a, b) {
61
+ const counts = new Map();
62
+ for (const token of a)
63
+ counts.set(token, (counts.get(token) ?? 0) + 1);
64
+ let common = 0;
65
+ for (const token of b) {
66
+ const left = counts.get(token) ?? 0;
67
+ if (left > 0) {
68
+ counts.set(token, left - 1);
69
+ common += 1;
70
+ }
71
+ }
72
+ return common;
73
+ }
74
+ export function changeRate(before, after, options = {}) {
75
+ const ignoreMarkup = options.ignoreMarkup ?? false;
76
+ const a = tokenize(normalize(before, ignoreMarkup));
77
+ const b = tokenize(normalize(after, ignoreMarkup));
78
+ if (a.length === 0 && b.length === 0)
79
+ return 0;
80
+ if (a.length === 0 || b.length === 0)
81
+ return 1;
82
+ const tooBig = a.length > TOKEN_DP_CAP || b.length > TOKEN_DP_CAP;
83
+ const common = tooBig ? overlapCount(a, b) : lcsLength(a, b);
84
+ return 1 - (2 * common) / (a.length + b.length);
85
+ }
86
+ //# sourceMappingURL=change-rate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"change-rate.js","sourceRoot":"","sources":["../../../src/humanize/change-rate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import { type Register, type RuleBook } from './rules.js';
2
+ export type Verdict = 'pass' | 'warn' | 'abort';
3
+ export declare const EXIT_CODE: Record<Verdict | 'unknown', number>;
4
+ export declare const THRESHOLD: {
5
+ readonly changeWarn: 0.3;
6
+ readonly changeAbort: 0.5;
7
+ readonly sentenceDrop: 0.25;
8
+ };
9
+ export interface AxisResult {
10
+ axis: 'change-rate' | 'residual-s1' | 'preservation' | 'structure';
11
+ verdict: Verdict;
12
+ detail: string;
13
+ evidence?: string[];
14
+ }
15
+ export interface CheckReport {
16
+ register: Register;
17
+ verdict: Verdict;
18
+ exitCode: number;
19
+ changeRate: number;
20
+ changeRateNoMarkup: number;
21
+ axes: AxisResult[];
22
+ residualS1: {
23
+ ruleId: string;
24
+ before: number;
25
+ after: number;
26
+ }[];
27
+ introduced: {
28
+ ruleId: string;
29
+ before: number;
30
+ after: number;
31
+ }[];
32
+ }
33
+ export interface RunCheckOptions {
34
+ register?: Register;
35
+ book?: RuleBook;
36
+ }
37
+ export declare function runCheck(before: string, after: string, options?: RunCheckOptions): CheckReport;
38
+ export declare function formatReport(report: CheckReport): string;
39
+ //# sourceMappingURL=check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/humanize/check.ts"],"names":[],"mappings":"AASA,OAAO,EAAwB,KAAK,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEhF,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEhD,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,OAAO,GAAG,SAAS,EAAE,MAAM,CAKzD,CAAC;AAEF,eAAO,MAAM,SAAS;;;;CAIZ,CAAC;AAEX,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,aAAa,GAAG,aAAa,GAAG,cAAc,GAAG,WAAW,CAAC;IACnE,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,IAAI,EAAE,UAAU,EAAE,CAAC;IACnB,UAAU,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAChE,UAAU,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACjE;AAsHD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,IAAI,CAAC,EAAE,QAAQ,CAAC;CACjB;AAED,wBAAgB,QAAQ,CACtB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,eAAoB,GAC5B,WAAW,CA0Bb;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAaxD"}
@@ -0,0 +1,150 @@
1
+ /**
2
+ * 윤문 결과를 코드가 판단하는 검사.
3
+ *
4
+ * 모델이 스스로 매긴 변경률·등급은 참고값이다. 문자 기반 변경률 하나로는
5
+ * 구조 편집이 안 보인다 — 변경률 2.8%인데 문장 3할이 갈려나간 사례가 있다.
6
+ * 그래서 변경률, 잔존, 보존, 구조 4가지 측면에서 각각 측정하고, 판단한다.
7
+ */
8
+ import { changeRate } from './change-rate.js';
9
+ import { countByRule, missingProtectedTokens, structureStats } from './detectors.js';
10
+ import { parseRuleBook, s1Ids } from './rules.js';
11
+ export const EXIT_CODE = {
12
+ pass: 0,
13
+ warn: 1,
14
+ abort: 2,
15
+ unknown: 3,
16
+ };
17
+ export const THRESHOLD = {
18
+ changeWarn: 0.3,
19
+ changeAbort: 0.5,
20
+ sentenceDrop: 0.25,
21
+ };
22
+ const WORST = { pass: 0, warn: 1, abort: 2 };
23
+ function worst(verdicts) {
24
+ return verdicts.reduce((acc, v) => (WORST[v] > WORST[acc] ? v : acc), 'pass');
25
+ }
26
+ function pct(value) {
27
+ return `${(value * 100).toFixed(1)}%`;
28
+ }
29
+ function checkChangeRate(rate, rateNoMarkup) {
30
+ const detail = `변경률 ${pct(rate)} (마크업 제외 ${pct(rateNoMarkup)})`;
31
+ if (rate >= THRESHOLD.changeAbort) {
32
+ return { axis: 'change-rate', verdict: 'abort', detail: `${detail} — 50% 이상, 채택 금지` };
33
+ }
34
+ if (rate >= THRESHOLD.changeWarn) {
35
+ return { axis: 'change-rate', verdict: 'warn', detail: `${detail} — 30% 이상, 과윤문 의심` };
36
+ }
37
+ return { axis: 'change-rate', verdict: 'pass', detail };
38
+ }
39
+ function checkResidualS1(book, register, before, after) {
40
+ const targets = s1Ids(book, register);
41
+ const beforeCounts = countByRule(before, targets);
42
+ const afterCounts = countByRule(after, targets);
43
+ const residual = targets
44
+ .map((ruleId) => ({
45
+ ruleId,
46
+ before: beforeCounts.get(ruleId) ?? 0,
47
+ after: afterCounts.get(ruleId) ?? 0,
48
+ }))
49
+ .filter((row) => row.after > 0);
50
+ if (residual.length === 0) {
51
+ return {
52
+ axis: { axis: 'residual-s1', verdict: 'pass', detail: 'S1 잔존 0건' },
53
+ residual,
54
+ };
55
+ }
56
+ const evidence = residual.map((row) => `${row.ruleId}: ${row.before} → ${row.after}`);
57
+ return {
58
+ axis: {
59
+ axis: 'residual-s1',
60
+ verdict: 'warn',
61
+ detail: `S1 ${residual.length}종 잔존`,
62
+ evidence,
63
+ },
64
+ residual,
65
+ };
66
+ }
67
+ /** 철칙 — AI 티는 빼기만 하고 넣지 않는다. 늘어난 룰이 있으면 윤문이 새 티를 심은 것이다 */
68
+ function findIntroduced(before, after) {
69
+ const beforeCounts = countByRule(before);
70
+ const afterCounts = countByRule(after);
71
+ return [...afterCounts.entries()]
72
+ .map(([ruleId, count]) => ({ ruleId, before: beforeCounts.get(ruleId) ?? 0, after: count }))
73
+ .filter((row) => row.after > row.before)
74
+ .sort((a, b) => b.after - b.before - (a.after - a.before));
75
+ }
76
+ function checkPreservation(before, after) {
77
+ const missing = missingProtectedTokens(before, after);
78
+ if (missing.length === 0) {
79
+ return { axis: 'preservation', verdict: 'pass', detail: '수치·인용·코드·고유명사 전부 생존' };
80
+ }
81
+ return {
82
+ axis: 'preservation',
83
+ verdict: 'abort',
84
+ detail: `보호 토큰 ${missing.length}건 유실 — 의미 불변 위반`,
85
+ evidence: missing.slice(0, 10),
86
+ };
87
+ }
88
+ function checkStructure(before, after, introduced) {
89
+ const a = structureStats(before);
90
+ const b = structureStats(after);
91
+ const problems = [];
92
+ const drop = a.sentences === 0 ? 0 : (a.sentences - b.sentences) / a.sentences;
93
+ if (drop > THRESHOLD.sentenceDrop) {
94
+ problems.push(`문장 ${a.sentences} → ${b.sentences} (${pct(drop)} 감소) — 내용 유실 의심`);
95
+ }
96
+ if (b.codeFences < a.codeFences) {
97
+ problems.push(`코드블록 ${a.codeFences / 2} → ${b.codeFences / 2}`);
98
+ }
99
+ if (b.links < a.links) {
100
+ problems.push(`링크 ${a.links} → ${b.links}`);
101
+ }
102
+ for (const row of introduced.slice(0, 5)) {
103
+ problems.push(`${row.ruleId} 신규 유입 ${row.before} → ${row.after}`);
104
+ }
105
+ if (problems.length === 0) {
106
+ return { axis: 'structure', verdict: 'pass', detail: '구조·정보량 보존' };
107
+ }
108
+ return {
109
+ axis: 'structure',
110
+ verdict: 'warn',
111
+ detail: `구조 이상 ${problems.length}건`,
112
+ evidence: problems,
113
+ };
114
+ }
115
+ export function runCheck(before, after, options = {}) {
116
+ const register = options.register ?? 'doc';
117
+ const book = options.book ?? parseRuleBook();
118
+ const rate = changeRate(before, after);
119
+ const rateNoMarkup = changeRate(before, after, { ignoreMarkup: true });
120
+ const changeAxis = checkChangeRate(rate, rateNoMarkup);
121
+ const { axis: s1Axis, residual } = checkResidualS1(book, register, before, after);
122
+ const preservationAxis = checkPreservation(before, after);
123
+ const introduced = findIntroduced(before, after);
124
+ const structureAxis = checkStructure(before, after, introduced);
125
+ const axes = [changeAxis, s1Axis, preservationAxis, structureAxis];
126
+ const verdict = worst(axes.map((a) => a.verdict));
127
+ return {
128
+ register,
129
+ verdict,
130
+ exitCode: EXIT_CODE[verdict],
131
+ changeRate: rate,
132
+ changeRateNoMarkup: rateNoMarkup,
133
+ axes,
134
+ residualS1: residual,
135
+ introduced,
136
+ };
137
+ }
138
+ export function formatReport(report) {
139
+ const head = `검사 ${report.verdict.toUpperCase()} (exit ${report.exitCode}) / 말투 ${report.register}`;
140
+ const lines = [head, ''];
141
+ for (const axis of report.axes) {
142
+ const mark = axis.verdict === 'pass' ? 'OK' : axis.verdict === 'warn' ? '경고' : '중단';
143
+ lines.push(`[${mark}] ${axis.axis} — ${axis.detail}`);
144
+ for (const item of axis.evidence ?? []) {
145
+ lines.push(` ${item}`);
146
+ }
147
+ }
148
+ return lines.join('\n');
149
+ }
150
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/humanize/check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * 룰 ID별 결정적 탐지기.
3
+ *
4
+ * 여기 있는 건 정규식만으로 오탐 없이 셀 수 있는 룰뿐이다. D-5 의인화 주어처럼
5
+ * 뜻을 봐야 판단되는 룰은 일부러 뺐다 — 검사가 오탐으로 멈추면 아무도 안 쓴다.
6
+ * 탐지기가 없는 룰은 모델이 자체검증으로 본다.
7
+ */
8
+ export interface Detection {
9
+ ruleId: string;
10
+ count: number;
11
+ samples: string[];
12
+ }
13
+ export declare function splitSentences(text: string): string[];
14
+ export declare const DETECTABLE_RULE_IDS: string[];
15
+ export declare function detect(text: string, ruleIds?: readonly string[]): Detection[];
16
+ export declare function countByRule(text: string, ruleIds?: readonly string[]): Map<string, number>;
17
+ /** 원문에서 한 글자도 바뀌면 안 되는 토큰을 뽑는다 */
18
+ export declare function protectedTokens(text: string): string[];
19
+ export declare function missingProtectedTokens(before: string, after: string): string[];
20
+ export interface StructureStats {
21
+ sentences: number;
22
+ headings: number;
23
+ bullets: number;
24
+ codeFences: number;
25
+ links: number;
26
+ }
27
+ export declare function structureStats(text: string): StructureStats;
28
+ //# sourceMappingURL=detectors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detectors.d.ts","sourceRoot":"","sources":["../../../src/humanize/detectors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AA8CD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAKrD;AA4CD,eAAO,MAAM,mBAAmB,EAAE,MAAM,EAAmC,CAAC;AAE5E,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAAE,CAgB7E;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAE1F;AAcD,kCAAkC;AAClC,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAStD;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAE9E;AAID,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAS3D"}