patina-cli 3.11.0 โ 4.0.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/.patina.default.yaml +29 -29
- package/CHANGELOG.md +53 -0
- package/NOTICE +21 -0
- package/README.md +117 -224
- package/README_JA.md +134 -77
- package/README_KR.md +132 -74
- package/README_ZH.md +137 -80
- package/SKILL.md +11 -20
- package/artifacts/rebaseline-2025/README.md +147 -0
- package/artifacts/rebaseline-2025/human-controls.public.jsonl +250 -0
- package/artifacts/rebaseline-2025/intake.example.jsonl +2 -0
- package/artifacts/rebaseline-2025/intake.local.example.jsonl +25 -0
- package/artifacts/rebaseline-2025/prompts.template.jsonl +7 -0
- package/artifacts/rebaseline-2025/sources.ko-public.jsonl +39 -0
- package/assets/brand/patina-badge.svg +18 -0
- package/assets/brand/patina-mark.svg +8 -0
- package/assets/demo/README.md +79 -0
- package/core/scoring.md +12 -12
- package/core/standalone-prompt.md +3 -1
- package/core/stylometry.md +93 -22
- package/docs/API.md +1554 -0
- package/docs/AUTHENTICATION.md +50 -26
- package/docs/AUTHENTICATION_KR.md +54 -29
- package/docs/BRANDING.md +9 -8
- package/docs/CLI.md +55 -14
- package/docs/COOKBOOK.md +8 -21
- package/docs/DEMO.md +32 -5
- package/docs/EXIT-CODES.md +2 -3
- package/docs/FALSE-POSITIVES.md +63 -0
- package/docs/FAQ.md +9 -1
- package/docs/FAQ_KR.md +3 -1
- package/docs/FLAG-PARITY.md +33 -47
- package/docs/ISSUE-WAVES.md +57 -0
- package/docs/PATTERNS-EN.md +67 -3
- package/docs/PATTERNS-JA.md +68 -2
- package/docs/PATTERNS-KO.md +70 -7
- package/docs/PATTERNS-ZH.md +67 -3
- package/docs/PATTERNS.md +5 -5
- package/docs/RESEARCH-DOCS-PLATFORM.md +54 -0
- package/docs/ROADMAP.md +46 -66
- package/docs/TRANSLATIONESE-KO.md +51 -0
- package/docs/audits/2026-05-deep-research.md +3 -1
- package/docs/benchmarks/README.md +51 -0
- package/docs/benchmarks/detector-comparison.json +69 -9
- package/docs/benchmarks/detector-comparison.md +10 -5
- package/docs/benchmarks/katfish-ko-latest.json +657 -0
- package/docs/benchmarks/katfish-ko-latest.md +77 -0
- package/docs/benchmarks/latest.json +1183 -108
- package/docs/benchmarks/latest.md +84 -60
- package/docs/benchmarks/lexicon-freshness-en-2026-05-22.json +1121 -0
- package/docs/benchmarks/lexicon-freshness-en-2026-05-22.md +136 -0
- package/docs/benchmarks/rebaseline-latest.json +381 -0
- package/docs/benchmarks/rebaseline-latest.md +121 -0
- package/docs/benchmarks/register-stratified-latest.json +164 -0
- package/docs/benchmarks/register-stratified-latest.md +99 -0
- package/docs/benchmarks/register-stratified.md +43 -0
- package/docs/integrations/github-action.md +44 -11
- package/docs/integrations/playground.md +58 -0
- package/docs/integrations/pre-commit.md +5 -5
- package/docs/integrations/release.md +5 -3
- package/docs/integrations/static-sites.md +83 -0
- package/docs/research/2025-rebaseline-plan.md +71 -2
- package/docs/research/2026-rebaseline.md +102 -0
- package/docs/research/adversarial-mps.md +41 -0
- package/docs/research/ai-human-metrics.md +35 -23
- package/docs/research/human-eval-panel.md +42 -0
- package/docs/research/judge-agreement.md +24 -0
- package/docs/research/ko-2025-corpus-sources.md +135 -0
- package/docs/research/lexicon-freshness-audit.md +64 -0
- package/docs/research/zh-ja-lexicon-calibration.md +60 -0
- package/docs/social/patina-launch-copy.md +173 -100
- package/docs/social/patina-launch-execution.md +94 -0
- package/docs/social/patina-launch-korean-first.md +83 -0
- package/docs/social/signs-of-ai-writing.md +26 -0
- package/docs/social/signs-of-ai-writing_KR.md +26 -0
- package/lexicon/ai-en.md +21 -24
- package/lexicon/ai-ja.md +158 -0
- package/lexicon/ai-ko.md +9 -9
- package/lexicon/ai-zh.md +158 -0
- package/lexicon/provenance/ai-en.json +970 -0
- package/lexicon/provenance/ai-ja.json +542 -0
- package/lexicon/provenance/ai-ko.json +866 -0
- package/lexicon/provenance/ai-zh.json +542 -0
- package/package.json +49 -8
- package/patterns/en-communication.md +5 -0
- package/patterns/en-content.md +5 -0
- package/patterns/en-filler.md +5 -0
- package/patterns/en-language.md +29 -1
- package/patterns/en-structure.md +5 -0
- package/patterns/en-style.md +5 -0
- package/patterns/en-viral-hook.md +42 -2
- package/patterns/ja-communication.md +5 -0
- package/patterns/ja-content.md +5 -0
- package/patterns/ja-filler.md +5 -0
- package/patterns/ja-language.md +33 -1
- package/patterns/ja-structure.md +12 -0
- package/patterns/ja-style.md +5 -0
- package/patterns/ja-viral-hook.md +41 -2
- package/patterns/ko-communication.md +5 -0
- package/patterns/ko-content.md +5 -0
- package/patterns/ko-filler.md +5 -0
- package/patterns/ko-language.md +33 -1
- package/patterns/ko-structure.md +25 -6
- package/patterns/ko-style.md +5 -0
- package/patterns/ko-viral-hook.md +38 -2
- package/patterns/zh-communication.md +5 -0
- package/patterns/zh-content.md +5 -0
- package/patterns/zh-filler.md +5 -0
- package/patterns/zh-language.md +37 -1
- package/patterns/zh-structure.md +12 -0
- package/patterns/zh-style.md +5 -0
- package/patterns/zh-viral-hook.md +38 -2
- package/playground/README.md +55 -0
- package/playground/analytics.js +4 -0
- package/playground/analyzer.js +883 -0
- package/playground/app.js +157 -0
- package/playground/data/lexicons.js +343 -0
- package/playground/index.html +138 -0
- package/playground/styles.css +267 -0
- package/profiles/namuwiki.md +111 -0
- package/scripts/adversarial-mps-report.mjs +201 -0
- package/scripts/badge-json.mjs +79 -0
- package/scripts/benchmark-report.mjs +56 -9
- package/scripts/check-release-metadata.mjs +0 -2
- package/scripts/detector-comparison.mjs +7 -7
- package/scripts/generate-playground-data.mjs +77 -0
- package/scripts/katfish-calibration.mjs +464 -0
- package/scripts/lexicon-freshness.mjs +485 -0
- package/scripts/lint.mjs +1 -1
- package/scripts/precommit-score.mjs +4 -3
- package/scripts/prose-score.mjs +81 -5
- package/scripts/rebaseline-intake.mjs +242 -0
- package/scripts/rebaseline-score.mjs +268 -0
- package/scripts/rebaseline-summary.mjs +773 -0
- package/scripts/rebaseline-web-collect.mjs +410 -0
- package/scripts/update-benchmark-ranges.mjs +1 -0
- package/src/api.js +69 -105
- package/src/auth.js +50 -2
- package/src/backends/claude-cli.js +19 -4
- package/src/backends/codex-cli.js +19 -3
- package/src/backends/contract.js +230 -1
- package/src/backends/gemini-cli.js +18 -5
- package/src/backends/index.js +87 -12
- package/src/backends/kimi-cli.js +161 -0
- package/src/cli.js +577 -567
- package/src/commands/doctor.js +2 -2
- package/src/config.js +29 -0
- package/src/errors.js +53 -1
- package/src/features/discourse-tells.js +68 -0
- package/src/features/index.js +82 -8
- package/src/features/lexicon.js +40 -6
- package/src/features/markup-leakage.js +69 -0
- package/src/features/segment.js +41 -0
- package/src/features/signal-strength.js +81 -0
- package/src/features/stylometry.js +231 -1
- package/src/features/translationese.js +127 -0
- package/src/loader.js +76 -0
- package/src/logger.js +22 -23
- package/src/model-defaults.js +55 -0
- package/src/ouroboros.js +31 -0
- package/src/output.js +102 -90
- package/src/prompt-builder.js +103 -68
- package/src/providers.js +51 -4
- package/src/scoring.js +210 -2
- package/src/security.js +75 -0
- package/tests/fixtures/live-quality/en/public-docs-01.md +26 -0
- package/tests/fixtures/live-quality/ko/public-docs-01.md +26 -0
- package/tests/fixtures/suspect-zones/expected-ranges.json +207 -16
- package/tests/fixtures/suspect-zones/ja/ai/ja-ai-04-lexicon.md +11 -0
- package/tests/fixtures/suspect-zones/ja/natural/ja-nat-04-lexicon-cold.md +11 -0
- package/tests/fixtures/suspect-zones/ko/ai/ko-ai-02.md +4 -5
- package/tests/fixtures/suspect-zones/ko/ai/ko-ai-07-ko-diagnostic.md +11 -0
- package/tests/fixtures/suspect-zones/zh/ai/zh-ai-04-lexicon.md +11 -0
- package/tests/fixtures/suspect-zones/zh/natural/zh-nat-04-lexicon-cold.md +11 -0
- package/tests/quality/README.md +188 -11
- package/tests/quality/adversarial-mps/fixtures.jsonl +10 -0
- package/tests/quality/benchmark.mjs +39 -1
- package/tests/quality/dogfood.mjs +5 -3
- package/tests/quality/live-fixtures.jsonl +2 -0
- package/tests/quality/live-quality.mjs +596 -0
- package/tests/quality/ranking-metrics.mjs +136 -0
- package/tests/quality/rebaseline-manifest.example.jsonl +5 -0
- package/vercel.json +53 -0
- package/SKILL-MAX.md +0 -455
- package/docs/internal/HARNESS.md +0 -14
- package/docs/internal/README.md +0 -14
- package/docs/internal/WARP.md +0 -23
- package/patina-max/SKILL.md +0 -523
- package/patina-max/composite.py +0 -457
- package/src/cache.js +0 -106
- package/src/commands/init.js +0 -208
- package/src/manifest.js +0 -162
- package/src/max-mode.js +0 -207
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
export function summarizeRanking(records = []) {
|
|
2
|
+
const normalized = records
|
|
3
|
+
.map((record) => ({
|
|
4
|
+
score: Number(record.score),
|
|
5
|
+
expected: Boolean(record.expected),
|
|
6
|
+
}))
|
|
7
|
+
.filter((record) => Number.isFinite(record.score));
|
|
8
|
+
|
|
9
|
+
const positives = normalized.filter((record) => record.expected).length;
|
|
10
|
+
const negatives = normalized.length - positives;
|
|
11
|
+
const sweep = thresholdSweep(normalized);
|
|
12
|
+
const best = bestF1Threshold(sweep);
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
n: normalized.length,
|
|
16
|
+
positives,
|
|
17
|
+
negatives,
|
|
18
|
+
scoreRange: scoreRange(normalized),
|
|
19
|
+
roc_auc: round(rocAuc(normalized)),
|
|
20
|
+
pr_auc: round(averagePrecision(normalized)),
|
|
21
|
+
bestF1: best,
|
|
22
|
+
sweep,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function thresholdSweep(records = []) {
|
|
27
|
+
const thresholds = thresholdCandidates(records);
|
|
28
|
+
return thresholds.map((threshold) => {
|
|
29
|
+
const metrics = emptyMetrics();
|
|
30
|
+
for (const record of records) {
|
|
31
|
+
updateMetrics(metrics, record.score >= threshold, record.expected);
|
|
32
|
+
}
|
|
33
|
+
return { threshold, ...summarize(metrics) };
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function bestF1Threshold(rows = []) {
|
|
38
|
+
if (!rows.length) return null;
|
|
39
|
+
return [...rows].sort((a, b) =>
|
|
40
|
+
b.f1 - a.f1 ||
|
|
41
|
+
b.recall - a.recall ||
|
|
42
|
+
b.precision - a.precision ||
|
|
43
|
+
b.accuracy - a.accuracy ||
|
|
44
|
+
a.threshold - b.threshold
|
|
45
|
+
)[0];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function rocAuc(records = []) {
|
|
49
|
+
const positives = records.filter((record) => record.expected);
|
|
50
|
+
const negatives = records.filter((record) => !record.expected);
|
|
51
|
+
if (!positives.length || !negatives.length) return null;
|
|
52
|
+
|
|
53
|
+
let wins = 0;
|
|
54
|
+
for (const positive of positives) {
|
|
55
|
+
for (const negative of negatives) {
|
|
56
|
+
if (positive.score > negative.score) wins += 1;
|
|
57
|
+
else if (positive.score === negative.score) wins += 0.5;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return wins / (positives.length * negatives.length);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function averagePrecision(records = []) {
|
|
64
|
+
const positives = records.filter((record) => record.expected).length;
|
|
65
|
+
if (!positives) return null;
|
|
66
|
+
|
|
67
|
+
const groups = scoreGroups(records);
|
|
68
|
+
let seen = 0;
|
|
69
|
+
let truePositives = 0;
|
|
70
|
+
let area = 0;
|
|
71
|
+
|
|
72
|
+
for (const group of groups) {
|
|
73
|
+
seen += group.total;
|
|
74
|
+
truePositives += group.positives;
|
|
75
|
+
if (group.positives) area += group.positives * (truePositives / seen);
|
|
76
|
+
}
|
|
77
|
+
return area / positives;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function thresholdCandidates(records) {
|
|
81
|
+
const uniqueScores = [...new Set(records.map((record) => record.score))]
|
|
82
|
+
.filter((score) => Number.isFinite(score))
|
|
83
|
+
.sort((a, b) => a - b);
|
|
84
|
+
return [...new Set([0, ...uniqueScores, 101])].sort((a, b) => a - b);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function scoreGroups(records) {
|
|
88
|
+
const map = new Map();
|
|
89
|
+
for (const record of records) {
|
|
90
|
+
const group = map.get(record.score) || { score: record.score, total: 0, positives: 0 };
|
|
91
|
+
group.total += 1;
|
|
92
|
+
if (record.expected) group.positives += 1;
|
|
93
|
+
map.set(record.score, group);
|
|
94
|
+
}
|
|
95
|
+
return [...map.values()].sort((a, b) => b.score - a.score);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function scoreRange(records) {
|
|
99
|
+
if (!records.length) return { min: 0, max: 0 };
|
|
100
|
+
const scores = records.map((record) => record.score);
|
|
101
|
+
return {
|
|
102
|
+
min: round(Math.min(...scores)),
|
|
103
|
+
max: round(Math.max(...scores)),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function emptyMetrics() {
|
|
108
|
+
return { tp: 0, fp: 0, fn: 0, tn: 0, total: 0 };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function updateMetrics(metrics, predicted, expected) {
|
|
112
|
+
metrics.total += 1;
|
|
113
|
+
if (predicted && expected) metrics.tp += 1;
|
|
114
|
+
else if (predicted && !expected) metrics.fp += 1;
|
|
115
|
+
else if (!predicted && expected) metrics.fn += 1;
|
|
116
|
+
else metrics.tn += 1;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function summarize(metrics) {
|
|
120
|
+
const accuracy = metrics.total ? (metrics.tp + metrics.tn) / metrics.total : 0;
|
|
121
|
+
const precision = metrics.tp + metrics.fp ? metrics.tp / (metrics.tp + metrics.fp) : 0;
|
|
122
|
+
const recall = metrics.tp + metrics.fn ? metrics.tp / (metrics.tp + metrics.fn) : 0;
|
|
123
|
+
const f1 = precision + recall ? (2 * precision * recall) / (precision + recall) : 0;
|
|
124
|
+
return {
|
|
125
|
+
...metrics,
|
|
126
|
+
accuracy: round(accuracy),
|
|
127
|
+
precision: round(precision),
|
|
128
|
+
recall: round(recall),
|
|
129
|
+
f1: round(f1),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function round(value, digits = 3) {
|
|
134
|
+
if (value === null || value === undefined) return null;
|
|
135
|
+
return Math.round(value * 10 ** digits) / 10 ** digits;
|
|
136
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{"sample_id":"en-gpt-blog-ai-001","language":"en","class":"ai-like","register":"blog","model_family":"gpt-family","provider":"fixture","model":"fixture-gpt-family-2026-05","generated_at":"2026-05-21","prompt_id":"rb25-blog-launch-001","decoding":{"temperature":0.7,"top_p":0.9},"postprocess":{"editing_pass":"none"},"redistribution":"repo-ok","text":"This launch guide provides a seamless framework for teams that want to unlock clearer messaging across every touchpoint.","text_hash":"sha256:702cc81afca0e662268a2f4802622a707a2f1fddb10c5d61ef6af8159b0b26b3"}
|
|
2
|
+
{"sample_id":"ko-human-productdoc-001","language":"ko","class":"natural-human","register":"product-doc","model_family":"human-reference","provider":"fixture","model":"maintainer-written-reference","generated_at":"2026-05-21","prompt_id":"rb25-product-doc-001","decoding":"not-applicable","postprocess":{"editing_pass":"maintainer copyedit"},"redistribution":"repo-ok","text":"์ค์ ํ์ผ์ ๋จผ์ ์ฝ๊ณ , ๊ฐ์ด ์์ ๋๋ง ๊ธฐ๋ณธ๊ฐ์ ์ฌ์ฉํ๋ค. ๊ทธ๋์ ํ๋ณ ์์ธ๋ฅผ ๋ฌธ์์ ๋จ๊ธฐ๊ธฐ ์ฝ๋ค.","text_hash":"sha256:7e7edd6e2cfab5a33c0f278ac24f121174d93a92211d150f659429bcba795ddf"}
|
|
3
|
+
{"sample_id":"ja-gemini-technical-lightedit-001","language":"ja","class":"lightly-edited-ai","register":"technical-how-to","model_family":"gemini-family","provider":"manual-vendor-copy","model":"gemini-family-redacted","generated_at":"2026-05-21","prompt_id":"rb25-howto-cache-001","decoding":{"temperature":0.4},"postprocess":{"editing_pass":"light grammar pass"},"redistribution":"metadata-only","text_hash":"sha256:e6ac1a38435c63987b4ad2e15b6acd1e05c09408cb1ae4ec73d0a9bca2d02c6d"}
|
|
4
|
+
{"sample_id":"zh-openweight-academic-heavyedit-001","language":"zh","class":"heavily-edited-ai","register":"academic-summary","model_family":"open-weight","provider":"local-fixture","model":"open-weight-redacted","generated_at":"2026-05-21","prompt_id":"rb25-academic-energy-001","decoding":{"temperature":0.2,"top_p":0.8},"postprocess":{"editing_pass":"heavy human edit"},"redistribution":"no-redistribution","text_hash":"sha256:22b2556861f48baf29f880ac04aedf885b862b5460ce4b24985413f7e94e94ed"}
|
|
5
|
+
{"sample_id":"en-claude-chat-ai-001","language":"en","class":"ai-like","register":"chat-update","model_family":"claude-family","provider":"fixture","model":"fixture-claude-family-2026-05","generated_at":"2026-05-21","prompt_id":"rb25-chat-update-001","decoding":{"temperature":0.5},"postprocess":{"editing_pass":"none"},"redistribution":"repo-ok","text":"Here is a concise update on the initiative: the team aligned on priorities, improved execution, and created a scalable path forward.","text_hash":"sha256:df2076d0f8d458da8bc132ae1d9c86ddae9e92e2f3832a06d405d8dd0d219a4d"}
|
package/vercel.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cleanUrls": true,
|
|
3
|
+
"trailingSlash": false,
|
|
4
|
+
"rewrites": [
|
|
5
|
+
{
|
|
6
|
+
"source": "/",
|
|
7
|
+
"destination": "/playground"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"source": "/app.js",
|
|
11
|
+
"destination": "/playground/app.js"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"source": "/analytics.js",
|
|
15
|
+
"destination": "/playground/analytics.js"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"source": "/analyzer.js",
|
|
19
|
+
"destination": "/playground/analyzer.js"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"source": "/styles.css",
|
|
23
|
+
"destination": "/playground/styles.css"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"source": "/data/:path*",
|
|
27
|
+
"destination": "/playground/data/:path*"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"headers": [
|
|
31
|
+
{
|
|
32
|
+
"source": "/(.*)",
|
|
33
|
+
"headers": [
|
|
34
|
+
{
|
|
35
|
+
"key": "X-Content-Type-Options",
|
|
36
|
+
"value": "nosniff"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"key": "Referrer-Policy",
|
|
40
|
+
"value": "strict-origin-when-cross-origin"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"key": "Permissions-Policy",
|
|
44
|
+
"value": "clipboard-write=(self), camera=(), microphone=(), geolocation=()"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"key": "Content-Security-Policy",
|
|
48
|
+
"value": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; base-uri 'self'; form-action 'none'; frame-ancestors 'none'"
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
package/SKILL-MAX.md
DELETED
|
@@ -1,455 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: patina-max
|
|
3
|
-
version: 3.11.0
|
|
4
|
-
description: |
|
|
5
|
-
Multi-model humanization. Runs the same humanization task on multiple
|
|
6
|
-
local model CLIs, scores each result, and selects the best
|
|
7
|
-
output by lowest AI score among candidates that pass the MPS
|
|
8
|
-
meaning-preservation floor. Uses `claude -p` / `gemini -p` for
|
|
9
|
-
Claude/Gemini and `codex exec` for Codex.
|
|
10
|
-
allowed-tools:
|
|
11
|
-
- Read
|
|
12
|
-
- Write
|
|
13
|
-
- Edit
|
|
14
|
-
- Grep
|
|
15
|
-
- Glob
|
|
16
|
-
- Bash
|
|
17
|
-
- AskUserQuestion
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
# patina MAX: ๋ฉํฐ๋ชจ๋ธ Best-of-N Rewriter
|
|
21
|
-
|
|
22
|
-
๋น์ ์ ์ฌ๋ฌ AI ๋ชจ๋ธ์ ๋์์ ์ฌ์ฉํ์ฌ ํ
์คํธ๋ฅผ humanizeํ๊ณ , ๊ฐ์ฅ ์์ฐ์ค๋ฌ์ด ๊ฒฐ๊ณผ๋ฅผ ์๋ ์ ํํ๋ ์ค์ผ์คํธ๋ ์ดํฐ์
๋๋ค. ๊ฐ ๋ชจ๋ธ์ด ๊ฐ์ ํ
์คํธ๋ฅผ humanizeํ ๋ค, ์๋ฏธ ๋ณด์กด ๊ธฐ์ค(MPS โฅ 70)์ ํต๊ณผํ ๊ฒฐ๊ณผ ์ค AI ์ ์ฌ๋ ์ ์๊ฐ ๊ฐ์ฅ ๋ฎ์ ๊ฒ์ ์ต์ข
๋ณธ์ผ๋ก ์ ํํฉ๋๋ค.
|
|
23
|
-
|
|
24
|
-
> **์ ์ ์กฐ๊ฑด:**
|
|
25
|
-
> - **oh-my-claudecode (OMC)** ๊ฐ ์ค์น๋์ด ์์ด์ผ ํฉ๋๋ค (`dispatch: omc` ๋ณ๋ ฌ ๋ชจ๋)
|
|
26
|
-
> - **tmux** ์ธ์
์์์ ์คํํด์ผ ํฉ๋๋ค (`dispatch: omc` ๋ณ๋ ฌ ๋ชจ๋, `$TMUX` ํ๊ฒฝ๋ณ์ ํ์ธ)
|
|
27
|
-
> - ์ ํํ ๋ชจ๋ธ์ ๋ก์ปฌ CLI๊ฐ ์ค์น๋์ด ์์ด์ผ ํฉ๋๋ค (`claude`, `gemini`, `codex`)
|
|
28
|
-
> - `dispatch: direct` ๋ชจ๋์์๋ OMC/tmux ์์ด๋ ๋์ํฉ๋๋ค (์์ฐจ ์คํ, tmux fallback ๊ฒฝ๊ณ ์์)
|
|
29
|
-
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
## 1๋จ๊ณ: ์ค์ ๋ก๋
|
|
33
|
-
|
|
34
|
-
`.patina.default.yaml`์ ์ฝ์ด ์ค์ ์ ๋ก๋ํ๋ค.
|
|
35
|
-
|
|
36
|
-
```
|
|
37
|
-
Glob .patina.default.yaml โ Read
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
์ค์ ์์ ๋ค์์ ํ์ธ:
|
|
41
|
-
- `profile`: ์ฌ์ฉํ ํ๋กํ (๊ธฐ๋ณธ: `default`)
|
|
42
|
-
- `patterns`: ๋ก๋ํ ํจํด ํฉ ๋ชฉ๋ก
|
|
43
|
-
- `skip-patterns`: ๊ฑด๋๋ธ ํจํด ํฉ
|
|
44
|
-
- `blocklist`: ์ถ๊ฐ ๊ฐ์ง ์ดํ
|
|
45
|
-
- `allowlist`: ๊ฐ์ง ์ ์ธ ์ดํ
|
|
46
|
-
- `max-models`: MAX ๋ชจ๋์์ ์ฌ์ฉํ ๋ชจ๋ธ ๋ชฉ๋ก (๊ธฐ๋ณธ: `[claude, gemini]`)
|
|
47
|
-
- `dispatch`: ๋์คํจ์น ๋ชจ๋ (`omc` ๋๋ `direct`, ๊ธฐ๋ณธ: `omc`)
|
|
48
|
-
|
|
49
|
-
`$ARGUMENTS`์์ ์ต์
์ ํ์ฑํ์ฌ ์ค์ ์ ์ค๋ฒ๋ผ์ด๋:
|
|
50
|
-
- `--profile <name>`: ํ๋กํ ๋ณ๊ฒฝ
|
|
51
|
-
- `--lang <code>`: ์ฒ๋ฆฌ ์ธ์ด ๋ณ๊ฒฝ (ko, en, zh, ja)
|
|
52
|
-
- `--models <list>`: ์ฌ์ฉํ ๋ชจ๋ธ ๋ณ๊ฒฝ (์ผํ ๊ตฌ๋ถ, ์: `claude,gemini,codex`)
|
|
53
|
-
- `--dispatch <mode>`: ๋์คํจ์น ๋ชจ๋ ๋ณ๊ฒฝ (`omc` ๋๋ `direct`)
|
|
54
|
-
|
|
55
|
-
๋ชจ๋ธ ์ ํจ์ฑ ๊ฒ์ฌ: ์์ฒญ๋ ๋ชจ๋ ๋ชจ๋ธ์ด ์ง์ ๋ชฉ๋ก (`claude`, `codex`, `gemini`) ์์ ์๋์ง ํ์ธํ๋ค. ์ง์ํ์ง ์๋ ๋ชจ๋ธ์ด ์์ผ๋ฉด ๊ฒฝ๊ณ ๋ฅผ ํ์ํ๊ณ ํด๋น ๋ชจ๋ธ์ ๊ฑด๋๋ด๋ค.
|
|
56
|
-
|
|
57
|
-
### ์ค์น ์ธํฐ๋ทฐ (์ต์ด ์คํ)
|
|
58
|
-
|
|
59
|
-
`.patina.yaml` (์ฌ์ฉ์ ์ค์ ํ์ผ)์ด ํ๋ก์ ํธ ๋ฃจํธ์ ์์ผ๋ฉด ์ต์ด ์คํ์ผ๋ก ๊ฐ์ฃผํ๊ณ `AskUserQuestion`์ผ๋ก ์ธํฐ๋ทฐ๋ฅผ ์งํํ๋ค:
|
|
60
|
-
|
|
61
|
-
1. **๋ชจ๋ธ ์ ํ**: "MAX mode์์ ์ฌ์ฉํ ๋ชจ๋ธ์ ์ ํํ์ธ์ (์ผํ ๊ตฌ๋ถ): claude, gemini, codex"
|
|
62
|
-
- ๊ธฐ๋ณธ๊ฐ: `claude, gemini`
|
|
63
|
-
- ์๋ต์ `max-models` ๋ชฉ๋ก์ผ๋ก ์ ์ฅ
|
|
64
|
-
|
|
65
|
-
2. **๋์คํจ์น ๋ชจ๋**: "๋์คํจ์น ๋ชจ๋๋ฅผ ์ ํํ์ธ์:"
|
|
66
|
-
- `omc` โ tmux pane ๋ณ๋ ฌ ์คํ (์ถ์ฒ, OMC + tmux ํ์)
|
|
67
|
-
- `direct` โ stdin pipe ์์ฐจ ์คํ (์์กด์ฑ ์์)
|
|
68
|
-
- ๊ธฐ๋ณธ๊ฐ: `omc`
|
|
69
|
-
|
|
70
|
-
3. **CLI ์ค์น ํ์ธ**: ์ ํ๋ ๊ฐ ๋ชจ๋ธ์ CLI๋ฅผ `which` ๋ช
๋ น์ผ๋ก ํ์ธํ๋ค
|
|
71
|
-
- ๋ฏธ์ค์น ๋ชจ๋ธ์ด ์์ผ๋ฉด ์ค์น ์๋ด๋ฅผ ํ์:
|
|
72
|
-
- `claude`: `npm install -g @anthropic-ai/claude-code`
|
|
73
|
-
- `gemini`: `npm install -g @google/gemini-cli`
|
|
74
|
-
- `codex`: `npm install -g @openai/codex`
|
|
75
|
-
- ๋ฏธ์ค์น ๋ชจ๋ธ์ด ์์ด๋ ์ค์ ์ ์ ์ฅํ๋ค (๋์ค์ ์ค์น ๊ฐ๋ฅ)
|
|
76
|
-
|
|
77
|
-
4. **OMC/tmux ํ์ธ** (`dispatch: omc` ์ ํ ์):
|
|
78
|
-
- `$TMUX` ํ๊ฒฝ๋ณ์๋ก tmux ์ธ์
์ฌ๋ถ ํ์ธ
|
|
79
|
-
- tmux๊ฐ ์๋๋ฉด ์๋์ ์ ํํ ๊ฒฝ๊ณ ๋ฅผ stderr์ ์ถ๋ ฅํ๊ณ `dispatch: direct`๋ก ์๋ ์ ํ:
|
|
80
|
-
`[patina-max] tmux not detected. Falling back to sequential dispatch (expect ~Xmin instead of ~Ys). Pass --dispatch direct to silence.`
|
|
81
|
-
- ์ฌ์ฉ์๊ฐ ๋ช
์์ ์ผ๋ก `--dispatch direct`๋ฅผ ์ ํํ ๊ฒฝ์ฐ์๋ ๊ฒฝ๊ณ ๋ฅผ ์ถ๋ ฅํ์ง ์๋๋ค
|
|
82
|
-
|
|
83
|
-
์ธํฐ๋ทฐ ๊ฒฐ๊ณผ๋ฅผ `.patina.yaml`์ ์ ์ฅํ๋ค:
|
|
84
|
-
|
|
85
|
-
```yaml
|
|
86
|
-
# Generated by patina-max setup interview
|
|
87
|
-
max-models:
|
|
88
|
-
- claude
|
|
89
|
-
- gemini
|
|
90
|
-
dispatch: omc
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
์ดํ ์คํ์์๋ `.patina.yaml`์ด ์กด์ฌํ๋ฉด ์ธํฐ๋ทฐ๋ฅผ ๊ฑด๋๋ฐ๊ณ ๋ฐ๋ก ์ค์ ์ ๋ก๋ํ๋ค. `.patina.default.yaml`๋ณด๋ค `.patina.yaml`์ ๊ฐ์ด ์ฐ์ ํ๋ค.
|
|
94
|
-
|
|
95
|
-
---
|
|
96
|
-
|
|
97
|
-
## 2๋จ๊ณ: ํจํด ํฉ ๋ก๋
|
|
98
|
-
|
|
99
|
-
1๋จ๊ณ์์ ๊ฒฐ์ ๋ ์ธ์ด ์ฝ๋๋ฅผ `{lang}`์ผ๋ก ์ฌ์ฉํ์ฌ ํจํด ํฉ์ ์๋ ํ์ํ๋ค.
|
|
100
|
-
|
|
101
|
-
```
|
|
102
|
-
Glob patterns/{lang}-*.md โ Read ๊ฐ ํ์ผ
|
|
103
|
-
Glob custom/patterns/{lang}-*.md โ Read (์ฌ์ฉ์ ์ปค์คํ
ํจํด ์ถ๊ฐ ๋ก๋)
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
`skip-patterns`์ ํด๋นํ๋ ํฉ์ ์ ์ธํ๋ค.
|
|
107
|
-
|
|
108
|
-
๋ชจ๋ ํจํด ํฉ์ ์ ์ฒด ๋ด์ฉ์ ๋ฉ๋ชจ๋ฆฌ์ ๋ณด๊ดํ๋ค โ 4๋จ๊ณ์์ ์์ปค ํ๋กฌํํธ์ ์ธ๋ผ์ธํด์ผ ํ๋ค.
|
|
109
|
-
|
|
110
|
-
---
|
|
111
|
-
|
|
112
|
-
## 3๋จ๊ณ: ํ๋กํ + ๋ชฉ์๋ฆฌ ์ง์นจ ๋ก๋
|
|
113
|
-
|
|
114
|
-
```
|
|
115
|
-
Read profiles/{profile}.md
|
|
116
|
-
Glob custom/profiles/{profile}.md โ Read (์ปค์คํ
ํ๋กํ ์ฐ์ )
|
|
117
|
-
Read core/voice.md
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
ํ๋กํ๊ณผ voice.md์ ์ ์ฒด ๋ด์ฉ์ ๋ฉ๋ชจ๋ฆฌ์ ๋ณด๊ดํ๋ค โ 4๋จ๊ณ์์ ์์ปค ํ๋กฌํํธ์ ์ธ๋ผ์ธํด์ผ ํ๋ค.
|
|
121
|
-
|
|
122
|
-
---
|
|
123
|
-
|
|
124
|
-
## 4๋จ๊ณ: ์์ปค ํ๋กฌํํธ ๊ตฌ์ฑ
|
|
125
|
-
|
|
126
|
-
๋ชจ๋ ๋ชจ๋ธ์ ๋ณด๋ผ **ํ๋์ ์๋ฆฝํ ํ๋กฌํํธ**๋ฅผ ๊ตฌ์ฑํ๋ค. ์ด ํ๋กฌํํธ๋ ๋ชจ๋ธ์ ๋ฌด๊ดํ๊ฒ ๋์ํด์ผ ํ๋ค.
|
|
127
|
-
|
|
128
|
-
ํ๋กฌํํธ ๊ตฌ์กฐ:
|
|
129
|
-
|
|
130
|
-
```
|
|
131
|
-
๋น์ ์ AI๊ฐ ์์ฑํ ํ
์คํธ์์ AI ํน์ ์ ํจํด์ ์ฐพ์ ์ ๊ฑฐํ์ฌ, ๊ธ์ ์์ฐ์ค๋ฝ๊ณ ์ฌ๋์ด ์ด ๊ฒ์ฒ๋ผ ๋ง๋๋ ํธ์ง์์
๋๋ค.
|
|
132
|
-
|
|
133
|
-
## ํจํด ํฉ
|
|
134
|
-
{2๋จ๊ณ์์ ๋ก๋ํ ๋ชจ๋ ํจํด ํฉ์ ์ ์ฒด ๋ด์ฉ์ ์ฌ๊ธฐ์ ์ธ๋ผ์ธ}
|
|
135
|
-
|
|
136
|
-
## ํ๋กํ ์ง์นจ
|
|
137
|
-
{3๋จ๊ณ์์ ๋ก๋ํ ํ๋กํ ๋ด์ฉ์ ์ฌ๊ธฐ์ ์ธ๋ผ์ธ}
|
|
138
|
-
|
|
139
|
-
## ๋ชฉ์๋ฆฌ ์ง์นจ
|
|
140
|
-
{3๋จ๊ณ์์ ๋ก๋ํ voice.md ๋ด์ฉ์ ์ฌ๊ธฐ์ ์ธ๋ผ์ธ}
|
|
141
|
-
|
|
142
|
-
## ์ฒ๋ฆฌ ์ง์นจ
|
|
143
|
-
1. ์์ ํจํด ํฉ์์ ์ ์๋ ๋ชจ๋ AI ํจํด์ ์
๋ ฅ ํ
์คํธ์์ ์ค์บํ๋ผ
|
|
144
|
-
2. ๋ฐ๊ฒฌ๋ AI ํจํด์ ์์ฐ์ค๋ฌ์ด ๋์์ผ๋ก ๊ต์ฒดํ๋ผ
|
|
145
|
-
3. ํต์ฌ ๋ฉ์์ง์ ์๋ฏธ๋ฅผ ๋ณด์กดํ๋ผ
|
|
146
|
-
4. ํ๋กํ์ ์ด์กฐ ์ง์นจ์ ๋ฐ๋ผ ํค์ ์กฐ์ ํ๋ผ
|
|
147
|
-
5. ๋ชฉ์๋ฆฌ ์ง์นจ์ ๋ฐ๋ผ ์ค์ ์ฌ๋์ ๊ฐ์ฑ์ ๋ถ์ด๋ฃ์ด๋ผ
|
|
148
|
-
|
|
149
|
-
## ์
๋ ฅ ํ
์คํธ
|
|
150
|
-
{์ฌ์ฉ์๊ฐ ์ ๊ณตํ ์๋ฌธ ํ
์คํธ}
|
|
151
|
-
|
|
152
|
-
## ์ค์ ์ ์ฝ
|
|
153
|
-
Humanize this text by removing the AI patterns described above.
|
|
154
|
-
Output ONLY the humanized text.
|
|
155
|
-
Do not use any tools. Do not read or modify any files.
|
|
156
|
-
Do not ask questions. Do not include explanations or metadata.
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
์ด ํ๋กฌํํธ๋ฅผ ์คํ๋ง๋ค ๊ณ ์ ํ ์์ ๋๋ ํฐ๋ฆฌ์ ์ ์ฅํ๋ค:
|
|
160
|
-
|
|
161
|
-
```bash
|
|
162
|
-
RUN_DIR="$(mktemp -d /tmp/patina-max.XXXXXX)"
|
|
163
|
-
PROMPT_FILE="$RUN_DIR/prompt.txt"
|
|
164
|
-
TIMEOUT_SECONDS=900
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
์ดํ ์์์ `$RUN_DIR`/`$PROMPT_FILE`์ ์ด ์คํ์์ ์์ฑํ ๊ฒฝ๋ก๋ฅผ ๋ปํ๋ค. ์ต์ข
์ถ๋ ฅ์ด ๋๋ ๋๊น์ง ์ด ๋๋ ํฐ๋ฆฌ๋ฅผ ์ ์งํ๊ณ , ๋ง์ง๋ง์ ์ ๋ฆฌํ๋ค.
|
|
168
|
-
|
|
169
|
-
```
|
|
170
|
-
Write tool โ $PROMPT_FILE
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
---
|
|
174
|
-
|
|
175
|
-
## 5๋จ๊ณ: ๋ชจ๋ธ ๋์คํจ์น (dispatch-aware)
|
|
176
|
-
|
|
177
|
-
ํ๋กฌํํธ๋ ์ด๋ฏธ `$PROMPT_FILE`์ ์ ์ฅ๋์ด ์๋ค (4๋จ๊ณ).
|
|
178
|
-
Claude/Codex๋ **stdin pipe**, Gemini๋ **`$(cat file)` ์ธ์ ์นํ**์ผ๋ก ํ๋กฌํํธ๋ฅผ ์ ๋ฌํ๋ค.
|
|
179
|
-
ํ๋กฌํํธ๋ ํ์ผ์์ ์ฝ์ผ๋ฏ๋ก ์
ธ ๋ณ์ ํ์ฅ ์์ด ์์ ํ๊ฒ ์ ๋ฌ๋๋ค.
|
|
180
|
-
|
|
181
|
-
- Claude: `claude -p`
|
|
182
|
-
- Gemini: `gemini -p "$(cat $PROMPT_FILE)" --output-format text`
|
|
183
|
-
- Codex: `codex exec --skip-git-repo-check --output-last-message <file>`
|
|
184
|
-
|
|
185
|
-
๊ณ ์ `/tmp/patina-max-*` ํ์ผ๋ช
์ ์ฌ์ฉํ์ง ์๋๋ค. ๋ชจ๋ ์ฐ์ถ๋ฌผ์ `$RUN_DIR` ์๋์ ์ ์ฅํ๋ค.
|
|
186
|
-
|
|
187
|
-
### Dispatch preflight
|
|
188
|
-
|
|
189
|
-
`DISPATCH_MODE`๋ ์ค์ ํ์ผ๊ณผ `--dispatch` ํ๋๊ทธ๋ฅผ ๋ฐ์ํ ์ต์ข
dispatch ๊ฐ์ด๋ค. ์ฌ์ฉ์๊ฐ `--dispatch direct`๋ฅผ ๋ช
์ํ์ผ๋ฉด ์ด preflight๋ ๊ฒฝ๊ณ ์์ด direct ๋ชจ๋๋ฅผ ์ ์งํ๋ค.
|
|
190
|
-
|
|
191
|
-
```bash
|
|
192
|
-
if [ "$DISPATCH_MODE" = "omc" ] && [ -z "${TMUX:-}" ]; then
|
|
193
|
-
MODEL_COUNT=$(printf '%s\n' $SELECTED_MODELS | sed '/^$/d' | wc -l | tr -d ' ')
|
|
194
|
-
DIRECT_MIN=$(( (MODEL_COUNT * TIMEOUT_SECONDS + 59) / 60 ))
|
|
195
|
-
printf '[patina-max] tmux not detected. Falling back to sequential dispatch (expect ~%smin instead of ~%ss). Pass --dispatch direct to silence.\n' \
|
|
196
|
-
"$DIRECT_MIN" "$TIMEOUT_SECONDS" >&2
|
|
197
|
-
DISPATCH_MODE="direct"
|
|
198
|
-
fi
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### ๋ชจ๋ A: OMC dispatch (`dispatch: omc`)
|
|
202
|
-
|
|
203
|
-
tmux pane์ ์ฌ์ฉํ์ฌ ๋ชจ๋ ๋ชจ๋ธ์ **๋ณ๋ ฌ** ์คํํ๋ค. ๊ฐ pane์์ ํ๋กฌํํธ ํ์ผ์ ์ฝ์ด ์ ๋ฌํ๊ณ , ์๋ฃ ์ sentinel ํ์ผ์ ์์ฑํ๋ค. wall-clock ์ํ์ ๊ฐ์ฅ ๋๋ฆฐ ๋ชจ๋ธ ํ๋์ ๊ฐ๊น๋ค (`TIMEOUT_SECONDS=900`์ด๋ฉด ์ฝ 900์ด).
|
|
204
|
-
|
|
205
|
-
```bash
|
|
206
|
-
SELECTED_MODELS="claude gemini codex" # ์ค์ ๋ก๋ ์ค์ /ํ๋๊ทธ์์ ์ ํ๋ ๋ชจ๋ธ๋ง ํฌํจ
|
|
207
|
-
CLAUDE_PANE=""
|
|
208
|
-
GEMINI_PANE=""
|
|
209
|
-
CODEX_PANE=""
|
|
210
|
-
|
|
211
|
-
# Claude
|
|
212
|
-
CLAUDE_PANE=$(tmux split-window -d -P -F "#{pane_id}" -h \
|
|
213
|
-
"cat \"$PROMPT_FILE\" | claude -p > \"$RUN_DIR/claude-output.txt\" 2> \"$RUN_DIR/claude-log.txt\"; printf '%s' \$? > \"$RUN_DIR/claude.exit\"; touch \"$RUN_DIR/claude.done\"")
|
|
214
|
-
|
|
215
|
-
# Gemini
|
|
216
|
-
GEMINI_PANE=$(tmux split-window -d -P -F "#{pane_id}" -v \
|
|
217
|
-
"gemini -p \"\$(cat \\\"$PROMPT_FILE\\\")\" --output-format text > \"$RUN_DIR/gemini-output.txt\" 2> \"$RUN_DIR/gemini-log.txt\"; printf '%s' \$? > \"$RUN_DIR/gemini.exit\"; touch \"$RUN_DIR/gemini.done\"")
|
|
218
|
-
|
|
219
|
-
# Codex
|
|
220
|
-
CODEX_PANE=$(tmux split-window -d -P -F "#{pane_id}" -v \
|
|
221
|
-
"cat \"$PROMPT_FILE\" | codex exec --skip-git-repo-check --output-last-message \"$RUN_DIR/codex-output.txt\" > \"$RUN_DIR/codex-log.txt\" 2>&1; printf '%s' \$? > \"$RUN_DIR/codex.exit\"; touch \"$RUN_DIR/codex.done\"")
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
์ค์ ์คํ์ `max-models`์ ํฌํจ๋ ๋ชจ๋ธ์ pane๋ง ์์ฑํ๊ณ , pane id๋ ํด๋น ๋ชจ๋ธ์ ๋ํด์๋ง ๊ธฐ๋กํ๋ค.
|
|
225
|
-
|
|
226
|
-
**์๋ฃ ๋๊ธฐ**: Bash๋ก sentinel ํ์ผ์ ํด๋งํ๋ค.
|
|
227
|
-
|
|
228
|
-
```bash
|
|
229
|
-
START_TIME=$(date +%s)
|
|
230
|
-
|
|
231
|
-
# ์ ํ๋ ๋ชจ๋ธ๋ค์ .done ํ์ผ๋ง ๊ธฐ๋ค๋ฆฐ๋ค
|
|
232
|
-
while true; do
|
|
233
|
-
ALL_DONE=true
|
|
234
|
-
for model in $SELECTED_MODELS; do
|
|
235
|
-
[ -f "$RUN_DIR/$model.done" ] || ALL_DONE=false
|
|
236
|
-
done
|
|
237
|
-
$ALL_DONE && break
|
|
238
|
-
|
|
239
|
-
NOW=$(date +%s)
|
|
240
|
-
if [ $((NOW - START_TIME)) -ge $TIMEOUT_SECONDS ]; then
|
|
241
|
-
for model in $SELECTED_MODELS; do
|
|
242
|
-
if [ ! -f "$RUN_DIR/$model.done" ]; then
|
|
243
|
-
printf '124' > "$RUN_DIR/$model.exit"
|
|
244
|
-
printf 'timeout after %ss\n' "$TIMEOUT_SECONDS" > "$RUN_DIR/$model.log.txt"
|
|
245
|
-
touch "$RUN_DIR/$model.timeout" "$RUN_DIR/$model.done"
|
|
246
|
-
fi
|
|
247
|
-
done
|
|
248
|
-
[ -n "$CLAUDE_PANE" ] && tmux kill-pane -t "$CLAUDE_PANE" 2>/dev/null || true
|
|
249
|
-
[ -n "$GEMINI_PANE" ] && tmux kill-pane -t "$GEMINI_PANE" 2>/dev/null || true
|
|
250
|
-
[ -n "$CODEX_PANE" ] && tmux kill-pane -t "$CODEX_PANE" 2>/dev/null || true
|
|
251
|
-
break
|
|
252
|
-
fi
|
|
253
|
-
|
|
254
|
-
sleep 3
|
|
255
|
-
done
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
> tmux pane์ ์คํ ์๋ฃ ํ ์๋์ผ๋ก ๋ซํ๋ค. ์งํ ์ค์๋ ์ฌ์ฉ์๊ฐ pane์ ์ ํํ์ฌ ๊ฐ ๋ชจ๋ธ์ ์คํ ์ํ๋ฅผ ์๊ฐ์ ์ผ๋ก ํ์ธํ ์ ์๋ค. ํ์์์์ด ๋ฐ์ํ pane์ kill ํ `failed`๋ก ํ์ํ๋ค.
|
|
259
|
-
|
|
260
|
-
### ๋ชจ๋ B: Direct dispatch (`dispatch: direct`)
|
|
261
|
-
|
|
262
|
-
tmux ์์ด ์์ฐจ์ ์ผ๋ก ์คํํ๋ค. OMC/tmux๊ฐ ์๋ ํ๊ฒฝ์์์ fallback. wall-clock ์ํ์ ์ ํํ ๋ชจ๋ธ ์์ ๋น๋กํ๋ค (`TIMEOUT_SECONDS=900`, ๋ชจ๋ธ 3๊ฐ๋ฉด ์ฝ 45๋ถ๊น์ง ๊ฐ๋ฅ). ๋ณ๋ ฌ tmux ์คํ๋ณด๋ค ๋๋ฆด ์ ์์ผ๋ฏ๋ก, ์๋์ ์ผ๋ก direct๋ฅผ ์ฐ๋ ๊ฒฝ์ฐ `--dispatch direct`๋ฅผ ๋ช
์ํ๋ฉด fallback ๊ฒฝ๊ณ ๋ฅผ ๋ ์ ์๋ค.
|
|
263
|
-
|
|
264
|
-
```bash
|
|
265
|
-
# Claude
|
|
266
|
-
timeout "${TIMEOUT_SECONDS}s" sh -c 'cat "$1" | claude -p > "$2" 2> "$3"' sh \
|
|
267
|
-
"$PROMPT_FILE" "$RUN_DIR/claude-output.txt" "$RUN_DIR/claude-log.txt"
|
|
268
|
-
printf '%s' $? > "$RUN_DIR/claude.exit"
|
|
269
|
-
touch "$RUN_DIR/claude.done"
|
|
270
|
-
|
|
271
|
-
# Gemini
|
|
272
|
-
timeout "${TIMEOUT_SECONDS}s" sh -c 'gemini -p "$(cat "$1")" --output-format text > "$2" 2> "$3"' sh \
|
|
273
|
-
"$PROMPT_FILE" "$RUN_DIR/gemini-output.txt" "$RUN_DIR/gemini-log.txt"
|
|
274
|
-
printf '%s' $? > "$RUN_DIR/gemini.exit"
|
|
275
|
-
touch "$RUN_DIR/gemini.done"
|
|
276
|
-
|
|
277
|
-
# Codex
|
|
278
|
-
timeout "${TIMEOUT_SECONDS}s" sh -c 'cat "$1" | codex exec --skip-git-repo-check --output-last-message "$2" > "$3" 2>&1' sh \
|
|
279
|
-
"$PROMPT_FILE" "$RUN_DIR/codex-output.txt" "$RUN_DIR/codex-log.txt"
|
|
280
|
-
printf '%s' $? > "$RUN_DIR/codex.exit"
|
|
281
|
-
touch "$RUN_DIR/codex.done"
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
์ค์ ์คํ์ `max-models`์ ํฌํจ๋ ๋ชจ๋ธ์๋ง ์ ์ฉํ๋ค. ๊ฐ ๋ช
๋ น์ `TIMEOUT_SECONDS` ์ํ์ ๋๊ณ , `timeout`์ด ์์ผ๋ฉด ๋๋ฑํ ํ์์์ ๋ํผ(`gtimeout` ๋ฑ)๋ก ๋์ฒดํ๋ค.
|
|
285
|
-
|
|
286
|
-
### ๊ฒฐ๊ณผ ์์ง (๊ณตํต)
|
|
287
|
-
|
|
288
|
-
- `claude`
|
|
289
|
-
1. `$RUN_DIR/claude-output.txt`๋ฅผ Readํ๋ค
|
|
290
|
-
2. `$RUN_DIR/claude.exit`๊ฐ 0์ด๊ณ output์ด ๋น์ด ์์ง ์์ผ๋ฉด ๊ฒฐ๊ณผ ํ
์คํธ๋ก ์ฌ์ฉํ๋ค
|
|
291
|
-
3. ์คํจ ๋๋ ๋น ์ถ๋ ฅ์ด๋ฉด `$RUN_DIR/claude-log.txt`๋ฅผ ์ง๋จ ์ ๋ณด๋ก Readํ๋ค
|
|
292
|
-
|
|
293
|
-
- `gemini`
|
|
294
|
-
1. `$RUN_DIR/gemini-output.txt`๋ฅผ Readํ๋ค
|
|
295
|
-
2. `$RUN_DIR/gemini.exit`๊ฐ 0์ด๊ณ output์ด ๋น์ด ์์ง ์์ผ๋ฉด ๊ฒฐ๊ณผ ํ
์คํธ๋ก ์ฌ์ฉํ๋ค
|
|
296
|
-
3. `$RUN_DIR/gemini-log.txt`์๋ ์ธ์ฆ/ํ์ฅ/MCP ๊ฒฝ๊ณ ๊ฐ ํฌํจ๋ ์ ์์ผ๋ฏ๋ก, ์คํจ ์ง๋จ์ฉ์ผ๋ก๋ง ์ฌ์ฉํ๋ค
|
|
297
|
-
|
|
298
|
-
- `codex`
|
|
299
|
-
1. `$RUN_DIR/codex-output.txt`๋ฅผ Readํ๋ค (`--output-last-message`๊ฐ ๊ธฐ๋กํ ์ต์ข
ํ
์คํธ)
|
|
300
|
-
2. `$RUN_DIR/codex.exit`๊ฐ 0์ด๊ณ output์ด ๋น์ด ์์ง ์์ผ๋ฉด ๊ฒฐ๊ณผ ํ
์คํธ๋ก ์ฌ์ฉํ๋ค
|
|
301
|
-
3. ์คํจ ๋๋ ๋น ์ถ๋ ฅ์ด๋ฉด `$RUN_DIR/codex-log.txt`๋ฅผ ์ง๋จ ์ ๋ณด๋ก Readํ๋ค
|
|
302
|
-
|
|
303
|
-
### ์คํจ ์ฒ๋ฆฌ
|
|
304
|
-
|
|
305
|
-
- ํน์ ๋ชจ๋ธ์ exit code๊ฐ 0์ด ์๋๊ฑฐ๋, output ํ์ผ์ด ๋น์ด ์๊ฑฐ๋, ํ์ผ์ด ์์ผ๋ฉด โ ํด๋น ๋ชจ๋ธ์ `failed`๋ก ํ์ํ๊ณ ๋๋จธ์ง๋ก ๊ณ์ ์งํ
|
|
306
|
-
- `.timeout` ํ์ผ์ด ์๊ฑฐ๋ exit code๊ฐ `124`์ด๋ฉด โ `timed out`์ผ๋ก ๊ธฐ๋กํ๊ณ `failed`๋ก ํ์
|
|
307
|
-
- `.done` ํ์ผ์ ์๊ฒผ์ง๋ง output ํ์ผ์ด ๋น์ด ์์ผ๋ฉด โ CLI๊ฐ ๋น ์๋ต์ ๋ฐํํ ๊ฒ์ด๋ฏ๋ก `failed`๋ก ํ์
|
|
308
|
-
- ๋ชจ๋ ๋ชจ๋ธ์ด ์คํจํ ๊ฒฝ์ฐ โ ์๋ฌ ๋ฉ์์ง์ ํจ๊ป ๊ฐ ๋ชจ๋ธ์ output/log ํ์ผ ๋ด์ฉ์ ์ง๋จ ์ ๋ณด๋ก ์ถ๋ ฅํ๊ณ ์ข
๋ฃ
|
|
309
|
-
- `dispatch: omc`์์ tmux๊ฐ ์์ผ๋ฉด (`$TMUX` ๋ฏธ์ค์ ) โ `[patina-max] tmux not detected. Falling back to sequential dispatch (expect ~Xmin instead of ~Ys). Pass --dispatch direct to silence.` ํ์์ ๊ฒฝ๊ณ ํ direct ๋ชจ๋๋ก ์๋ ์ ํ
|
|
310
|
-
- `--dispatch direct`๋ฅผ ๋ช
์ํ ๊ฒฝ์ฐ โ ์ด๋ฏธ ์์ฐจ ์คํ์ ์ ํํ ๊ฒ์ด๋ฏ๋ก tmux fallback ๊ฒฝ๊ณ ๋ฅผ ์ถ๋ ฅํ์ง ์์
|
|
311
|
-
|
|
312
|
-
---
|
|
313
|
-
|
|
314
|
-
## 6๋จ๊ณ: ๊ฒฐ๊ณผ ํ๊ฐ (AI ์ ์ฌ๋ ์ ์)
|
|
315
|
-
|
|
316
|
-
๊ฐ ๋ชจ๋ธ์ humanize ๊ฒฐ๊ณผ์ ๋ํด `core/scoring.md`์ ์์ ๊ธฐ๋ฐ ์ค์ฝ์ด๋ง ์๊ณ ๋ฆฌ์ฆ์ ์ ์ฉํ๋ค.
|
|
317
|
-
|
|
318
|
-
2๋จ๊ณ์์ ๋ก๋ํ ๋ชจ๋ ํจํด ํฉ์ ๊ธฐ์ค์ผ๋ก, ๊ฐ ๊ฒฐ๊ณผ์ ๋ํด SKILL.md์ `--score` ๋ชจ๋์ ๋์ผํ ์ ์ฐจ๋ฅผ ์คํํ๋ค:
|
|
319
|
-
|
|
320
|
-
1. **ํจํด ๊ฐ์ง**: ๋ชจ๋ ํจํด์ ์ค์บํ๊ณ , ๊ฐ์ง๋ ๊ฐ ํจํด์ severity๋ฅผ ๋ถ์ฌํ๋ค (`core/scoring.md`์ ์ฌ๊ฐ๋ ๋ฃจ๋ธ๋ฆญ ์ฐธ์กฐ)
|
|
321
|
-
2. **ํ๋กํ ์ค๋ฒ๋ผ์ด๋ ์ ์ฉ**: pattern-overrides๊ฐ ์์ผ๋ฉด severity๋ฅผ ์กฐ์ ํ๋ค
|
|
322
|
-
3. **์นดํ
๊ณ ๋ฆฌ ์ ์ ๊ณ์ฐ**: `์นดํ
๊ณ ๋ฆฌ ์ ์ = (์กฐ์ ๋ ์ฌ๊ฐ๋ ํฉ๊ณ / (ํจํด ์ ร 3)) ร 100`
|
|
323
|
-
4. **์ ์ฒด ์ ์ ๊ณ์ฐ**: ์นดํ
๊ณ ๋ฆฌ ์ ์์ ๊ฐ์ค ํ๊ท (`ouroboros.category-weights.{lang}` ์ฌ์ฉ)
|
|
324
|
-
|
|
325
|
-
์ด ์ ์ฐจ๋ ๊ฐ ๋ชจ๋ธ์ ๊ฒฐ๊ณผ์ ๋ํด ๋
๋ฆฝ์ ์ผ๋ก ์คํํ๋ค. ๋ชจ๋ ๋ชจ๋ธ์ด ๋์ผํ ์์์ผ๋ก ํ๊ฐ๋๋ฏ๋ก ๊ณต์ ํ ๋น๊ต๊ฐ ๊ฐ๋ฅํ๋ค.
|
|
326
|
-
|
|
327
|
-
๊ฐ ๊ฒฐ๊ณผ์ ๋ํด ์ถ๊ฐ๋ก MPS(Meaning Preservation Score)๋ฅผ ์ฐ์ถํ๋ค. ์๋ณธ ํ
์คํธ์์ ์๋ฏธ ์ต์ปค๋ฅผ ์ถ์ถํ๊ณ , ๊ฐ ๋ชจ๋ธ์ humanize ๊ฒฐ๊ณผ๊ฐ ์ต์ปค๋ฅผ ์ผ๋ง๋ ๋ณด์กดํ๋์ง๋ฅผ `core/scoring.md` ยงยง 14-17์ ์ ์ฐจ๋ก ํ๊ฐํ๋ค.
|
|
328
|
-
|
|
329
|
-
> **์ฐธ๊ณ :** ์ด์ ๋ฒ์ ์์๋ MAX ๋ชจ๋๊ฐ ์ฃผ๊ด์ ํ๊ฐ๋ฅผ ์ฌ์ฉํ์ผ๋, v3.2.0๋ถํฐ `core/scoring.md`์ ์์ ๊ธฐ๋ฐ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ํตํฉ๋์๋ค. ๋จ์ผ ๋ชจ๋(`--score`)์ MAX ๋ชจ๋๊ฐ ๋์ผํ ์ค์ฝ์ด๋ง์ ์ฌ์ฉํ๋ค.
|
|
330
|
-
|
|
331
|
-
---
|
|
332
|
-
|
|
333
|
-
## 7๋จ๊ณ: ๋น๊ต ๋ฐ ์ ํ
|
|
334
|
-
|
|
335
|
-
๊ฒฐ๊ณผ ๋น๊ต ํ
์ด๋ธ์ ๊ตฌ์ฑํ๊ณ ์ต์ข
๋ณธ์ ์ ํํ๋ค.
|
|
336
|
-
|
|
337
|
-
### ๋น๊ต ํ
์ด๋ธ ํ์
|
|
338
|
-
|
|
339
|
-
```
|
|
340
|
-
| Model | AI Score | MPS | Status |
|
|
341
|
-
|---------|----------|------|---------|
|
|
342
|
-
| claude | 23 | 92 | โ
|
|
|
343
|
-
| gemini | 31 | 85 | โ
|
|
|
344
|
-
| codex | -- | -- | failed |
|
|
345
|
-
|
|
346
|
-
Best: claude (AI Score: 23, MPS: 92)
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
- MPS โฅ 70์ธ ํ๋ณด ์ค AI ์ ์๊ฐ ๊ฐ์ฅ ๋ฎ์ ๊ฒฐ๊ณผ๋ฅผ ์๋ ์ ํํ๋ค
|
|
350
|
-
- MPS < 70์ธ ํ๋ณด๋ AI ์ ์์ ๊ด๊ณ์์ด ํ๋ฝํ๋ค
|
|
351
|
-
- ๋ชจ๋ ํ๋ณด์ MPS < 70์ธ ๊ฒฝ์ฐ, MPS๊ฐ ๊ฐ์ฅ ๋์ ํ๋ณด๋ฅผ ์ ํํ๋ค (์๋ฏธ ๋ณด์กด ์ฐ์ )
|
|
352
|
-
- ๋์ ์ด๋ฉด ์ค์ ํ์ผ์ ๋ชจ๋ธ ์์์์ ๋จผ์ ์ค๋ ๊ฒ์ ์ฐ์ ํ๋ค
|
|
353
|
-
|
|
354
|
-
### Composite ์ฌ์ ํ artifact (์ ํ)
|
|
355
|
-
|
|
356
|
-
`patina-max/composite.py`๋ก 4์ถ(AI, MPS, RSS, EditCons) ์ฌ์ ํ์ ์คํํ๋ ค๋ฉด `$RUN_DIR`์ ์๋ ๋ ์ด์์์ ์์ฑํ๋ค. ๊ธฐ์กด `*-output.txt`๋ ์ง๋จ์ฉ์ผ๋ก ์ ์งํ๊ณ , ์ฑ๊ณตํ ํ๋ณด์ ์ต์ข
ํ
์คํธ๋ฅผ ๋ชจ๋ธ๋ณ Markdown ํ์ผ๋ก๋ ์ ์ฅํ๋ค.
|
|
357
|
-
|
|
358
|
-
```text
|
|
359
|
-
$RUN_DIR/
|
|
360
|
-
input.md
|
|
361
|
-
claude.md
|
|
362
|
-
gemini.md
|
|
363
|
-
codex.md
|
|
364
|
-
meta.md
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
- `input.md`: ์ฌ์ฉ์๊ฐ ์ ๊ณตํ ์๋ฌธ ํ
์คํธ
|
|
368
|
-
- `{model}.md`: ํด๋น ๋ชจ๋ธ์ humanize ๊ฒฐ๊ณผ. ์คํจํ ๋ชจ๋ธ์ ํ์ผ์ ์๋ตํ๊ฑฐ๋ ์คํจ ๋ฉ๋ชจ๋ง ๋๋ค
|
|
369
|
-
- `meta.md`: ํ๋ณด๋ณ `model`, `status`, `ai_score`, `mps` ๊ฐ์ `candidates:` ๋ชฉ๋ก์ผ๋ก ๊ธฐ๋กํ๋ค
|
|
370
|
-
|
|
371
|
-
`meta.md` ์์:
|
|
372
|
-
|
|
373
|
-
```yaml
|
|
374
|
-
candidates:
|
|
375
|
-
- model: claude
|
|
376
|
-
status: success
|
|
377
|
-
ai_score: 23
|
|
378
|
-
mps: 92
|
|
379
|
-
- model: gemini
|
|
380
|
-
status: failed
|
|
381
|
-
ai_score: n/a
|
|
382
|
-
mps: n/a
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
์คํ:
|
|
386
|
-
|
|
387
|
-
```bash
|
|
388
|
-
python3 patina-max/composite.py "$RUN_DIR"
|
|
389
|
-
```
|
|
390
|
-
|
|
391
|
-
์คํฌ๋ฆฝํธ๋ `$RUN_DIR/composite.md`์ `$RUN_DIR/winner.md`๋ฅผ ์์ฑํ๋ค. `--weights ai=0.4,rss=0.3`์ฒ๋ผ ๊ฐ์ค์น๋ฅผ ๋ฎ์ด์ธ ์ ์์ผ๋ฉฐ, ์ง์ ํ์ง ์์ ์ถ์ ๊ธฐ๋ณธ๊ฐ์ ์ฌ์ฉํ ๋ค ํฉ๊ณ๊ฐ 1์ด ๋๋๋ก ์ ๊ทํํ๋ค.
|
|
392
|
-
|
|
393
|
-
---
|
|
394
|
-
|
|
395
|
-
## 8๋จ๊ณ: ์ถ๋ ฅ
|
|
396
|
-
|
|
397
|
-
### ์ต์ข
์ถ๋ ฅ ๊ตฌ์ฑ
|
|
398
|
-
|
|
399
|
-
1. **๋น๊ต ํ
์ด๋ธ** โ ๋ชจ๋ ๋ชจ๋ธ์ AI ์ ์์ ์ํ
|
|
400
|
-
2. **์ต์ข
๋ณธ** โ ๊ฐ์ฅ ๋ฎ์ AI ์ ์๋ฅผ ๋ฐ์ ๊ฒฐ๊ณผ์ ์ ์ฒด ํ
์คํธ
|
|
401
|
-
3. **์นดํ
๊ณ ๋ฆฌ๋ณ ์ธ๋ถ ์ ์** โ ์ต์ข
๋ณธ์ ํจํด ์นดํ
๊ณ ๋ฆฌ๋ณ ์ ์
|
|
402
|
-
4. **์ฐจ์ ๊ฒฐ๊ณผ ์์ฝ** โ ๋ค๋ฅธ ๋ชจ๋ธ์ ๊ฒฐ๊ณผ๋ฅผ ์ ํ ์น์
์ผ๋ก ์ ๊ณต (์ฐธ๊ณ ์ฉ)
|
|
403
|
-
5. **์คํจ ์ ๋ณด** โ ์คํจํ ๋ชจ๋ธ์ด ์์ผ๋ฉด ์ฌ์ ํ์
|
|
404
|
-
6. **์์ ํ์ผ ์ ๋ฆฌ** โ ์ถ๋ ฅ์ด ๋๋ ๋ค `rm -rf "$RUN_DIR"`๋ก ์ ๋ฆฌ
|
|
405
|
-
|
|
406
|
-
### ์ถ๋ ฅ ์์
|
|
407
|
-
|
|
408
|
-
```
|
|
409
|
-
## MAX Mode ๊ฒฐ๊ณผ
|
|
410
|
-
|
|
411
|
-
### ๋น๊ต ํ
์ด๋ธ
|
|
412
|
-
| Model | AI Score | Status |
|
|
413
|
-
|---------|----------|---------|
|
|
414
|
-
| claude | 23 | success |
|
|
415
|
-
| gemini | 31 | success |
|
|
416
|
-
|
|
417
|
-
**Best: claude (AI Score: 23)**
|
|
418
|
-
|
|
419
|
-
### ์นดํ
๊ณ ๋ฆฌ๋ณ ์ ์ (claude)
|
|
420
|
-
| Category | Score |
|
|
421
|
-
|---------------|-------|
|
|
422
|
-
| Structure | 15 |
|
|
423
|
-
| Content | 20 |
|
|
424
|
-
| Language | 25 |
|
|
425
|
-
| Style | 30 |
|
|
426
|
-
| Communication | 25 |
|
|
427
|
-
| Filler | 20 |
|
|
428
|
-
|
|
429
|
-
### ์ต์ข
๋ณธ
|
|
430
|
-
{claude์ humanize ๊ฒฐ๊ณผ ์ ์ฒด ํ
์คํธ}
|
|
431
|
-
|
|
432
|
-
<details>
|
|
433
|
-
<summary>gemini ๊ฒฐ๊ณผ (AI Score: 31)</summary>
|
|
434
|
-
|
|
435
|
-
{gemini์ humanize ๊ฒฐ๊ณผ ์ ์ฒด ํ
์คํธ}
|
|
436
|
-
</details>
|
|
437
|
-
```
|
|
438
|
-
|
|
439
|
-
๋จ์ผ ๋ชจ๋ธ๋ง ์ฑ๊ณตํ ๊ฒฝ์ฐ, ํด๋น ๊ฒฐ๊ณผ๋ฅผ ์ต์ข
๋ณธ์ผ๋ก ์ ์ํ๋ "๋จ์ผ ๋ชจ๋ธ๋ง ์ฑ๊ณตํ์ฌ ๋น๊ต ๋ถ๊ฐ" ๊ฒฝ๊ณ ๋ฅผ ํ์ํ๋ค.
|
|
440
|
-
|
|
441
|
-
---
|
|
442
|
-
|
|
443
|
-
## ์ฐธ๊ณ
|
|
444
|
-
|
|
445
|
-
- ์ด ์คํฌ์ ๊ธฐ์กด `/patina` ์คํฌ์ ํ์ฅ ๋ฒ์ ์ผ๋ก, ๋์ผํ ํจํด ํฉ๊ณผ ํ๋กํ์ ์ฌ์ฉํฉ๋๋ค
|
|
446
|
-
- ๋ชจ๋ธ ์ถ๊ฐ/์ ๊ฑฐ๋ `.patina.default.yaml`์ `max-models` ๋๋ `--models` ํ๋๊ทธ๋ก ์ค์ ํฉ๋๋ค
|
|
447
|
-
- ์ง์ ๋ชจ๋ธ: `claude`, `codex`, `gemini` (Claude/Codex๋ stdin pipe, Gemini๋ `$(cat file)` ์ธ์ ์นํ)
|
|
448
|
-
- ๋์คํจ์น ๋ชจ๋: `omc` (tmux pane ๋ณ๋ ฌ, ๊ธฐ๋ณธ) / `direct` (์์ฐจ ์คํ, fallback)
|
|
449
|
-
- ๊ฐ ์คํ์ ๊ณ ์ temp dir๋ฅผ ์ฌ์ฉํ๋ฉฐ, ์ ํ๋ ๋ชจ๋ธ๋ง ๊ธฐ๋ค๋ฆฌ๊ณ , timeout ๋ชจ๋ธ์ ์๋์ผ๋ก `failed` ์ฒ๋ฆฌํ๋ค
|
|
450
|
-
- ์ต์ด ์คํ ์ ์ค์น ์ธํฐ๋ทฐ๋ก `.patina.yaml` ์์ฑ (๋ชจ๋ธ ์ ํ, ๋์คํจ์น ๋ชจ๋, CLI ์ค์น ํ์ธ)
|
|
451
|
-
- `--ouroboros`์ ํจ๊ป ์ฌ์ฉ ๊ฐ๋ฅ: ์ต๊ณ ์ ์๊ฐ target-score ์ด์์ด๋ฉด ํด๋น ๋ชจ๋ธ ๊ฒฐ๊ณผ๋ฅผ ์
๋ ฅ์ผ๋ก ์ฌ์คํํ์ฌ ์ ์๋ฅผ ์๋ ด์ํจ๋ค
|
|
452
|
-
|
|
453
|
-
## ํค ์ ํ (v3.10)
|
|
454
|
-
|
|
455
|
-
MAX mode์์ ํค ํด์์ SKILL.md 1๋จ๊ณ/4.5b๋จ๊ณ์ ๋์ผํ๊ฒ ์ฒ๋ฆฌ๋๋ค. 1๋จ๊ณ์์ resolved_tone, tone_source, tone_evidence, tone_confidence๋ฅผ ๊ฒฐ์ ํ ๋ค, ์์ปค ํ๋กฌํํธ(4๋จ๊ณ์์ ๊ฐ ๋ชจ๋ธ์ ์ ๋ฌํ๋ ์ธ๋ผ์ธ ํ๋กฌํํธ)์ `<tone-context>` ๋ธ๋ก์ผ๋ก ํฌํจํ๋ค. ๋ชจ๋ ๋์คํจ์น ๋ชจ๋ธ(claude, gemini, codex)์ ๋์ผํ ํค ์ปจํ
์คํธ๋ฅผ ๋ฐ์ ์ผ๊ด๋ ๋ชฉ์๋ฆฌ๋ก humanize๋ฅผ ์ํํ๋ค. ์ต์ข
์ ํ๋ ๊ฒฐ๊ณผ์ YAML footer์๋ SKILL.md 6๋จ๊ณ ๊ท์น๊ณผ ๋์ผํ๊ฒ tone ๋ฉํ๋ฐ์ดํฐ๊ฐ ํฌํจ๋๋ค.
|
package/docs/internal/HARNESS.md
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# Harness Notes
|
|
2
|
-
|
|
3
|
-
Status: internal maintainer note. This is not public installation guidance.
|
|
4
|
-
|
|
5
|
-
## Current stance
|
|
6
|
-
|
|
7
|
-
- Patina is primarily a Markdown skill plus a Node.js CLI.
|
|
8
|
-
- Use specification-first review for changes that touch pattern definitions, scoring logic, or meaning-preservation behavior.
|
|
9
|
-
- Keep the core skill pipeline stable unless the change explicitly targets pipeline behavior.
|
|
10
|
-
- For docs-only waves, prefer `docs-review` evidence and the standard npm verification gates.
|
|
11
|
-
|
|
12
|
-
## Historical context
|
|
13
|
-
|
|
14
|
-
Older agent notes referenced an OMC/Ouroboros harness as the primary working lane. The current workspace uses the repo's active Codex/OMX runtime instructions from `AGENTS.md` and the bootstrap files instead. Treat older harness-specific routing as historical unless it is reintroduced in active automation.
|