@n2world/orchestrator 1.1.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 (154) hide show
  1. package/dist/agent-os-rd.d.ts +100 -0
  2. package/dist/agent-os-rd.js +258 -0
  3. package/dist/audit-store.d.ts +14 -0
  4. package/dist/audit-store.js +107 -0
  5. package/dist/beta-runner.d.ts +95 -0
  6. package/dist/beta-runner.js +251 -0
  7. package/dist/beta.d.ts +102 -0
  8. package/dist/beta.js +180 -0
  9. package/dist/browser-agent.d.ts +90 -0
  10. package/dist/browser-agent.js +223 -0
  11. package/dist/channel-gateway.d.ts +74 -0
  12. package/dist/channel-gateway.js +270 -0
  13. package/dist/channels.d.ts +120 -0
  14. package/dist/channels.js +432 -0
  15. package/dist/chat-store.d.ts +29 -0
  16. package/dist/chat-store.js +120 -0
  17. package/dist/cli.d.ts +2 -0
  18. package/dist/cli.js +607 -0
  19. package/dist/command-screen.d.ts +12 -0
  20. package/dist/command-screen.js +44 -0
  21. package/dist/commit-gate.d.ts +98 -0
  22. package/dist/commit-gate.js +258 -0
  23. package/dist/companion-api.d.ts +37 -0
  24. package/dist/companion-api.js +101 -0
  25. package/dist/conversation-graph.d.ts +39 -0
  26. package/dist/conversation-graph.js +92 -0
  27. package/dist/cost-estimator.d.ts +27 -0
  28. package/dist/cost-estimator.js +42 -0
  29. package/dist/cron-runner.d.ts +31 -0
  30. package/dist/cron-runner.js +46 -0
  31. package/dist/dashboard/chat.html +326 -0
  32. package/dist/dashboard/dental.html +58 -0
  33. package/dist/dashboard/freebie.png +0 -0
  34. package/dist/dashboard/icon-192.png +0 -0
  35. package/dist/dashboard/index.html +892 -0
  36. package/dist/dashboard/manifest.json +15 -0
  37. package/dist/dashboard/service-worker.js +28 -0
  38. package/dist/dashboard-server.d.ts +37 -0
  39. package/dist/dashboard-server.js +457 -0
  40. package/dist/dental-intake-service.d.ts +37 -0
  41. package/dist/dental-intake-service.js +61 -0
  42. package/dist/dental-metrics.d.ts +25 -0
  43. package/dist/dental-metrics.js +37 -0
  44. package/dist/docking.d.ts +36 -0
  45. package/dist/docking.js +73 -0
  46. package/dist/finance-mcts-candidate.d.ts +37 -0
  47. package/dist/finance-mcts-candidate.js +106 -0
  48. package/dist/finance-regulation-kr.d.ts +33 -0
  49. package/dist/finance-regulation-kr.js +104 -0
  50. package/dist/finance-workflow.d.ts +135 -0
  51. package/dist/finance-workflow.js +242 -0
  52. package/dist/gateway.d.ts +18 -0
  53. package/dist/gateway.js +123 -0
  54. package/dist/governance.d.ts +39 -0
  55. package/dist/governance.js +48 -0
  56. package/dist/governed-executor.d.ts +31 -0
  57. package/dist/governed-executor.js +63 -0
  58. package/dist/governed-llm.d.ts +41 -0
  59. package/dist/governed-llm.js +83 -0
  60. package/dist/gpu-bridge.d.ts +16 -0
  61. package/dist/gpu-bridge.js +53 -0
  62. package/dist/health.d.ts +47 -0
  63. package/dist/health.js +66 -0
  64. package/dist/identity-link.d.ts +32 -0
  65. package/dist/identity-link.js +98 -0
  66. package/dist/index.d.ts +184 -0
  67. package/dist/index.js +417 -0
  68. package/dist/integrations/emr-adapter.d.ts +41 -0
  69. package/dist/integrations/emr-adapter.js +63 -0
  70. package/dist/kakao-oauth.d.ts +16 -0
  71. package/dist/kakao-oauth.js +87 -0
  72. package/dist/knowledge-graph.d.ts +53 -0
  73. package/dist/knowledge-graph.js +156 -0
  74. package/dist/llm.d.ts +65 -0
  75. package/dist/llm.js +357 -0
  76. package/dist/mcp-client-guard.d.ts +32 -0
  77. package/dist/mcp-client-guard.js +179 -0
  78. package/dist/mcp-macaroon.d.ts +75 -0
  79. package/dist/mcp-macaroon.js +161 -0
  80. package/dist/mcts-kernel-bridge.d.ts +36 -0
  81. package/dist/mcts-kernel-bridge.js +99 -0
  82. package/dist/mcts-prior.d.ts +79 -0
  83. package/dist/mcts-prior.js +170 -0
  84. package/dist/model-router.d.ts +51 -0
  85. package/dist/model-router.js +75 -0
  86. package/dist/multi-axis-lift.d.ts +43 -0
  87. package/dist/multi-axis-lift.js +141 -0
  88. package/dist/net-guard.d.ts +39 -0
  89. package/dist/net-guard.js +141 -0
  90. package/dist/onboarding.d.ts +38 -0
  91. package/dist/onboarding.js +94 -0
  92. package/dist/oracle-anchored-search.d.ts +25 -0
  93. package/dist/oracle-anchored-search.js +50 -0
  94. package/dist/oracle.d.ts +22 -0
  95. package/dist/oracle.js +116 -0
  96. package/dist/p6-governance.d.ts +150 -0
  97. package/dist/p6-governance.js +252 -0
  98. package/dist/pairing.d.ts +22 -0
  99. package/dist/pairing.js +81 -0
  100. package/dist/personalization.d.ts +35 -0
  101. package/dist/personalization.js +73 -0
  102. package/dist/pglite-hnsw-bridge.d.ts +118 -0
  103. package/dist/pglite-hnsw-bridge.js +311 -0
  104. package/dist/pglite-store.d.ts +59 -0
  105. package/dist/pglite-store.js +180 -0
  106. package/dist/playbook.d.ts +79 -0
  107. package/dist/playbook.js +83 -0
  108. package/dist/playbooks/dental-intake.d.ts +20 -0
  109. package/dist/playbooks/dental-intake.js +112 -0
  110. package/dist/predictive-agent.d.ts +157 -0
  111. package/dist/predictive-agent.js +535 -0
  112. package/dist/prompt-optimizer.d.ts +18 -0
  113. package/dist/prompt-optimizer.js +104 -0
  114. package/dist/rate-limiter.d.ts +25 -0
  115. package/dist/rate-limiter.js +75 -0
  116. package/dist/safety-anneal.d.ts +83 -0
  117. package/dist/safety-anneal.js +153 -0
  118. package/dist/sandbox-controller.d.ts +12 -0
  119. package/dist/sandbox-controller.js +95 -0
  120. package/dist/satisfaction-metrics.d.ts +26 -0
  121. package/dist/satisfaction-metrics.js +61 -0
  122. package/dist/sensor-bridge.d.ts +53 -0
  123. package/dist/sensor-bridge.js +133 -0
  124. package/dist/session-repair.d.ts +27 -0
  125. package/dist/session-repair.js +66 -0
  126. package/dist/slack-finance-intake.d.ts +42 -0
  127. package/dist/slack-finance-intake.js +122 -0
  128. package/dist/symbolic-dynamics.d.ts +113 -0
  129. package/dist/symbolic-dynamics.js +420 -0
  130. package/dist/telemetry.d.ts +19 -0
  131. package/dist/telemetry.js +68 -0
  132. package/dist/text-embedding.d.ts +6 -0
  133. package/dist/text-embedding.js +42 -0
  134. package/dist/tier-classifier.d.ts +20 -0
  135. package/dist/tier-classifier.js +58 -0
  136. package/dist/tier-guard.d.ts +36 -0
  137. package/dist/tier-guard.js +56 -0
  138. package/dist/tui.d.ts +9 -0
  139. package/dist/tui.js +214 -0
  140. package/dist/update-security.d.ts +31 -0
  141. package/dist/update-security.js +112 -0
  142. package/dist/v-calibration.d.ts +16 -0
  143. package/dist/v-calibration.js +42 -0
  144. package/dist/value-calibration.d.ts +41 -0
  145. package/dist/value-calibration.js +133 -0
  146. package/dist/value-head.d.ts +20 -0
  147. package/dist/value-head.js +91 -0
  148. package/dist/wal-buffer.d.ts +23 -0
  149. package/dist/wal-buffer.js +144 -0
  150. package/dist/wiki-synthesizer.d.ts +80 -0
  151. package/dist/wiki-synthesizer.js +0 -0
  152. package/dist/worker-agent.d.ts +10 -0
  153. package/dist/worker-agent.js +19 -0
  154. package/package.json +65 -0
