@tienne/gestalt 0.50.0 → 0.52.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 (104) hide show
  1. package/CLAUDE.md +8 -5
  2. package/dist/package.json +4 -3
  3. package/dist/plugin/role-agents/_shared/references/README.md +13 -0
  4. package/dist/plugin/role-agents/_shared/references/ai-tell-quick-rules.md +66 -15
  5. package/dist/plugin/role-agents/_shared/references/style-guide.md +40 -0
  6. package/dist/plugin/role-agents/code-review-responder/AGENT.md +1 -1
  7. package/dist/plugin/role-agents/code-review-writer/AGENT.md +1 -1
  8. package/dist/plugin/role-agents/harness-architect/AGENT.md +1 -1
  9. package/dist/plugin/role-agents/humanize-monolith/AGENT.md +20 -2
  10. package/dist/plugin/role-agents/jira-writer/AGENT.md +11 -11
  11. package/dist/plugin/role-agents/slack-messenger/AGENT.md +1 -1
  12. package/dist/plugin/skills/_shared/agent-model.md +39 -0
  13. package/dist/plugin/skills/agent/SKILL.md +2 -0
  14. package/dist/plugin/skills/brief/SKILL.md +2 -0
  15. package/dist/plugin/skills/dispatch/SKILL.md +3 -3
  16. package/dist/plugin/skills/execute/SKILL.md +1 -1
  17. package/dist/plugin/skills/jira-create/SKILL.md +6 -5
  18. package/dist/plugin/skills/pr/SKILL.md +1 -0
  19. package/dist/plugin/skills/presentation/SKILL.md +7 -6
  20. package/dist/plugin/skills/review/SKILL.md +2 -0
  21. package/dist/plugin/skills/review-reply/SKILL.md +5 -3
  22. package/dist/plugin/skills/slack-send/SKILL.md +3 -2
  23. package/dist/src/cli/commands/humanize-check.d.ts +8 -0
  24. package/dist/src/cli/commands/humanize-check.d.ts.map +1 -0
  25. package/dist/src/cli/commands/humanize-check.js +29 -0
  26. package/dist/src/cli/commands/humanize-check.js.map +1 -0
  27. package/dist/src/cli/index.d.ts.map +1 -1
  28. package/dist/src/cli/index.js +11 -0
  29. package/dist/src/cli/index.js.map +1 -1
  30. package/dist/src/code-graph/rrf.d.ts +4 -4
  31. package/dist/src/code-graph/rrf.js +4 -4
  32. package/dist/src/core/config.d.ts +23 -0
  33. package/dist/src/core/config.d.ts.map +1 -1
  34. package/dist/src/core/config.js +19 -2
  35. package/dist/src/core/config.js.map +1 -1
  36. package/dist/src/core/constants.d.ts +17 -1
  37. package/dist/src/core/constants.d.ts.map +1 -1
  38. package/dist/src/core/constants.js +17 -1
  39. package/dist/src/core/constants.js.map +1 -1
  40. package/dist/src/execute/model-hint.d.ts +0 -13
  41. package/dist/src/execute/model-hint.d.ts.map +1 -1
  42. package/dist/src/execute/model-hint.js +0 -24
  43. package/dist/src/execute/model-hint.js.map +1 -1
  44. package/dist/src/execute/parallel-groups.d.ts +1 -1
  45. package/dist/src/execute/parallel-groups.js +1 -1
  46. package/dist/src/gestalt/surface-labels.d.ts +3 -3
  47. package/dist/src/gestalt/surface-labels.js +1 -1
  48. package/dist/src/humanize/change-rate.d.ts +13 -0
  49. package/dist/src/humanize/change-rate.d.ts.map +1 -0
  50. package/dist/src/humanize/change-rate.js +86 -0
  51. package/dist/src/humanize/change-rate.js.map +1 -0
  52. package/dist/src/humanize/check.d.ts +39 -0
  53. package/dist/src/humanize/check.d.ts.map +1 -0
  54. package/dist/src/humanize/check.js +150 -0
  55. package/dist/src/humanize/check.js.map +1 -0
  56. package/dist/src/humanize/detectors.d.ts +28 -0
  57. package/dist/src/humanize/detectors.d.ts.map +1 -0
  58. package/dist/src/humanize/detectors.js +134 -0
  59. package/dist/src/humanize/detectors.js.map +1 -0
  60. package/dist/src/humanize/index.d.ts +5 -0
  61. package/dist/src/humanize/index.d.ts.map +1 -0
  62. package/dist/src/humanize/index.js +5 -0
  63. package/dist/src/humanize/index.js.map +1 -0
  64. package/dist/src/humanize/rules.d.ts +34 -0
  65. package/dist/src/humanize/rules.d.ts.map +1 -0
  66. package/dist/src/humanize/rules.js +95 -0
  67. package/dist/src/humanize/rules.js.map +1 -0
  68. package/dist/src/llm/factory.d.ts +0 -6
  69. package/dist/src/llm/factory.d.ts.map +1 -1
  70. package/dist/src/llm/factory.js +0 -29
  71. package/dist/src/llm/factory.js.map +1 -1
  72. package/dist/src/mcp/server.d.ts.map +1 -1
  73. package/dist/src/mcp/server.js +1 -1
  74. package/dist/src/mcp/server.js.map +1 -1
  75. package/dist/src/mcp/tools/agent-passthrough.d.ts +4 -1
  76. package/dist/src/mcp/tools/agent-passthrough.d.ts.map +1 -1
  77. package/dist/src/mcp/tools/agent-passthrough.js +7 -1
  78. package/dist/src/mcp/tools/agent-passthrough.js.map +1 -1
  79. package/package.json +4 -3
  80. package/plugin/.codex-plugin/plugin.json +1 -1
  81. package/plugin/role-agents/_shared/references/README.md +13 -0
  82. package/plugin/role-agents/_shared/references/ai-tell-quick-rules.md +66 -15
  83. package/plugin/role-agents/_shared/references/style-guide.md +40 -0
  84. package/plugin/role-agents/code-review-responder/AGENT.md +1 -1
  85. package/plugin/role-agents/code-review-writer/AGENT.md +1 -1
  86. package/plugin/role-agents/harness-architect/AGENT.md +1 -1
  87. package/plugin/role-agents/humanize-monolith/AGENT.md +20 -2
  88. package/plugin/role-agents/jira-writer/AGENT.md +11 -11
  89. package/plugin/role-agents/slack-messenger/AGENT.md +1 -1
  90. package/plugin/skills/_shared/agent-model.md +39 -0
  91. package/plugin/skills/agent/SKILL.md +2 -0
  92. package/plugin/skills/brief/SKILL.md +2 -0
  93. package/plugin/skills/dispatch/SKILL.md +3 -3
  94. package/plugin/skills/execute/SKILL.md +1 -1
  95. package/plugin/skills/jira-create/SKILL.md +6 -5
  96. package/plugin/skills/pr/SKILL.md +1 -0
  97. package/plugin/skills/presentation/SKILL.md +7 -6
  98. package/plugin/skills/review/SKILL.md +2 -0
  99. package/plugin/skills/review-reply/SKILL.md +5 -3
  100. package/plugin/skills/slack-send/SKILL.md +3 -2
  101. package/dist/src/agent/figural-router.d.ts +0 -48
  102. package/dist/src/agent/figural-router.d.ts.map +0 -1
  103. package/dist/src/agent/figural-router.js +0 -55
  104. package/dist/src/agent/figural-router.js.map +0 -1
