@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.
- package/CLAUDE.md +8 -5
- package/dist/package.json +4 -3
- package/dist/plugin/role-agents/_shared/references/README.md +13 -0
- package/dist/plugin/role-agents/_shared/references/ai-tell-quick-rules.md +66 -15
- package/dist/plugin/role-agents/_shared/references/style-guide.md +40 -0
- package/dist/plugin/role-agents/code-review-responder/AGENT.md +1 -1
- package/dist/plugin/role-agents/code-review-writer/AGENT.md +1 -1
- package/dist/plugin/role-agents/harness-architect/AGENT.md +1 -1
- package/dist/plugin/role-agents/humanize-monolith/AGENT.md +20 -2
- package/dist/plugin/role-agents/jira-writer/AGENT.md +11 -11
- package/dist/plugin/role-agents/slack-messenger/AGENT.md +1 -1
- package/dist/plugin/skills/_shared/agent-model.md +39 -0
- package/dist/plugin/skills/agent/SKILL.md +2 -0
- package/dist/plugin/skills/brief/SKILL.md +2 -0
- package/dist/plugin/skills/dispatch/SKILL.md +3 -3
- package/dist/plugin/skills/execute/SKILL.md +1 -1
- package/dist/plugin/skills/jira-create/SKILL.md +6 -5
- package/dist/plugin/skills/pr/SKILL.md +1 -0
- package/dist/plugin/skills/presentation/SKILL.md +7 -6
- package/dist/plugin/skills/review/SKILL.md +2 -0
- package/dist/plugin/skills/review-reply/SKILL.md +5 -3
- package/dist/plugin/skills/slack-send/SKILL.md +3 -2
- package/dist/src/cli/commands/humanize-check.d.ts +8 -0
- package/dist/src/cli/commands/humanize-check.d.ts.map +1 -0
- package/dist/src/cli/commands/humanize-check.js +29 -0
- package/dist/src/cli/commands/humanize-check.js.map +1 -0
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +11 -0
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/code-graph/rrf.d.ts +4 -4
- package/dist/src/code-graph/rrf.js +4 -4
- package/dist/src/core/config.d.ts +23 -0
- package/dist/src/core/config.d.ts.map +1 -1
- package/dist/src/core/config.js +19 -2
- package/dist/src/core/config.js.map +1 -1
- package/dist/src/core/constants.d.ts +17 -1
- package/dist/src/core/constants.d.ts.map +1 -1
- package/dist/src/core/constants.js +17 -1
- package/dist/src/core/constants.js.map +1 -1
- package/dist/src/execute/model-hint.d.ts +0 -13
- package/dist/src/execute/model-hint.d.ts.map +1 -1
- package/dist/src/execute/model-hint.js +0 -24
- package/dist/src/execute/model-hint.js.map +1 -1
- package/dist/src/execute/parallel-groups.d.ts +1 -1
- package/dist/src/execute/parallel-groups.js +1 -1
- package/dist/src/gestalt/surface-labels.d.ts +3 -3
- package/dist/src/gestalt/surface-labels.js +1 -1
- package/dist/src/humanize/change-rate.d.ts +13 -0
- package/dist/src/humanize/change-rate.d.ts.map +1 -0
- package/dist/src/humanize/change-rate.js +86 -0
- package/dist/src/humanize/change-rate.js.map +1 -0
- package/dist/src/humanize/check.d.ts +39 -0
- package/dist/src/humanize/check.d.ts.map +1 -0
- package/dist/src/humanize/check.js +150 -0
- package/dist/src/humanize/check.js.map +1 -0
- package/dist/src/humanize/detectors.d.ts +28 -0
- package/dist/src/humanize/detectors.d.ts.map +1 -0
- package/dist/src/humanize/detectors.js +134 -0
- package/dist/src/humanize/detectors.js.map +1 -0
- package/dist/src/humanize/index.d.ts +5 -0
- package/dist/src/humanize/index.d.ts.map +1 -0
- package/dist/src/humanize/index.js +5 -0
- package/dist/src/humanize/index.js.map +1 -0
- package/dist/src/humanize/rules.d.ts +34 -0
- package/dist/src/humanize/rules.d.ts.map +1 -0
- package/dist/src/humanize/rules.js +95 -0
- package/dist/src/humanize/rules.js.map +1 -0
- package/dist/src/llm/factory.d.ts +0 -6
- package/dist/src/llm/factory.d.ts.map +1 -1
- package/dist/src/llm/factory.js +0 -29
- package/dist/src/llm/factory.js.map +1 -1
- package/dist/src/mcp/server.d.ts.map +1 -1
- package/dist/src/mcp/server.js +1 -1
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/mcp/tools/agent-passthrough.d.ts +4 -1
- package/dist/src/mcp/tools/agent-passthrough.d.ts.map +1 -1
- package/dist/src/mcp/tools/agent-passthrough.js +7 -1
- package/dist/src/mcp/tools/agent-passthrough.js.map +1 -1
- package/package.json +4 -3
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/role-agents/_shared/references/README.md +13 -0
- package/plugin/role-agents/_shared/references/ai-tell-quick-rules.md +66 -15
- package/plugin/role-agents/_shared/references/style-guide.md +40 -0
- package/plugin/role-agents/code-review-responder/AGENT.md +1 -1
- package/plugin/role-agents/code-review-writer/AGENT.md +1 -1
- package/plugin/role-agents/harness-architect/AGENT.md +1 -1
- package/plugin/role-agents/humanize-monolith/AGENT.md +20 -2
- package/plugin/role-agents/jira-writer/AGENT.md +11 -11
- package/plugin/role-agents/slack-messenger/AGENT.md +1 -1
- package/plugin/skills/_shared/agent-model.md +39 -0
- package/plugin/skills/agent/SKILL.md +2 -0
- package/plugin/skills/brief/SKILL.md +2 -0
- package/plugin/skills/dispatch/SKILL.md +3 -3
- package/plugin/skills/execute/SKILL.md +1 -1
- package/plugin/skills/jira-create/SKILL.md +6 -5
- package/plugin/skills/pr/SKILL.md +1 -0
- package/plugin/skills/presentation/SKILL.md +7 -6
- package/plugin/skills/review/SKILL.md +2 -0
- package/plugin/skills/review-reply/SKILL.md +5 -3
- package/plugin/skills/slack-send/SKILL.md +3 -2
- package/dist/src/agent/figural-router.d.ts +0 -48
- package/dist/src/agent/figural-router.d.ts.map +0 -1
- package/dist/src/agent/figural-router.js +0 -55
- package/dist/src/agent/figural-router.js.map +0 -1
|
@@ -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"}
|