@@ -0,0 +1,535 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.PredictiveAgent = void 0;
37
+ exports.parseCandidates = parseCandidates;
38
+ exports.buildCandidatePrompt = buildCandidatePrompt;
39
+ exports.makeLlmCandidateGenerator = makeLlmCandidateGenerator;
40
+ exports.runPredictiveTask = runPredictiveTask;
41
+ const child_process_1 = require("child_process");
42
+ const fs = __importStar(require("fs/promises"));
43
+ const os = __importStar(require("os"));
44
+ const path = __importStar(require("path"));
45
+ const core_1 = require("@n2world/core");
46
+ const llm_1 = require("./llm");
47
+ const text_embedding_1 = require("./text-embedding");
48
+ const symbolic_dynamics_1 = require("./symbolic-dynamics");
49
+ function sh(cmd, cwd, timeout = 20000) {
50
+ return new Promise((resolve) => {
51
+ (0, child_process_1.exec)(cmd, { cwd, timeout }, (err, stdout, stderr) => {
52
+ resolve({ code: err ? (err.code ?? 1) : 0, stdout: (stdout || '').toString(), stderr: (stderr || '').toString() });
53
+ });
54
+ });
55
+ }
56
+ class PredictiveAgent {
57
+ workspaceDir;
58
+ testCommand;
59
+ dangerousPatterns;
60
+ /** 관련성 신호 모드: 'token'=토큰 집합 겹침(기본), 'embedding'=해시 임베딩 코사인(graded). */
61
+ relevanceMode;
62
+ /** 오라클(testCommand) 실행 타임아웃(ms). 무거운 실테스트 스위트 도메인에서 상향. */
63
+ oracleTimeoutMs;
64
+ /** 적응 게이팅 임계 θ: 오라클/필터 비용비 ≥ θ 일 때만 g_fast(§4g 크로스오버 ≈2.3×). */
65
+ autoThreshold;
66
+ /** 세션 비용 추정 캐시(calibrate 로 채움). auto 모드 게이팅 근거. */
67
+ costEstimate;
68
+ constructor(workspaceDir, testCommand, dangerousPatterns = ['rm -rf', 'rm -fr', 'mkfs', 'dd if=', ':(){', 'shutdown', 'reboot', 'format ', 'del /', 'rmdir /s'], opts = {}) {
69
+ this.workspaceDir = workspaceDir;
70
+ this.testCommand = testCommand;
71
+ this.dangerousPatterns = dangerousPatterns;
72
+ this.relevanceMode = opts.relevanceMode ?? 'token';
73
+ this.oracleTimeoutMs = opts.oracleTimeoutMs ?? 20000; // 오라클(testCommand) 타임아웃. 무거운 실테스트는 상향 필요.
74
+ this.autoThreshold = opts.autoThreshold ?? 2.3; // §4g 크로스오버 임계
75
+ }
76
+ /** g_fast 구문 타당성: JS 편집이면 `node --check`로 컴파일 가능성 추정(그리드월드 대체). */
77
+ async isInfeasibleEdit(c) {
78
+ if (c.kind !== 'edit' || !c.file)
79
+ return false;
80
+ if (!/\.(c?js|mjs)$/.test(c.file))
81
+ return false; // JS 외 파일은 이 단계 통과
82
+ const tmp = path.join(this.workspaceDir, `.gfast_${c.id}.js`);
83
+ await fs.writeFile(tmp, c.content ?? '', 'utf8');
84
+ const r = await sh(`node --check "${tmp}"`, this.workspaceDir);
85
+ await fs.rm(tmp, { force: true });
86
+ return r.code !== 0; // 구문 오류 → 비타당
87
+ }
88
+ /** 1단계 g_fast 게이트: 위험 명령 + 비타당 편집을 가지치기. */
89
+ async prune(candidates) {
90
+ const pruned = [];
91
+ const survivors = [];
92
+ for (const c of candidates) {
93
+ if (c.kind === 'command') {
94
+ // Rust prune_actions 재사용: 위험 패턴 포함 명령은 제거됨.
95
+ const kept = (0, core_1.pruneActions)([c.command ?? ''], this.dangerousPatterns);
96
+ if (kept.length === 0) {
97
+ pruned.push(c.id);
98
+ continue;
99
+ }
100
+ }
101
+ if (await this.isInfeasibleEdit(c)) {
102
+ pruned.push(c.id);
103
+ continue;
104
+ }
105
+ survivors.push(c);
106
+ }
107
+ return { survivors, pruned };
108
+ }
109
+ async applyTo(dir, c) {
110
+ if (c.kind === 'edit' && c.file) {
111
+ const fp = path.join(dir, c.file);
112
+ await fs.mkdir(path.dirname(fp), { recursive: true });
113
+ await fs.writeFile(fp, c.content ?? '', 'utf8');
114
+ return;
115
+ }
116
+ if (c.kind === 'command' && c.command) {
117
+ await sh(c.command, dir);
118
+ }
119
+ }
120
+ /** 2단계: 워크스페이스 복사본에 후보 적용 후 오라클(테스트) 실행 → 통과 여부. */
121
+ async simulateAndVerify(c) {
122
+ const scratch = await fs.mkdtemp(path.join(os.tmpdir(), 'n2w-sim-'));
123
+ try {
124
+ await fs.cp(this.workspaceDir, scratch, { recursive: true });
125
+ await this.applyTo(scratch, c);
126
+ const r = await sh(this.testCommand, scratch, this.oracleTimeoutMs);
127
+ return r.code === 0; // 오라클 통과 = 보상 1
128
+ }
129
+ finally {
130
+ await fs.rm(scratch, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); // Windows EBUSY(자식 프로세스 핸들) 재시도
131
+ }
132
+ }
133
+ /**
134
+ * 적응 게이팅 캘리브레이션 — 대표 후보 1개로 **오라클 단가**와 (워밍업 제외) **후보당 필터 단가**를
135
+ * 실측해 `ratio = oracleMs/filterMs` 를 캐시한다. `run({ gfast:'auto' })` 가 이 ratio 로 g_fast/baseline 을
136
+ * 자동 선택(§4g 크로스오버 임계 θ). 정직: 필터 단가는 amortize 후(2번째 필터) 후보당 비용을 반영한다.
137
+ * 편집·컴파일판정불가 표본이면 필터 측정 불가 → ratio 미설정(auto 는 보수적으로 baseline).
138
+ */
139
+ async calibrate(sample, opts = {}) {
140
+ const t0 = Date.now();
141
+ await this.simulateAndVerify(sample); // 오라클 1회(결과 무시, 단가만 측정)
142
+ const oracleMs = Date.now() - t0;
143
+ let filterMs;
144
+ const a = (0, symbolic_dynamics_1.candidateToEditAction)(sample);
145
+ if (a.kind === 'edit' && a.file && (0, symbolic_dynamics_1.isCompilerDecidableFile)(a.file) && typeof a.content === 'string') {
146
+ const checker = opts.sharedChecker ?? new symbolic_dynamics_1.WarmTypeChecker();
147
+ await checker.seedDirOnce(this.workspaceDir);
148
+ const fileName = path.join(this.workspaceDir, a.file);
149
+ checker.addedErrorsForEdit(fileName, a.content); // 워밍업(첫 필터 = 프로그램 빌드)
150
+ const tf = Date.now();
151
+ checker.addedErrorsForEdit(fileName, a.content); // 후보당 순 필터(2번째, amortize 후)
152
+ filterMs = Date.now() - tf;
153
+ }
154
+ const ratio = filterMs != null ? oracleMs / Math.max(filterMs, 1) : undefined;
155
+ this.costEstimate = ratio != null ? { oracleMs, filterMs: filterMs, ratio } : undefined;
156
+ return { oracleMs, filterMs, ratio };
157
+ }
158
+ /** 현재 워크스페이스에서 테스트(오라클)가 통과하는지. */
159
+ async oraclePasses() {
160
+ const r = await sh(this.testCommand, this.workspaceDir, this.oracleTimeoutMs);
161
+ return r.code === 0;
162
+ }
163
+ /**
164
+ * 오라클 "부분 점수"∈[0,1]: 테스트 출력의 `SCORE:x/y` 를 파싱(멀티파일 부분 진척용).
165
+ * 없으면 종료 코드로 1.0/0.0. 멀티스텝 탐색의 가치 신호.
166
+ */
167
+ async oracleScore(dir = this.workspaceDir) {
168
+ const r = await sh(this.testCommand, dir, this.oracleTimeoutMs);
169
+ const m = (r.stdout + r.stderr).match(/SCORE:\s*(\d+)\s*\/\s*(\d+)/);
170
+ if (m) {
171
+ const y = parseInt(m[2], 10);
172
+ return y > 0 ? Math.max(0, Math.min(1, parseInt(m[1], 10) / y)) : 0;
173
+ }
174
+ return r.code === 0 ? 1 : 0;
175
+ }
176
+ /** 후보를 복사본에 적용 후 오라클 부분 점수 측정(실제 워크스페이스 보존). */
177
+ async simulateScore(c) {
178
+ const scratch = await fs.mkdtemp(path.join(os.tmpdir(), 'n2w-msim-'));
179
+ try {
180
+ await fs.cp(this.workspaceDir, scratch, { recursive: true });
181
+ await this.applyTo(scratch, c);
182
+ return await this.oracleScore(scratch);
183
+ }
184
+ finally {
185
+ await fs.rm(scratch, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); // Windows EBUSY(자식 프로세스 핸들) 재시도
186
+ }
187
+ }
188
+ /**
189
+ * g_fast 가치 추정(오라클 없이, 값싸게). 후보의 "유망도"∈[0,1] — 목표/오류 컨텍스트와의
190
+ * 텍스트 관련성 + 종류 편향. 정직: 이는 정답성이 아니라 우선순위 신호다(진실은 오라클이 판정).
191
+ */
192
+ gfastValue(c, context) {
193
+ const candText = `${c.description} ${c.content ?? ''} ${c.command ?? ''}`;
194
+ let relevance;
195
+ if (this.relevanceMode === 'embedding') {
196
+ // 해시 임베딩 코사인(연속 관련성). 실 의미 임베딩 아님(정직).
197
+ relevance = (0, text_embedding_1.embeddingRelevance)(candText, context);
198
+ }
199
+ else {
200
+ // 토큰 집합 겹침(기본).
201
+ const tok = (s) => new Set((s || '').toLowerCase().split(/[^a-z0-9가-힣]+/).filter((t) => t.length > 1));
202
+ const ctx = tok(context);
203
+ if (ctx.size === 0)
204
+ return c.kind === 'edit' ? 0.05 : 0;
205
+ let overlap = 0;
206
+ const cand = tok(candText);
207
+ for (const t of cand)
208
+ if (ctx.has(t))
209
+ overlap++;
210
+ relevance = overlap / ctx.size;
211
+ }
212
+ const kindBias = c.kind === 'edit' ? 0.05 : 0; // 명령보다 편집을 약간 선호(안전)
213
+ return Math.min(1, relevance + kindBias);
214
+ }
215
+ /**
216
+ * G3 — g_fast 기호 경로 정렬: 컴파일러(ρ)로 후보를 사전 평가해
217
+ * (a) **비컴파일 후보를 오라클 전에 제외**(건전: 컴파일 실패 ⟹ 그 후보 임포트 테스트 실패),
218
+ * (b) 결정 불가(δ=0: 명령·비JS) 후보는 그대로 유지(오라클 위임),
219
+ * (c) 생존 후보를 ρ 내림차순 → gfastValue 순으로 정렬.
220
+ * 비싼 테스트 오라클 대신 값싼 컴파일만 추가로 돈다.
221
+ */
222
+ async gfastRank(survivors, goal) {
223
+ const scored = [];
224
+ for (const c of survivors) {
225
+ const a = (0, symbolic_dynamics_1.candidateToEditAction)(c);
226
+ let m0 = { targetFile: a.file ?? '', astErrors: [], buildStatus: 'unknown' };
227
+ if (a.kind === 'edit' && a.file) {
228
+ try {
229
+ m0 = await (0, symbolic_dynamics_1.recompileMeta)(this.workspaceDir, a.file);
230
+ }
231
+ catch { /* 미상 */ }
232
+ }
233
+ const e = await (0, symbolic_dynamics_1.gfastEvaluate)(this.workspaceDir, m0, a);
234
+ if (!e.decidable) {
235
+ scored.push({ c, decidable: false, compiles: true, rho: -Infinity });
236
+ continue;
237
+ }
238
+ const compiles = e.mNext?.buildStatus !== 'fail';
239
+ scored.push({ c, decidable: true, compiles, rho: e.rho ?? 0 });
240
+ }
241
+ // (a) 결정 가능 & 비컴파일 후보 제외(오라클 호출 절감, 건전).
242
+ const survivors2 = scored.filter((s) => !(s.decidable && !s.compiles));
243
+ // (c) 정렬: 결정 가능(ρ 높은) 먼저, 그다음 결정 불가(gfastValue), 동률은 gfastValue.
244
+ survivors2.sort((x, y) => {
245
+ if (x.decidable !== y.decidable)
246
+ return x.decidable ? -1 : 1;
247
+ if (x.decidable && y.decidable && x.rho !== y.rho)
248
+ return y.rho - x.rho;
249
+ return this.gfastValue(y.c, goal) - this.gfastValue(x.c, goal);
250
+ });
251
+ return survivors2.map((s) => s.c);
252
+ }
253
+ /**
254
+ * G3c — 웜(증분) g_fast 정렬: in-process TypeScript Language Service 로 후보 내용을
255
+ * *증분* 타입체크(프로세스 spawn·scratch 복사·콜드 시작 없음). 첫 후보만 프로그램 빌드(웜업).
256
+ * 비컴파일 후보를 오라클 전에 제외하고 ρ 로 정렬. 필터 비용을 콜드 tsc 대비 크게 낮춘다.
257
+ */
258
+ gfastRankWarm(survivors, goal, shared) {
259
+ const checker = shared ?? new symbolic_dynamics_1.WarmTypeChecker(); // 재사용 시 프로그램 빌드(웜업) amortize
260
+ const scored = [];
261
+ for (const c of survivors) {
262
+ const a = (0, symbolic_dynamics_1.candidateToEditAction)(c);
263
+ if (a.kind === 'edit' && a.file && (0, symbolic_dynamics_1.isCompilerDecidableFile)(a.file) && typeof a.content === 'string') {
264
+ const fileName = path.join(this.workspaceDir, a.file);
265
+ const m0 = { targetFile: fileName, astErrors: [], buildStatus: 'unknown' };
266
+ const mNext = (0, symbolic_dynamics_1.recompileMetaWarm)(checker, fileName, a.content);
267
+ scored.push({ c, decidable: true, compiles: mNext.buildStatus !== 'fail', rho: (0, symbolic_dynamics_1.ruleReward)(m0, mNext) });
268
+ }
269
+ else {
270
+ scored.push({ c, decidable: false, compiles: true, rho: -Infinity });
271
+ }
272
+ }
273
+ const survivors2 = scored.filter((s) => !(s.decidable && !s.compiles)); // 비컴파일 제외(건전)
274
+ survivors2.sort((x, y) => {
275
+ if (x.decidable !== y.decidable)
276
+ return x.decidable ? -1 : 1;
277
+ if (x.decidable && y.decidable && x.rho !== y.rho)
278
+ return y.rho - x.rho;
279
+ return this.gfastValue(y.c, goal) - this.gfastValue(x.c, goal);
280
+ });
281
+ return survivors2.map((s) => s.c);
282
+ }
283
+ /**
284
+ * G3d — 프로젝트-시드(교차파일) 웜 정렬. 워크스페이스 전체를 한 번 시드한 뒤, 각 후보 편집이
285
+ * *프로젝트에 새 타입오차를 도입하는지*(import한 다른 파일을 깨는 경우 포함) 증분 검사해 제외.
286
+ * 단일 파일 격리 체크(G3c)가 못 잡는 교차파일 오류를 잡는다. spawn 없음(in-process).
287
+ */
288
+ async gfastRankProject(survivors, goal, shared) {
289
+ const checker = shared ?? new symbolic_dynamics_1.WarmTypeChecker(); // 재사용 시 시드+빌드(웜업) amortize
290
+ await checker.seedDirOnce(this.workspaceDir); // 프로젝트 전체 시드(세션 1회; 재사용 checker면 최초만)
291
+ const scored = [];
292
+ for (const c of survivors) {
293
+ const a = (0, symbolic_dynamics_1.candidateToEditAction)(c);
294
+ if (a.kind === 'edit' && a.file && (0, symbolic_dynamics_1.isCompilerDecidableFile)(a.file) && typeof a.content === 'string') {
295
+ const fileName = path.join(this.workspaceDir, a.file);
296
+ const added = checker.addedErrorsForEdit(fileName, a.content); // 교차파일 포함 새 오차
297
+ const m0 = { targetFile: fileName, astErrors: [], buildStatus: 'unknown' };
298
+ const mNext = { targetFile: fileName, astErrors: added, buildStatus: added.length ? 'fail' : 'pass' };
299
+ scored.push({ c, decidable: true, compiles: added.length === 0, rho: (0, symbolic_dynamics_1.ruleReward)(m0, mNext) });
300
+ }
301
+ else {
302
+ scored.push({ c, decidable: false, compiles: true, rho: -Infinity });
303
+ }
304
+ }
305
+ const survivors2 = scored.filter((s) => !(s.decidable && !s.compiles)); // 프로젝트를 깨는 후보 제외
306
+ survivors2.sort((x, y) => {
307
+ if (x.decidable !== y.decidable)
308
+ return x.decidable ? -1 : 1;
309
+ if (x.decidable && y.decidable && x.rho !== y.rho)
310
+ return y.rho - x.rho;
311
+ return this.gfastValue(y.c, goal) - this.gfastValue(x.c, goal);
312
+ });
313
+ return survivors2.map((s) => s.c);
314
+ }
315
+ /**
316
+ * 예측 실행: 가지치기 → (가치순 정렬) → 복사본 오라클 검증을 유망 순서로 → 검증된 첫 수 커밋.
317
+ * 7-0b 게이팅: 값싼 g_fast로 순서를 정하고 비싼 오라클은 유망 순서로 호출, 첫 통과 시 조기 종료.
318
+ * opts.rank=false 면 랭킹 없이(원래 순서) 비교 측정 가능.
319
+ */
320
+ async run(candidates, opts = {}) {
321
+ const ranked = opts.rank !== false;
322
+ // 대책1(적응 게이팅): gfast:'auto' → 캘리브레이션된 비용비 ratio≥θ 일 때만 g_fast(project+shared), 아니면 baseline.
323
+ // 추정 없으면 보수적으로 baseline(회귀 0 우선). auto 는 항상 프로젝트(교차파일·최강) 경로를 쓴다.
324
+ const auto = opts.gfast === 'auto';
325
+ const autoGate = auto && (this.costEstimate?.ratio ?? 0) >= this.autoThreshold;
326
+ // G3: g_fast 기호 경로 opt-in. 기본 OFF(N2WORLD_GFAST=1 또는 opts.gfast=true 시 ON) → 회귀 0.
327
+ const gfastOn = autoGate || opts.gfast === true || opts.gfastWarm === true || opts.gfastProject === true || /^(1|true|on)$/i.test(process.env.N2WORLD_GFAST || '');
328
+ // G3c: 웜(증분) 타입체크 필터 — 콜드 tsc spawn 대신 in-process Language Service.
329
+ const warm = opts.gfastWarm === true || /^(1|true|on)$/i.test(process.env.N2WORLD_GFAST_WARM || '');
330
+ // G3d: 프로젝트-시드(교차파일) 웜 필터. auto 게이트가 켜지면 프로젝트 경로 강제.
331
+ const project = autoGate || opts.gfastProject === true || /^(1|true|on)$/i.test(process.env.N2WORLD_GFAST_PROJECT || '');
332
+ const { survivors, pruned } = await this.prune(candidates);
333
+ let ordered = survivors;
334
+ if (gfastOn) {
335
+ // g_fast: 프로젝트 웜(교차파일) > 단일파일 웜 > 콜드 tsc 순 우선.
336
+ ordered = project ? await this.gfastRankProject(survivors, opts.goal ?? '', opts.sharedChecker)
337
+ : warm ? this.gfastRankWarm(survivors, opts.goal ?? '', opts.sharedChecker)
338
+ : await this.gfastRank(survivors, opts.goal ?? '');
339
+ }
340
+ else if (ranked) {
341
+ const context = opts.goal ?? '';
342
+ ordered = survivors
343
+ .map((c) => ({ c, v: this.gfastValue(c, context) }))
344
+ .sort((a, b) => b.v - a.v) // 가치 높은 후보 먼저
345
+ .map((s) => s.c);
346
+ }
347
+ const simulated = [];
348
+ let verified = null;
349
+ let oracleCalls = 0;
350
+ for (const c of ordered) {
351
+ oracleCalls++; // 비싼 2단계(오라클) 1회
352
+ const pass = await this.simulateAndVerify(c);
353
+ simulated.push({ id: c.id, oraclePass: pass });
354
+ if (pass) {
355
+ verified = c;
356
+ break;
357
+ } // 검증된 첫 수 → 조기 종료(나머지 오라클 호출 생략)
358
+ }
359
+ const order = ordered.map((c) => c.id);
360
+ if (verified) {
361
+ await this.applyTo(this.workspaceDir, verified);
362
+ // C4: 커밋을 sharedChecker 에 동기화 → 같은 워크스페이스 다라운드서 checker↔디스크 정합(stale 오판 방지).
363
+ // edit 만(command 는 파일 변경 추적 불가). 증분(setFile) 이라 재빌드 amortize 유지.
364
+ if (opts.sharedChecker && verified.kind === 'edit' && verified.file && typeof verified.content === 'string') {
365
+ opts.sharedChecker.setFile(path.join(this.workspaceDir, verified.file), verified.content);
366
+ }
367
+ return { success: true, committed: verified, pruned, simulated, oracleCalls, order, ranked, gfastApplied: gfastOn };
368
+ }
369
+ return { success: false, committed: null, pruned, simulated, oracleCalls, order, ranked, gfastApplied: gfastOn };
370
+ }
371
+ /**
372
+ * 멀티스텝 예측 실행(멀티파일·다단계). 한 단계가 다른 단계의 실패를 드러내는 SWE형 과제용.
373
+ * 트리 탐색(베스트퍼스트): g_fast=사전확률로 후보를 정렬하고, 오라클 부분점수=가치로 평가해
374
+ * 점수를 가장 크게 올리는 "검증된 편집"만 커밋하며 모든 테스트 통과까지 진행한다.
375
+ * (정직: 풀 확률적 MCTS 롤아웃이 아니라 g_fast 사전확률+오라클 가치의 베스트퍼스트 트리 탐색.)
376
+ */
377
+ async solveMultiStep(generate, goal, opts = {}) {
378
+ const maxSteps = opts.maxSteps ?? 8;
379
+ const steps = [];
380
+ const prunedAll = [];
381
+ let oracleCalls = 0;
382
+ let current = await this.oracleScore();
383
+ for (let step = 0; step < maxSteps && current < 1; step++) {
384
+ const ctx = await sh(this.testCommand, this.workspaceDir, this.oracleTimeoutMs);
385
+ const candidates = await generate(this.workspaceDir, goal, ctx.stdout + ctx.stderr);
386
+ const { survivors, pruned } = await this.prune(candidates);
387
+ prunedAll.push(...pruned);
388
+ // g_fast 사전확률로 후보 순서 결정(유망 순서 먼저 검증 → 비싼 오라클 절감).
389
+ const ranked = survivors
390
+ .map((c) => ({ c, v: this.gfastValue(c, goal) }))
391
+ .sort((a, b) => b.v - a.v)
392
+ .map((s) => s.c);
393
+ // 각 후보를 복사본에서 오라클 부분점수로 평가. 가장 크게 개선하는 검증된 편집을 채택.
394
+ let best = null;
395
+ let bestScore = current;
396
+ for (const c of ranked) {
397
+ oracleCalls++;
398
+ const score = await this.simulateScore(c);
399
+ if (score > bestScore) {
400
+ best = c;
401
+ bestScore = score;
402
+ if (score >= 1)
403
+ break;
404
+ } // 만점이면 조기 종료
405
+ }
406
+ if (!best)
407
+ break; // 개선 후보 없음 → 정직하게 중단(거짓 커밋 없음)
408
+ await this.applyTo(this.workspaceDir, best); // 검증된 개선 편집만 실제 워크스페이스에 커밋
409
+ steps.push({ committed: best.id, scoreBefore: +current.toFixed(3), scoreAfter: +bestScore.toFixed(3) });
410
+ current = bestScore;
411
+ }
412
+ return { success: current >= 1, finalScore: +current.toFixed(3), steps, pruned: prunedAll, oracleCalls };
413
+ }
414
+ }
415
+ exports.PredictiveAgent = PredictiveAgent;
416
+ // ---- LLM 후보 생성기 (생산 경로) — I/O와 파싱을 분리해 파싱은 순수·테스트 가능 ----
417
+ /** LLM 출력에서 균형 잡힌 첫 JSON 객체/배열 substring 추출(코드펜스·잡설 견딤). */
418
+ function extractJson(text) {
419
+ const fence = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
420
+ const body = fence ? fence[1] : text;
421
+ const start = body.search(/[\[{]/);
422
+ if (start < 0)
423
+ return null;
424
+ const open = body[start];
425
+ const close = open === '{' ? '}' : ']';
426
+ let depth = 0;
427
+ let inStr = false;
428
+ let esc = false;
429
+ for (let i = start; i < body.length; i++) {
430
+ const ch = body[i];
431
+ if (inStr) {
432
+ if (esc)
433
+ esc = false;
434
+ else if (ch === '\\')
435
+ esc = true;
436
+ else if (ch === '"')
437
+ inStr = false;
438
+ continue;
439
+ }
440
+ if (ch === '"')
441
+ inStr = true;
442
+ else if (ch === open)
443
+ depth++;
444
+ else if (ch === close) {
445
+ depth--;
446
+ if (depth === 0)
447
+ return body.slice(start, i + 1);
448
+ }
449
+ }
450
+ return null;
451
+ }
452
+ /**
453
+ * LLM 출력 → 구조화 후보. 잡설/코드펜스를 견디고, 유효하지 않은 항목은 버린다(정직).
454
+ * 형식: {"candidates":[{id,description,kind,file,content|command}]} 또는 후보 배열.
455
+ */
456
+ function parseCandidates(llmOutput, defaultFile) {
457
+ const json = extractJson(llmOutput);
458
+ if (!json)
459
+ return [];
460
+ let parsed;
461
+ try {
462
+ parsed = JSON.parse(json);
463
+ }
464
+ catch {
465
+ return [];
466
+ }
467
+ const arr = Array.isArray(parsed) ? parsed : Array.isArray(parsed?.candidates) ? parsed.candidates : [];
468
+ const out = [];
469
+ for (let i = 0; i < arr.length; i++) {
470
+ const c = arr[i];
471
+ if (!c || typeof c !== 'object')
472
+ continue;
473
+ const kind = c.kind === 'command' ? 'command' : c.kind === 'edit' ? 'edit' : null;
474
+ if (!kind)
475
+ continue;
476
+ const id = typeof c.id === 'string' && c.id ? c.id : `cand${i}`;
477
+ if (kind === 'edit') {
478
+ const file = (typeof c.file === 'string' && c.file) ? c.file : defaultFile;
479
+ if (!file || typeof c.content !== 'string')
480
+ continue;
481
+ out.push({ id, description: String(c.description ?? ''), kind, file, content: c.content });
482
+ }
483
+ else {
484
+ if (typeof c.command !== 'string' || !c.command)
485
+ continue;
486
+ out.push({ id, description: String(c.description ?? ''), kind, command: c.command });
487
+ }
488
+ }
489
+ return out;
490
+ }
491
+ function buildCandidatePrompt(goal, targetFile, fileContent, testOutput, n) {
492
+ return [
493
+ `목표: ${goal}`,
494
+ `수정 대상 파일: ${targetFile}`,
495
+ `현재 파일 내용:\n\`\`\`\n${fileContent}\n\`\`\``,
496
+ `실패한 테스트 출력:\n\`\`\`\n${testOutput.slice(0, 2000)}\n\`\`\``,
497
+ `위 목표를 달성할 서로 다른 수정 후보 ${n}개를 제안하라.`,
498
+ `반드시 아래 JSON만 출력(설명 금지). content 는 파일 전체 내용:`,
499
+ `{"candidates":[{"id":"fix1","description":"...","kind":"edit","file":"${targetFile}","content":"<파일 전체 내용>"}]}`,
500
+ ].join('\n\n');
501
+ }
502
+ /**
503
+ * LLM 기반 후보 생성기(생산 경로). 파일·테스트출력을 모아 프롬프트를 만들고 LLM 호출 후 파싱.
504
+ * `complete` 주입으로 LLM 없이도(모의) 전체 경로를 결정적으로 검증할 수 있다.
505
+ */
506
+ function makeLlmCandidateGenerator(opts) {
507
+ const complete = opts.complete ?? llm_1.llmComplete;
508
+ const n = opts.numCandidates ?? 3;
509
+ return async (workspaceDir, goal) => {
510
+ let fileContent = '';
511
+ try {
512
+ fileContent = await fs.readFile(path.join(workspaceDir, opts.targetFile), 'utf8');
513
+ }
514
+ catch { /* 새 파일 */ }
515
+ const testOut = await sh(opts.testCommand, workspaceDir);
516
+ const prompt = buildCandidatePrompt(goal, opts.targetFile, fileContent, testOut.stdout + testOut.stderr, n);
517
+ let raw = '';
518
+ try {
519
+ raw = await complete(prompt);
520
+ }
521
+ catch {
522
+ return [];
523
+ } // 키 없음/오류 → 빈 후보(정직)
524
+ return parseCandidates(raw, opts.targetFile);
525
+ };
526
+ }
527
+ /**
528
+ * Stage A 오케스트레이션: 후보 생성 → 예측 실행(가지치기→검증→검증된 첫 수 커밋).
529
+ * 후보 생성기를 주입받으므로 LLM/결정적 어느 쪽이든 동일 경로를 탄다.
530
+ */
531
+ async function runPredictiveTask(workspaceDir, goal, testCommand, generate, dangerousPatterns) {
532
+ const candidates = await generate(workspaceDir, goal);
533
+ const agent = new PredictiveAgent(workspaceDir, testCommand, dangerousPatterns);
534
+ return agent.run(candidates);
535
+ }
@@ -0,0 +1,18 @@
1
+ export interface PromptCandidate {
2
+ prompt: string;
3
+ score: number;
4
+ }
5
+ export declare class PromptOptimizer {
6
+ private candidates;
7
+ constructor(initialPrompt: string);
8
+ getCandidates(): PromptCandidate[];
9
+ mutate(prompt: string): string;
10
+ optimize(evaluator: (prompt: string) => Promise<number>, generations?: number, populationSize?: number): Promise<PromptCandidate>;
11
+ }
12
+ export declare class LlmInTheLoopPromptOptimizer {
13
+ private candidates;
14
+ constructor(initialPrompt: string);
15
+ getCandidates(): PromptCandidate[];
16
+ mutateWithFeedback(prompt: string, log: string): string;
17
+ optimize(evaluator: (prompt: string) => Promise<number>, executionLogs: string[], generations?: number, populationSize?: number): Promise<PromptCandidate>;
18
+ }
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ // ============================================================================
3
+ // 프롬프트 최적화 — 정직 고지(제1계명)
4
+ // ----------------------------------------------------------------------------
5
+ // 이것은 **DSPy/GEPA가 아니다.** 하드코딩된 변형 규칙(문자열 추가/치환)으로 후보를 만들고
6
+ // evaluator로 점수를 매겨 상위를 고르는 **간단한 휴리스틱 진화(hill-climbing) 최적화**다.
7
+ // 설계 문서가 언급한 "DSPy/GEPA 연동"은 미구현이며, 본 모듈을 DSPy라고 표기하지 않는다.
8
+ // 실제 동작(변형→평가→선택)은 진짜이며 테스트로 검증된다.
9
+ // ============================================================================
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.LlmInTheLoopPromptOptimizer = exports.PromptOptimizer = void 0;
12
+ class PromptOptimizer {
13
+ candidates = [];
14
+ constructor(initialPrompt) {
15
+ this.candidates.push({ prompt: initialPrompt, score: 0 });
16
+ }
17
+ getCandidates() {
18
+ return this.candidates;
19
+ }
20
+ mutate(prompt) {
21
+ const mutations = [
22
+ (p) => p + "\nConstraint: Be extremely precise and output only valid JSON.",
23
+ (p) => p + "\nInstruction: Do not write hardcoded mock return statements.",
24
+ (p) => p.replace(/extremely/g, 'ultraly'),
25
+ (p) => p + "\nNote: Focus on performance and maintainability.",
26
+ (p) => p.replace(/\s+/g, ' ')
27
+ ];
28
+ const randomMutation = mutations[Math.floor(Math.random() * mutations.length)];
29
+ return randomMutation(prompt);
30
+ }
31
+ async optimize(evaluator, generations = 3, populationSize = 4) {
32
+ for (let gen = 0; gen < generations; gen++) {
33
+ const newCandidates = [];
34
+ this.candidates.sort((a, b) => b.score - a.score);
35
+ const parents = this.candidates.slice(0, Math.max(1, Math.floor(populationSize / 2)));
36
+ for (const parent of parents) {
37
+ if (newCandidates.length < populationSize) {
38
+ newCandidates.push(parent);
39
+ }
40
+ while (newCandidates.length < populationSize) {
41
+ const mutatedText = this.mutate(parent.prompt);
42
+ newCandidates.push({ prompt: mutatedText, score: 0 });
43
+ }
44
+ }
45
+ for (const candidate of newCandidates) {
46
+ if (candidate.score === 0) {
47
+ candidate.score = await evaluator(candidate.prompt);
48
+ }
49
+ }
50
+ this.candidates = newCandidates;
51
+ }
52
+ this.candidates.sort((a, b) => b.score - a.score);
53
+ return this.candidates[0];
54
+ }
55
+ }
56
+ exports.PromptOptimizer = PromptOptimizer;
57
+ class LlmInTheLoopPromptOptimizer {
58
+ candidates = [];
59
+ constructor(initialPrompt) {
60
+ this.candidates.push({ prompt: initialPrompt, score: 0 });
61
+ }
62
+ getCandidates() {
63
+ return this.candidates;
64
+ }
65
+ mutateWithFeedback(prompt, log) {
66
+ let feedback = '';
67
+ if (log.toLowerCase().includes('json')) {
68
+ feedback = '\n[LLM Feedback] Ensure output is strict valid JSON structure, matching the schema exactly.';
69
+ }
70
+ else if (log.toLowerCase().includes('cheat') || log.toLowerCase().includes('hardcoded')) {
71
+ feedback = '\n[LLM Feedback] Do not output hardcoded conditional check outputs; execute actual logic.';
72
+ }
73
+ else {
74
+ feedback = `\n[LLM Feedback] Address log error: "${log}" by increasing robustness constraints.`;
75
+ }
76
+ return prompt + feedback;
77
+ }
78
+ async optimize(evaluator, executionLogs, generations = 3, populationSize = 4) {
79
+ for (let gen = 0; gen < generations; gen++) {
80
+ const newCandidates = [];
81
+ this.candidates.sort((a, b) => b.score - a.score);
82
+ const parents = this.candidates.slice(0, Math.max(1, Math.floor(populationSize / 2)));
83
+ for (const parent of parents) {
84
+ if (newCandidates.length < populationSize) {
85
+ newCandidates.push(parent);
86
+ }
87
+ while (newCandidates.length < populationSize) {
88
+ const log = executionLogs[Math.floor(Math.random() * executionLogs.length)] || '';
89
+ const mutatedText = this.mutateWithFeedback(parent.prompt, log);
90
+ newCandidates.push({ prompt: mutatedText, score: 0 });
91
+ }
92
+ }
93
+ for (const candidate of newCandidates) {
94
+ if (candidate.score === 0) {
95
+ candidate.score = await evaluator(candidate.prompt);
96
+ }
97
+ }
98
+ this.candidates = newCandidates;
99
+ }
100
+ this.candidates.sort((a, b) => b.score - a.score);
101
+ return this.candidates[0];
102
+ }
103
+ }
104
+ exports.LlmInTheLoopPromptOptimizer = LlmInTheLoopPromptOptimizer;