@@ -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":"AAAA;;;;;;GAMG;AAEH,iDAAiD;AACjD,MAAM,YAAY,GAAG,IAAI,CAAC;AAE1B,MAAM,aAAa,GAAG,qCAAqC,CAAC;AAC5D,MAAM,MAAM,GAAG,sEAAsE,CAAC;AAOtF,SAAS,SAAS,CAAC,IAAY,EAAE,YAAqB;IACpD,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;IAC3C,IAAI,YAAY;QAAE,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjD,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AACzC,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,SAAS,CAAC,CAAoB,EAAE,CAAoB;IAC3D,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAE/C,6BAA6B;IAC7B,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,OAAO,IAAI,GAAG,CAAC,CAAC,MAAM,IAAI,IAAI,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;QAAE,IAAI,IAAI,CAAC,CAAC;IAC5E,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,OACE,IAAI,GAAG,CAAC,CAAC,MAAM,GAAG,IAAI;QACtB,IAAI,GAAG,CAAC,CAAC,MAAM,GAAG,IAAI;QACtB,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,EACjD,CAAC;QACD,IAAI,IAAI,CAAC,CAAC;IACZ,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IAC3B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IAE1D,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7B,IAAI,IAAI,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,IAAI,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;IAEjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACjC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC;QACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACjC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAE,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC,CAAC;QACtF,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC;QAClB,IAAI,GAAG,IAAI,CAAC;QACZ,IAAI,GAAG,IAAI,CAAC;QACZ,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACf,CAAC;IAED,OAAO,MAAM,GAAG,IAAI,CAAC,IAAI,GAAG,CAAC,CAAE,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CAAC,CAAoB,EAAE,CAAoB;IAC9D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,KAAK,MAAM,KAAK,IAAI,CAAC;QAAE,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAEvE,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,KAAK,IAAI,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC;YAC5B,MAAM,IAAI,CAAC,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,KAAa,EAAE,UAA6B,EAAE;IACvF,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,KAAK,CAAC;IACnD,MAAM,CAAC,GAAG,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IACpD,MAAM,CAAC,GAAG,QAAQ,CAAC,SAAS,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC;IAEnD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC/C,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAE/C,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,GAAG,YAAY,IAAI,CAAC,CAAC,MAAM,GAAG,YAAY,CAAC;IAClE,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;AAClD,CAAC"}
@@ -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"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * 룰 ID별 결정적 탐지기.
3
+ *
4
+ * 여기 있는 건 정규식만으로 오탐 없이 셀 수 있는 룰뿐이다. D-5 의인화 주어처럼
5
+ * 뜻을 봐야 판단되는 룰은 일부러 뺐다 — 검사가 오탐으로 멈추면 아무도 안 쓴다.
6
+ * 탐지기가 없는 룰은 모델이 자체검증으로 본다.
7
+ */
8
+ const SAMPLE_CAP = 3;
9
+ /** 표 안 압축과 코드는 룰 적용 대상이 아니라서 센 뒤 빼야 한다 */
10
+ function proseOnly(text) {
11
+ return text
12
+ .replace(/```[\s\S]*?```/g, '\n')
13
+ .replace(/`[^`\n]+`/g, ' ')
14
+ .split('\n')
15
+ .filter((line) => !line.trimStart().startsWith('|'))
16
+ .join('\n');
17
+ }
18
+ function matcher(ruleId, re, onProse = true) {
19
+ return {
20
+ ruleId,
21
+ run: (text) => {
22
+ const target = onProse ? proseOnly(text) : text;
23
+ return [...target.matchAll(re)].map((m) => m[0].trim());
24
+ },
25
+ };
26
+ }
27
+ /** 문장 첫머리 접속사는 문장을 갈라서 봐야 한다 */
28
+ function sentenceInitial(ruleId, words) {
29
+ const re = new RegExp(`^(?:${words.join('|')})[\\s,]`);
30
+ return {
31
+ ruleId,
32
+ run: (text) => {
33
+ const hits = [];
34
+ for (const chunk of splitSentences(proseOnly(text))) {
35
+ const stripped = chunk.replace(/^[\s>*\-#\d.)]+/, '');
36
+ const match = stripped.match(re);
37
+ if (match)
38
+ hits.push(match[0].trim());
39
+ }
40
+ return hits;
41
+ },
42
+ };
43
+ }
44
+ export function splitSentences(text) {
45
+ return text
46
+ .split(/(?<=[.!?…])\s+|\n+/)
47
+ .map((s) => s.trim())
48
+ .filter(Boolean);
49
+ }
50
+ // 한글 뒤에는 \b가 성립하지 않는다(자모가 \w가 아님). 어미 끝은 후행 부정 탐색으로 막는다.
51
+ const NOT_HANGUL = '(?![가-힣])';
52
+ const JOSA = '(?:는|도|만|요)?';
53
+ const DETECTORS = [
54
+ matcher('A-1', new RegExp(`[가-힣)\\]]\\s*에\\s*대(?:해서|하여|해|한)${JOSA}${NOT_HANGUL}`, 'g')),
55
+ matcher('A-2', new RegExp(`[가-힣)\\]]\\s*(?:를|을)?\\s*통(?:해서|하여|해)${JOSA}${NOT_HANGUL}`, 'g')),
56
+ matcher('A-3', new RegExp(`[가-힣)\\]]\\s*에\\s*있어(?:서)?${JOSA}${NOT_HANGUL}`, 'g')),
57
+ matcher('A-5', new RegExp(`(?:와|과)\\s*관련(?:하여|해서|해|된|한)${NOT_HANGUL}`, 'g')),
58
+ matcher('A-7', /가지고\s*있(?:다|습니다|는|었|지)/g),
59
+ // 되어진다는 지+ㄴ이 결합해 "진"으로 적히므로 자모 분리 형태로는 안 잡힌다
60
+ matcher('A-8', /되어\s*(?:진|지[다고며])|지게\s*(?:된|되[다었어고])|되어\s*졌/g),
61
+ matcher('A-9', new RegExp(`[가-힣)\\]]\\s*에\\s*의(?:해서|하여|해)${NOT_HANGUL}`, 'g')),
62
+ matcher('A-19', new RegExp(`[가-힣]\\s*(?:에서의|에로의|으로의|로의|에의|으로부터의)${NOT_HANGUL}`, 'g')),
63
+ matcher('C-11', /[가-힣](?:하고|하며|되고|되며|고|며|지만|면서|아서|어서),/g),
64
+ matcher('C-12', /[가-힣A-Za-z0-9]·[가-힣A-Za-z0-9]/g),
65
+ matcher('D-1', /(?:결론적으로|요약하자면|요약하면|정리하자면|정리하면|종합하면|이를\s*통해)/g),
66
+ matcher('D-2', /(?:시사하는\s*바가\s*크|주목할\s*만하)/g),
67
+ matcher('D-3', /(?:본질적으로|핵심적으로)/g),
68
+ matcher('D-4', /(?:파격적|압도적|획기적|혁신적|전례\s*없|폭발적)/g),
69
+ matcher('D-6', /(?:할\s*때다|할\s*때입니다|할\s*시점|지금이야말로|할\s*순간)/g),
70
+ matcher('F-7', /(?:증류|배선|결정화|평탄화|오케스트레이션|파이프라인화)/g),
71
+ matcher('G-2', /(?:로\s*보인다|인\s*듯하다|로\s*판단된다|라고\s*여겨진다|로\s*여겨진다)/g),
72
+ matcher('I-1', /(?:인\s*것이다|한\s*것이다|는\s*것이다|일\s*것이다)/g),
73
+ matcher('I-3', /(?:다는\s*뜻이다|다는\s*의미다|다는\s*것이다)/g),
74
+ matcher('I-5', new RegExp(`(?:해당|이번|그)\\s*건${NOT_HANGUL}|[가-힣]\\s건(?:은|이|을|에|도)${NOT_HANGUL}`, 'g')),
75
+ sentenceInitial('H-1', ['또한', '따라서', '즉', '나아가', '아울러', '게다가', '더욱이']),
76
+ sentenceInitial('H-3', ['이는', '이\\s*점에서', '이\\s*관점에서', '이\\s*말은']),
77
+ ];
78
+ export const DETECTABLE_RULE_IDS = DETECTORS.map((d) => d.ruleId);
79
+ export function detect(text, ruleIds) {
80
+ const wanted = ruleIds ? new Set(ruleIds) : null;
81
+ const results = [];
82
+ for (const detector of DETECTORS) {
83
+ if (wanted && !wanted.has(detector.ruleId))
84
+ continue;
85
+ const hits = detector.run(text);
86
+ if (hits.length === 0)
87
+ continue;
88
+ results.push({
89
+ ruleId: detector.ruleId,
90
+ count: hits.length,
91
+ samples: [...new Set(hits)].slice(0, SAMPLE_CAP),
92
+ });
93
+ }
94
+ return results;
95
+ }
96
+ export function countByRule(text, ruleIds) {
97
+ return new Map(detect(text, ruleIds).map((d) => [d.ruleId, d.count]));
98
+ }
99
+ // --- 보존해야 하는 토큰 ---------------------------------------------------
100
+ const PROTECTED_PATTERNS = [
101
+ /```[\s\S]*?```/g,
102
+ /`[^`\n]+`/g,
103
+ /https?:\/\/[^\s)\]]+/g,
104
+ /"[^"\n]{2,}"|“[^”\n]{2,}”/g,
105
+ /\d[\d,]*(?:\.\d+)?%?/g,
106
+ /\b[A-Z][A-Za-z0-9]*(?:[A-Z][A-Za-z0-9]*)+\b/g,
107
+ /\b[A-Z]{2,}\b/g,
108
+ ];
109
+ /** 원문에서 한 글자도 바뀌면 안 되는 토큰을 뽑는다 */
110
+ export function protectedTokens(text) {
111
+ const tokens = new Set();
112
+ for (const re of PROTECTED_PATTERNS) {
113
+ for (const match of text.matchAll(re)) {
114
+ const token = match[0].trim();
115
+ if (token.length >= 2)
116
+ tokens.add(token);
117
+ }
118
+ }
119
+ return [...tokens];
120
+ }
121
+ export function missingProtectedTokens(before, after) {
122
+ return protectedTokens(before).filter((token) => !after.includes(token));
123
+ }
124
+ export function structureStats(text) {
125
+ const lines = text.split('\n');
126
+ return {
127
+ sentences: splitSentences(proseOnly(text)).length,
128
+ headings: lines.filter((line) => /^#{1,6}\s/.test(line.trim())).length,
129
+ bullets: lines.filter((line) => /^[-*+]\s|^\d+\.\s/.test(line.trim())).length,
130
+ codeFences: (text.match(/```/g) ?? []).length,
131
+ links: (text.match(/\[[^\]]+\]\([^)]+\)/g) ?? []).length,
132
+ };
133
+ }
134
+ //# sourceMappingURL=detectors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detectors.js","sourceRoot":"","sources":["../../../src/humanize/detectors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { parseRuleBook, s1Ids, citedRuleIds, expandIdRanges, QUICK_RULES_PATH, type Register, type Rule, type RuleBook, type Severity, } from './rules.js';
2
+ export { detect, countByRule, protectedTokens, missingProtectedTokens, structureStats, splitSentences, DETECTABLE_RULE_IDS, type Detection, type StructureStats, } from './detectors.js';
3
+ export { changeRate, type ChangeRateOptions } from './change-rate.js';
4
+ export { runCheck, formatReport, EXIT_CODE, THRESHOLD, type CheckReport, type AxisResult, type Verdict, } from './check.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/humanize/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,KAAK,EACL,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,KAAK,QAAQ,EACb,KAAK,IAAI,EACT,KAAK,QAAQ,EACb,KAAK,QAAQ,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,MAAM,EACN,WAAW,EACX,eAAe,EACf,sBAAsB,EACtB,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,KAAK,SAAS,EACd,KAAK,cAAc,GACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,SAAS,EACT,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,OAAO,GACb,MAAM,YAAY,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { parseRuleBook, s1Ids, citedRuleIds, expandIdRanges, QUICK_RULES_PATH, } from './rules.js';
2
+ export { detect, countByRule, protectedTokens, missingProtectedTokens, structureStats, splitSentences, DETECTABLE_RULE_IDS, } from './detectors.js';
3
+ export { changeRate } from './change-rate.js';
4
+ export { runCheck, formatReport, EXIT_CODE, THRESHOLD, } from './check.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/humanize/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,KAAK,EACL,YAAY,EACZ,cAAc,EACd,gBAAgB,GAKjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,MAAM,EACN,WAAW,EACX,eAAe,EACf,sBAAsB,EACtB,cAAc,EACd,cAAc,EACd,mBAAmB,GAGpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAA0B,MAAM,kBAAkB,CAAC;AACtE,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,SAAS,GAIV,MAAM,YAAY,CAAC"}
@@ -0,0 +1,34 @@
1
+ export type Severity = 'S1' | 'S2' | 'S3';
2
+ /** 산문(칼럼·리포트·문서) 기준과 대화·리뷰 코멘트 기준을 나눠 본다 */
3
+ export type Register = 'doc' | 'chat';
4
+ export interface Rule {
5
+ id: string;
6
+ category: string;
7
+ categoryTitle: string;
8
+ pattern: string;
9
+ /** 문서 기준 심각도 */
10
+ severity: Severity;
11
+ /** 대화·리뷰에서 격상되는 룰은 여기가 S1이 된다 */
12
+ chatSeverity: Severity;
13
+ prescription: string;
14
+ }
15
+ export interface RuleBook {
16
+ path: string;
17
+ rules: Map<string, Rule>;
18
+ /** 자체검증 5번이 열거한 잔존 금지 S1 목록 */
19
+ selfCheckS1: string[];
20
+ /** 자체검증 5번의 대화·리뷰 추가분 */
21
+ selfCheckChatS1: string[];
22
+ }
23
+ export declare const QUICK_RULES_PATH: string;
24
+ /**
25
+ * "D-1~D-7" 같은 범위 표기를 개별 ID로 편다.
26
+ * 룰북이 사람 읽기 좋게 범위로 적어둔 자리를 코드가 그대로 이해하게 만든다.
27
+ */
28
+ export declare function expandIdRanges(text: string): string[];
29
+ /** 마크다운 본문에서 인용된 모든 룰 ID를 뽑는다 (범위 표기 포함) */
30
+ export declare function citedRuleIds(markdown: string): string[];
31
+ export declare function parseRuleBook(path?: string): RuleBook;
32
+ /** 해당 말투 기준으로 S1인 룰 ID */
33
+ export declare function s1Ids(book: RuleBook, register: Register): string[];
34
+ //# sourceMappingURL=rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/humanize/rules.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE1C,4CAA4C;AAC5C,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAEtC,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB;IAChB,QAAQ,EAAE,QAAQ,CAAC;IACnB,iCAAiC;IACjC,YAAY,EAAE,QAAQ,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACzB,+BAA+B;IAC/B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,yBAAyB;IACzB,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAID,eAAO,MAAM,gBAAgB,QAG5B,CAAC;AAeF;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAmBrD;AAED,4CAA4C;AAC5C,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAEvD;AAED,wBAAgB,aAAa,CAAC,IAAI,GAAE,MAAyB,GAAG,QAAQ,CA6CvE;AAED,0BAA0B;AAC1B,wBAAgB,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,EAAE,CAKlE"}