@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
package/dist/index.js ADDED
@@ -0,0 +1,417 @@
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
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
36
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.kakaoOAuth = exports.DEFAULT_CHAT_HISTORY_PATH = exports.ChatStore = exports.activeLlmInfo = exports.llmCompleteUsage = exports.llmComplete = exports.askAgentChat = exports.askAgent = exports.EbpfMapScheduler = exports.pruneActions = exports.MctsEngine = exports.SkillManager = exports.FirecrackerSandbox = exports.LocalSandbox = exports.DEFAULT_SECURITY_POLICY = void 0;
40
+ exports.detectFirecracker = detectFirecracker;
41
+ exports.createSandbox = createSandbox;
42
+ exports.greetCore = greetCore;
43
+ exports.writeMetaTuple = writeMetaTuple;
44
+ exports.getMetaTuple = getMetaTuple;
45
+ const core_1 = require("@n2world/core");
46
+ Object.defineProperty(exports, "MctsEngine", { enumerable: true, get: function () { return core_1.MctsEngine; } });
47
+ Object.defineProperty(exports, "pruneActions", { enumerable: true, get: function () { return core_1.pruneActions; } });
48
+ Object.defineProperty(exports, "EbpfMapScheduler", { enumerable: true, get: function () { return core_1.EbpfMapScheduler; } });
49
+ const child_process_1 = require("child_process");
50
+ const fs = __importStar(require("fs/promises"));
51
+ const fssync = __importStar(require("fs"));
52
+ const path = __importStar(require("path"));
53
+ const os = __importStar(require("os"));
54
+ const knowledge_graph_1 = require("./knowledge-graph");
55
+ const command_screen_1 = require("./command-screen");
56
+ exports.DEFAULT_SECURITY_POLICY = {
57
+ deniedCommandPatterns: [
58
+ 'rm -rf /', 'rm -rf ~', 'rm -rf .', ':(){', 'mkfs', 'dd if=', '> /dev/sd',
59
+ 'shutdown', 'reboot', 'chmod -R 777 /', 'chown -R', 'del /f /s /q', 'format ',
60
+ ],
61
+ riskyCommandPatterns: [
62
+ 'rm -rf', 'rm -fr', 'sudo ', 'git push', 'npm publish', 'curl ', 'wget ', 'ssh ', 'scp ',
63
+ ],
64
+ };
65
+ class LocalSandbox {
66
+ policy;
67
+ tempDir = '';
68
+ constructor(policy = exports.DEFAULT_SECURITY_POLICY) {
69
+ this.policy = policy;
70
+ }
71
+ async init() {
72
+ this.tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'n2world-sandbox-'));
73
+ }
74
+ /** 명령 보안 점검: 차단/위험(승인)/허용. */
75
+ async checkCommand(cmd) {
76
+ // H1 — 위험명령 스크린(전 경로 공통, regex denylist). 파괴적/되돌릴 수 없는 패턴은 무조건 차단.
77
+ const screen = (0, command_screen_1.screenDangerousCommand)(cmd);
78
+ if (screen.flagged) {
79
+ return { allowed: false, reason: `위험명령 스크린 차단: ${screen.matched.join(', ')}` };
80
+ }
81
+ for (const p of this.policy.deniedCommandPatterns) {
82
+ if (cmd.includes(p))
83
+ return { allowed: false, reason: `denied pattern: "${p}"` };
84
+ }
85
+ for (const p of this.policy.riskyCommandPatterns) {
86
+ if (cmd.includes(p)) {
87
+ if (this.policy.approve) {
88
+ const ok = await this.policy.approve({ kind: 'command', detail: cmd });
89
+ return { allowed: ok, reason: ok ? 'approved' : 'rejected by approver' };
90
+ }
91
+ return { allowed: false, reason: `risky pattern needs approval: "${p}"` };
92
+ }
93
+ }
94
+ return { allowed: true, reason: 'ok' };
95
+ }
96
+ /** 경로 탈출 차단: tempDir 밖으로 나가는 경로를 거부. */
97
+ safePath(filePath) {
98
+ const root = path.resolve(this.tempDir);
99
+ const full = path.resolve(this.tempDir, filePath);
100
+ if (full !== root && !full.startsWith(root + path.sep)) {
101
+ throw new Error(`[security] 경로 탈출 차단: "${filePath}"`);
102
+ }
103
+ return full;
104
+ }
105
+ async runCommand(command) {
106
+ const check = await this.checkCommand(command);
107
+ if (!check.allowed) {
108
+ return { stdout: '', stderr: `[security] 명령 차단됨 — ${check.reason}`, code: 126 };
109
+ }
110
+ const isWindows = process.platform === 'win32';
111
+ const finalCommand = isWindows
112
+ ? `chcp 65001 >nul && ${command}`
113
+ : command;
114
+ return new Promise((resolve) => {
115
+ (0, child_process_1.exec)(finalCommand, { cwd: this.tempDir }, (err, stdout, stderr) => {
116
+ resolve({
117
+ stdout,
118
+ stderr,
119
+ code: err ? err.code || 1 : 0
120
+ });
121
+ });
122
+ });
123
+ }
124
+ async writeFile(filePath, content) {
125
+ const fullPath = this.safePath(filePath);
126
+ await fs.mkdir(path.dirname(fullPath), { recursive: true });
127
+ await fs.writeFile(fullPath, content, 'utf8');
128
+ }
129
+ async readFile(filePath) {
130
+ const fullPath = this.safePath(filePath);
131
+ return await fs.readFile(fullPath, 'utf8');
132
+ }
133
+ async destroy() {
134
+ if (this.tempDir) {
135
+ await fs.rm(this.tempDir, { recursive: true, force: true });
136
+ }
137
+ }
138
+ }
139
+ exports.LocalSandbox = LocalSandbox;
140
+ /** Firecracker microVM 부팅 가능성을 실제로 탐지한다(거짓 주장 금지). */
141
+ function detectFirecracker() {
142
+ if (process.platform !== 'linux') {
143
+ return { kvmPresent: false, kvmWritable: false, firecracker: false, ready: false, reason: '비-Linux(microVM 미지원, 폴백 사용)' };
144
+ }
145
+ const kvmPresent = fssync.existsSync('/dev/kvm');
146
+ let kvmWritable = false;
147
+ try {
148
+ fssync.accessSync('/dev/kvm', fssync.constants.R_OK | fssync.constants.W_OK);
149
+ kvmWritable = true;
150
+ }
151
+ catch { /* 권한 없음 */ }
152
+ let firecracker = false;
153
+ for (const p of (process.env.PATH || '').split(path.delimiter)) {
154
+ try {
155
+ if (p && fssync.existsSync(path.join(p, 'firecracker'))) {
156
+ firecracker = true;
157
+ break;
158
+ }
159
+ }
160
+ catch { /* skip */ }
161
+ }
162
+ const ready = kvmPresent && kvmWritable && firecracker;
163
+ const reason = !kvmPresent ? '/dev/kvm 없음'
164
+ : !kvmWritable ? '/dev/kvm 접근 불가(kvm 그룹/ACL 필요)'
165
+ : !firecracker ? 'firecracker 바이너리 없음'
166
+ : 'ready';
167
+ return { kvmPresent, kvmWritable, firecracker, ready, reason };
168
+ }
169
+ /**
170
+ * Firecracker microVM 샌드박스(ISandbox). 부팅 전제(KVM 접근·firecracker·커널/rootfs 이미지)가
171
+ * 갖춰져야 한다. 미충족 시 init()이 명확한 사유로 throw → createSandbox()가 폴백을 선택한다.
172
+ * (거짓 부팅을 흉내내지 않는다.)
173
+ */
174
+ class FirecrackerSandbox {
175
+ kernelImage;
176
+ rootfsImage;
177
+ status = detectFirecracker();
178
+ constructor(kernelImage, rootfsImage) {
179
+ this.kernelImage = kernelImage;
180
+ this.rootfsImage = rootfsImage;
181
+ }
182
+ async init() {
183
+ if (!this.status.ready) {
184
+ throw new Error(`FirecrackerSandbox 사용 불가: ${this.status.reason}. (해결: sudo usermod -aG kvm $USER + 커널/rootfs 이미지)`);
185
+ }
186
+ if (!this.kernelImage || !this.rootfsImage) {
187
+ throw new Error('FirecrackerSandbox: 커널 이미지와 rootfs 경로가 필요합니다.');
188
+ }
189
+ // 실제 microVM 생성은 여기서 firecracker API 소켓으로 수행(이미지 준비 시).
190
+ throw new Error('FirecrackerSandbox 부팅은 커널/rootfs 이미지 준비 후 활성화됩니다(미구성).');
191
+ }
192
+ async runCommand() {
193
+ throw new Error('FirecrackerSandbox 미초기화');
194
+ }
195
+ async writeFile() { throw new Error('FirecrackerSandbox 미초기화'); }
196
+ async readFile() { throw new Error('FirecrackerSandbox 미초기화'); }
197
+ async destroy() { }
198
+ }
199
+ exports.FirecrackerSandbox = FirecrackerSandbox;
200
+ /**
201
+ * P4 폴백 팩토리: microVM 부팅 가능하면 Firecracker, 아니면 LocalSandbox(유저스페이스 격리).
202
+ * "거짓 폴백 금지" — 실제로 동작하는 샌드박스를 반환한다.
203
+ */
204
+ async function createSandbox(opts) {
205
+ const status = detectFirecracker();
206
+ if (status.ready && opts?.kernelImage && opts?.rootfsImage) {
207
+ try {
208
+ const fc = new FirecrackerSandbox(opts.kernelImage, opts.rootfsImage);
209
+ await fc.init();
210
+ return { sandbox: fc, backend: 'firecracker', reason: 'ready' };
211
+ }
212
+ catch { /* 폴백 */ }
213
+ }
214
+ const local = new LocalSandbox();
215
+ await local.init();
216
+ return { sandbox: local, backend: 'local', reason: status.reason };
217
+ }
218
+ function greetCore(name) {
219
+ return (0, core_1.helloWorld)(name);
220
+ }
221
+ function writeMetaTuple(buffer, tuple) {
222
+ const jsonStr = JSON.stringify(tuple);
223
+ const encoder = new TextEncoder();
224
+ const payloadBytes = encoder.encode(jsonStr);
225
+ if (payloadBytes.length > 1012) {
226
+ throw new Error('Payload too large for metadata slot');
227
+ }
228
+ const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
229
+ // Write payload length at offset 8 (little endian)
230
+ view.setUint32(8, payloadBytes.length, true);
231
+ // Write payload bytes starting at offset 12
232
+ buffer.set(payloadBytes, 12);
233
+ }
234
+ function getMetaTuple(buffer) {
235
+ const jsonStr = (0, core_1.readMetaTuple)(buffer);
236
+ return JSON.parse(jsonStr);
237
+ }
238
+ class SkillManager {
239
+ skills = [];
240
+ skillsDir = '';
241
+ hnsw;
242
+ // P1: 옵셔널 영속 벡터 저장(부착 시에만 사용). 미부착 시 기존 동작 그대로(하위 호환).
243
+ vectorStore;
244
+ constructor(skillsDir) {
245
+ this.skillsDir = skillsDir;
246
+ this.hnsw = new core_1.HnswIndex();
247
+ }
248
+ /**
249
+ * P1: PGLite 영속 벡터 저장을 부착한다(선택). 부착하면 createSkill/loadSkills 시
250
+ * 임베딩이 영속화되고 `searchPersistent`/`persistedStaleWindowMs` 를 쓸 수 있다.
251
+ * 부착하지 않으면 기존 인메모리 HNSW 경로만 사용한다(공개 API 불변).
252
+ */
253
+ attachVectorStore(store) {
254
+ this.vectorStore = store;
255
+ }
256
+ async init() {
257
+ await fs.mkdir(this.skillsDir, { recursive: true });
258
+ await this.loadSkills();
259
+ }
260
+ async loadSkills() {
261
+ try {
262
+ const files = await fs.readdir(this.skillsDir);
263
+ this.skills = [];
264
+ this.hnsw = new core_1.HnswIndex();
265
+ for (const file of files) {
266
+ if (file.endsWith('.md')) {
267
+ const filePath = path.join(this.skillsDir, file);
268
+ const content = await fs.readFile(filePath, 'utf8');
269
+ const embedding = this.generateMockEmbedding(content);
270
+ this.skills.push({ filePath, content, embedding });
271
+ this.hnsw.addItem(filePath, embedding);
272
+ if (this.vectorStore)
273
+ await this.vectorStore.upsert(filePath, content, embedding);
274
+ }
275
+ }
276
+ }
277
+ catch (err) {
278
+ // ignore if folder doesn't exist yet
279
+ }
280
+ }
281
+ async createSkill(fileName, content) {
282
+ const filePath = path.join(this.skillsDir, fileName);
283
+ await fs.writeFile(filePath, content, 'utf8');
284
+ const embedding = this.generateMockEmbedding(content);
285
+ this.skills.push({ filePath, content, embedding });
286
+ this.hnsw.addItem(filePath, embedding);
287
+ if (this.vectorStore)
288
+ await this.vectorStore.upsert(filePath, content, embedding);
289
+ }
290
+ /**
291
+ * P1: 영속 저장(PGLite) 경로의 코사인 검색. vectorStore 부착 시에만 동작.
292
+ * 기존 routeSkill(SAB+HNSW)과 별개의 추가 경로다(하위 호환 — 기존 경로 불변).
293
+ */
294
+ async searchPersistent(query, k = 2) {
295
+ if (!this.vectorStore)
296
+ throw new Error('vectorStore 미부착: attachVectorStore() 를 먼저 호출하라');
297
+ return this.vectorStore.search(this.generateMockEmbedding(query), k);
298
+ }
299
+ /** P1: 영속 저장의 경계-staleness 측정값(ms). 미부착 시 null. */
300
+ persistedStaleWindowMs() {
301
+ return this.vectorStore ? this.vectorStore.staleWindowMs() : null;
302
+ }
303
+ /**
304
+ * P2: 적재된 스킬(.md) 항목 간 자가연결 지식 그래프를 만든다(참조·의존·유사).
305
+ * 라우팅/검색을 보조하는 추가 경로 — 기존 공개 API 불변(하위 호환).
306
+ * 항목 id 는 파일 basename 을 쓴다.
307
+ */
308
+ buildKnowledgeGraph(opts) {
309
+ const items = this.skills.map((s) => ({
310
+ id: path.basename(s.filePath),
311
+ content: s.content,
312
+ }));
313
+ return (0, knowledge_graph_1.parseKnowledgeGraph)(items, opts);
314
+ }
315
+ /**
316
+ * 7-2: 외부(제3자) 스킬 수용은 반드시 A2A 신뢰 게이트를 통과해야 한다.
317
+ * 서명+Macaroon 범위(HARD_GATE)와 평판으로 t를 산출하고, 통과한 스킬만 라우팅/색인한다.
318
+ * 가치 v가 아니라 신뢰 t로 게이팅한다(고가치·저신뢰 스킬은 차단).
319
+ */
320
+ async ingestExternalSkill(peerId, fileName, content, macaroonToken, ctx, gate) {
321
+ const r = gate.evaluate(peerId, macaroonToken, ctx);
322
+ if (!r.allowed) {
323
+ return { accepted: false, reason: r.reason, trust: r.trust };
324
+ }
325
+ await this.createSkill(fileName, content);
326
+ gate.ledgerRef().recordSuccess(peerId);
327
+ return { accepted: true, reason: 'routed', trust: r.trust };
328
+ }
329
+ skillCount() {
330
+ return this.skills.length;
331
+ }
332
+ generateMockEmbedding(content) {
333
+ const words = content.toLowerCase().split(/[^a-z0-9]+/);
334
+ const embedding = new Array(128).fill(0);
335
+ for (const word of words) {
336
+ if (word.length === 0)
337
+ continue;
338
+ let hash = 0;
339
+ for (let i = 0; i < word.length; i++) {
340
+ hash = (hash * 31 + word.charCodeAt(i)) % 128;
341
+ }
342
+ embedding[hash] += 1;
343
+ }
344
+ // Normalize
345
+ const sumSq = embedding.reduce((acc, val) => acc + val * val, 0);
346
+ const magnitude = Math.sqrt(sumSq);
347
+ return embedding.map(val => magnitude === 0 ? 0 : val / magnitude);
348
+ }
349
+ async routeSkill(query, sharedBuffer) {
350
+ if (this.skills.length === 0) {
351
+ await this.loadSkills();
352
+ }
353
+ const queryEmbedding = this.generateMockEmbedding(query);
354
+ // Copy query embedding to SharedArrayBuffer offset 1024
355
+ const floatView = new Float32Array(sharedBuffer.buffer, sharedBuffer.byteOffset + 1024, 128);
356
+ floatView.set(queryEmbedding);
357
+ // Lock buffer via Rust
358
+ const locked = (0, core_1.lockSharedBuffer)(sharedBuffer);
359
+ if (!locked) {
360
+ throw new Error('Failed to lock shared buffer');
361
+ }
362
+ const results = this.hnsw.search(queryEmbedding, 2);
363
+ // Unlock buffer via Rust
364
+ (0, core_1.unlockSharedBuffer)(sharedBuffer);
365
+ return results;
366
+ }
367
+ }
368
+ exports.SkillManager = SkillManager;
369
+ __exportStar(require("./sandbox-controller"), exports);
370
+ __exportStar(require("./worker-agent"), exports);
371
+ __exportStar(require("./gateway"), exports);
372
+ __exportStar(require("./wal-buffer"), exports);
373
+ __exportStar(require("./oracle"), exports);
374
+ __exportStar(require("./prompt-optimizer"), exports);
375
+ __exportStar(require("./agent-os-rd"), exports);
376
+ __exportStar(require("./gpu-bridge"), exports);
377
+ __exportStar(require("./dashboard-server"), exports);
378
+ __exportStar(require("./value-calibration"), exports);
379
+ __exportStar(require("./oracle-anchored-search"), exports);
380
+ __exportStar(require("./predictive-agent"), exports);
381
+ __exportStar(require("./value-head"), exports);
382
+ __exportStar(require("./telemetry"), exports);
383
+ __exportStar(require("./governance"), exports);
384
+ __exportStar(require("./cost-estimator"), exports);
385
+ __exportStar(require("./satisfaction-metrics"), exports);
386
+ __exportStar(require("./governed-executor"), exports);
387
+ __exportStar(require("./rate-limiter"), exports);
388
+ __exportStar(require("./health"), exports);
389
+ __exportStar(require("./text-embedding"), exports);
390
+ __exportStar(require("./personalization"), exports);
391
+ __exportStar(require("./beta"), exports);
392
+ __exportStar(require("./multi-axis-lift"), exports);
393
+ __exportStar(require("./pglite-store"), exports);
394
+ __exportStar(require("./pglite-hnsw-bridge"), exports);
395
+ __exportStar(require("./knowledge-graph"), exports);
396
+ __exportStar(require("./wiki-synthesizer"), exports);
397
+ __exportStar(require("./safety-anneal"), exports);
398
+ __exportStar(require("./mcts-prior"), exports);
399
+ __exportStar(require("./mcts-kernel-bridge"), exports);
400
+ __exportStar(require("./commit-gate"), exports);
401
+ __exportStar(require("./mcp-macaroon"), exports);
402
+ __exportStar(require("./p6-governance"), exports);
403
+ __exportStar(require("./beta-runner"), exports);
404
+ var llm_1 = require("./llm");
405
+ Object.defineProperty(exports, "askAgent", { enumerable: true, get: function () { return llm_1.askAgent; } });
406
+ Object.defineProperty(exports, "askAgentChat", { enumerable: true, get: function () { return llm_1.askAgentChat; } });
407
+ Object.defineProperty(exports, "llmComplete", { enumerable: true, get: function () { return llm_1.llmComplete; } });
408
+ Object.defineProperty(exports, "llmCompleteUsage", { enumerable: true, get: function () { return llm_1.llmCompleteUsage; } });
409
+ Object.defineProperty(exports, "activeLlmInfo", { enumerable: true, get: function () { return llm_1.activeLlmInfo; } });
410
+ var chat_store_1 = require("./chat-store");
411
+ Object.defineProperty(exports, "ChatStore", { enumerable: true, get: function () { return chat_store_1.ChatStore; } });
412
+ Object.defineProperty(exports, "DEFAULT_CHAT_HISTORY_PATH", { enumerable: true, get: function () { return chat_store_1.DEFAULT_CHAT_HISTORY_PATH; } });
413
+ __exportStar(require("./channels"), exports);
414
+ __exportStar(require("./channel-gateway"), exports);
415
+ __exportStar(require("./conversation-graph"), exports);
416
+ __exportStar(require("./browser-agent"), exports);
417
+ exports.kakaoOAuth = __importStar(require("./kakao-oauth"));
@@ -0,0 +1,41 @@
1
+ import { Playbook } from '../playbook';
2
+ type FetchFn = (url: string, init?: any) => Promise<{
3
+ ok: boolean;
4
+ status: number;
5
+ json: () => Promise<any>;
6
+ }>;
7
+ export interface EmrPatient {
8
+ patientId: string;
9
+ name: string;
10
+ dob: string;
11
+ lastVisit?: string;
12
+ }
13
+ /** EMR 환자 조회 — SSRF/허용목록 가드 + 출력 검증. 결과는 Tier-0. */
14
+ export declare function lookupPatient(baseUrl: string, allowHosts: string[], query: {
15
+ name: string;
16
+ dob: string;
17
+ }, fetchFn: FetchFn, resolver?: (host: string) => Promise<string[]>): Promise<{
18
+ ok: boolean;
19
+ patient?: EmrPatient;
20
+ tier: number;
21
+ reason: string;
22
+ }>;
23
+ export interface Questionnaire {
24
+ domain: string;
25
+ jobName: string;
26
+ fields: {
27
+ key: string;
28
+ label: string;
29
+ required: boolean;
30
+ sensitive: boolean;
31
+ }[];
32
+ clinicalLike: boolean;
33
+ }
34
+ /** 설문 → Playbook 골격. 민감 필드=pii Tier. 임상 유사 직군은 clinicalScope. */
35
+ export declare function authorPlaybook(q: Questionnaire): Playbook;
36
+ /** 마켓 등재 안전 게이트: 임상 직군인데 human-review 없으면 거부 등. */
37
+ export declare function safetyGate(pb: Playbook): {
38
+ ok: boolean;
39
+ reasons: string[];
40
+ };
41
+ export {};
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ // ============================================================================
3
+ // P6 — EMR/보험 연동 어댑터 + 설문→플레이북 저작 (앱 v1.2 §5·§6) — 테스트 가능
4
+ // ----------------------------------------------------------------------------
5
+ // MVP 대조 규칙을 실 EMR/보험 데이터로 확장. 외부 연동은 SSRF/허용목록 가드를 통과해야
6
+ // 하고, 가져온 환자 데이터는 Tier-0(외부 재송신 금지)다.
7
+ //
8
+ // 정직 고지(제1계명): fetch 주입형(테스트 가능). 실 EMR 연동은 파트너 환경 검증.
9
+ // 자동 생성 플레이북도 안전 게이트(Tier 라벨·임상 차단) 통과 후에만 사용.
10
+ // ============================================================================
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.lookupPatient = lookupPatient;
13
+ exports.authorPlaybook = authorPlaybook;
14
+ exports.safetyGate = safetyGate;
15
+ const mcp_client_guard_1 = require("../mcp-client-guard");
16
+ const tier_classifier_1 = require("../tier-classifier");
17
+ /** EMR 환자 조회 — SSRF/허용목록 가드 + 출력 검증. 결과는 Tier-0. */
18
+ async function lookupPatient(baseUrl, allowHosts, query, fetchFn, resolver) {
19
+ const url = `${baseUrl}/patients?name=${encodeURIComponent(query.name)}&dob=${encodeURIComponent(query.dob)}`;
20
+ // M2 — 허용목록·프로토콜 1차 + DNS resolve 후 사설 IP 재검사(리바인딩 차단).
21
+ const safe = await (0, mcp_client_guard_1.isSafeResolvedUrl)(url, allowHosts, resolver);
22
+ if (!safe.ok)
23
+ return { ok: false, tier: 0, reason: `연동 차단: ${safe.reason}` };
24
+ const res = await fetchFn(url, { method: 'GET' });
25
+ if (!res.ok)
26
+ return { ok: false, tier: 0, reason: `EMR HTTP ${res.status}` };
27
+ const raw = JSON.stringify(await res.json());
28
+ const v = (0, mcp_client_guard_1.sanitizeToolOutput)(raw, (o) => o && typeof o.patientId === 'string' && typeof o.name === 'string');
29
+ if (!v.ok)
30
+ return { ok: false, tier: 0, reason: `EMR 응답 검증 실패: ${v.flags.join(',')}` };
31
+ const p = v.data;
32
+ // 가져온 환자 데이터는 민감 → Tier-0(외부 재송신 금지).
33
+ const tier = (0, tier_classifier_1.classifyTier)({ text: `${p.name} ${p.dob}`, kind: 'task' }).tier === 0 ? 0 : 0;
34
+ return { ok: true, patient: p, tier: 0, reason: 'ok' };
35
+ }
36
+ /** 설문 → Playbook 골격. 민감 필드=pii Tier. 임상 유사 직군은 clinicalScope. */
37
+ function authorPlaybook(q) {
38
+ return {
39
+ id: `${q.domain}-authored`,
40
+ name: q.jobName,
41
+ domain: q.domain,
42
+ clinicalScope: q.clinicalLike,
43
+ fields: q.fields.map((f) => ({ key: f.key, label: f.label, required: f.required, tier: f.sensitive ? 'pii' : 'public' })),
44
+ crossChecks: [
45
+ { id: 'REQUIRED', check: ({ record }) => null }, // 필수검증은 런타임이 수행(placeholder)
46
+ ],
47
+ llmSteps: [{ id: 'summary', tier: q.fields.some((f) => f.sensitive) ? 'pii' : 'public', prompt: () => '요약' }],
48
+ needsHumanReview: q.clinicalLike ? () => true : undefined,
49
+ };
50
+ }
51
+ /** 마켓 등재 안전 게이트: 임상 직군인데 human-review 없으면 거부 등. */
52
+ function safetyGate(pb) {
53
+ const reasons = [];
54
+ if (pb.clinicalScope && !pb.needsHumanReview)
55
+ reasons.push('임상 범위인데 사람 확인(human-in-loop) 없음');
56
+ if (!pb.fields.length)
57
+ reasons.push('필드 없음');
58
+ // 민감 필드가 있는데 LLM 단계가 전부 public(외부)면 위험
59
+ const hasPii = pb.fields.some((f) => f.tier === 'pii' || f.tier === 'sensitive');
60
+ if (hasPii && pb.llmSteps.length && pb.llmSteps.every((s) => s.tier === 'public'))
61
+ reasons.push('민감 데이터인데 모든 LLM 단계가 외부(빠른경로)');
62
+ return { ok: reasons.length === 0, reasons };
63
+ }
@@ -0,0 +1,16 @@
1
+ import { FetchFn } from './channels';
2
+ export interface KakaoToken {
3
+ accessToken: string;
4
+ refreshToken?: string;
5
+ /** access token 만료(초). */
6
+ expiresIn?: number;
7
+ scope?: string;
8
+ }
9
+ /** 동의 화면 URL. scope=talk_message('나에게 보내기' 권한). */
10
+ export declare function authorizeUrl(restApiKey: string, redirectUri: string, scope?: string): string;
11
+ /** redirect 로 받은 전체 URL 또는 code 문자열에서 code 만 추출. */
12
+ export declare function extractCode(input: string): string | null;
13
+ /** authorization code → access/refresh token 교환. */
14
+ export declare function exchangeCode(restApiKey: string, redirectUri: string, code: string, fetchFn?: FetchFn): Promise<KakaoToken>;
15
+ /** refresh token 으로 access token 재발급. */
16
+ export declare function refresh(restApiKey: string, refreshToken: string, fetchFn?: FetchFn): Promise<KakaoToken>;
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ // ============================================================================
3
+ // Kakao OAuth — '나에게 보내기'(talk_message)용 access token 발급 헬퍼
4
+ // ----------------------------------------------------------------------------
5
+ // KakaoTalk 은 개방형 봇 API 가 없어, 아웃바운드는 OAuth access token 으로 '나에게 보내기'를 쓴다.
6
+ // 토큰 획득 흐름(Authorization Code):
7
+ // 1) authorizeUrl() 을 브라우저로 열어 동의 → redirect_uri 로 ?code=... 수신
8
+ // 2) exchangeCode(code) 로 access_token/refresh_token 발급
9
+ // 3) access_token 을 KAKAO_ACCESS_TOKEN 으로 사용(만료 시 refresh()).
10
+ // 정직: 실제 발급은 사용자의 Kakao 앱 REST 키·동의가 있어야 검증된다(그 전엔 미측정).
11
+ // ============================================================================
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.authorizeUrl = authorizeUrl;
14
+ exports.extractCode = extractCode;
15
+ exports.exchangeCode = exchangeCode;
16
+ exports.refresh = refresh;
17
+ const AUTH_BASE = 'https://kauth.kakao.com/oauth/authorize';
18
+ const TOKEN_URL = 'https://kauth.kakao.com/oauth/token';
19
+ function getFetch(injected) {
20
+ if (injected)
21
+ return injected;
22
+ const f = globalThis.fetch;
23
+ if (!f)
24
+ throw new Error('global fetch 가 없습니다(Node 18+ 필요).');
25
+ return f;
26
+ }
27
+ /** 동의 화면 URL. scope=talk_message('나에게 보내기' 권한). */
28
+ function authorizeUrl(restApiKey, redirectUri, scope = 'talk_message') {
29
+ const q = new URLSearchParams({
30
+ client_id: restApiKey,
31
+ redirect_uri: redirectUri,
32
+ response_type: 'code',
33
+ scope,
34
+ });
35
+ return `${AUTH_BASE}?${q.toString()}`;
36
+ }
37
+ /** redirect 로 받은 전체 URL 또는 code 문자열에서 code 만 추출. */
38
+ function extractCode(input) {
39
+ const s = input.trim();
40
+ if (!s)
41
+ return null;
42
+ const m = s.match(/[?&]code=([^&\s]+)/);
43
+ if (m)
44
+ return decodeURIComponent(m[1]);
45
+ // URL 이 아니면 code 자체로 간주(공백/URL 파편 제거).
46
+ return /^[\w-]+$/.test(s) ? s : null;
47
+ }
48
+ /** authorization code → access/refresh token 교환. */
49
+ async function exchangeCode(restApiKey, redirectUri, code, fetchFn) {
50
+ const fetch = getFetch(fetchFn);
51
+ const body = new URLSearchParams({
52
+ grant_type: 'authorization_code',
53
+ client_id: restApiKey,
54
+ redirect_uri: redirectUri,
55
+ code,
56
+ }).toString();
57
+ const res = await fetch(TOKEN_URL, {
58
+ method: 'POST',
59
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8' },
60
+ body,
61
+ });
62
+ const j = await res.json().catch(() => ({}));
63
+ if (!res.ok || !j?.access_token) {
64
+ throw new Error(`Kakao 토큰 교환 실패: ${j?.error_description || j?.error || `HTTP ${res.status}`}`);
65
+ }
66
+ return { accessToken: j.access_token, refreshToken: j.refresh_token, expiresIn: j.expires_in, scope: j.scope };
67
+ }
68
+ /** refresh token 으로 access token 재발급. */
69
+ async function refresh(restApiKey, refreshToken, fetchFn) {
70
+ const fetch = getFetch(fetchFn);
71
+ const body = new URLSearchParams({
72
+ grant_type: 'refresh_token',
73
+ client_id: restApiKey,
74
+ refresh_token: refreshToken,
75
+ }).toString();
76
+ const res = await fetch(TOKEN_URL, {
77
+ method: 'POST',
78
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8' },
79
+ body,
80
+ });
81
+ const j = await res.json().catch(() => ({}));
82
+ if (!res.ok || !j?.access_token) {
83
+ throw new Error(`Kakao 토큰 갱신 실패: ${j?.error_description || j?.error || `HTTP ${res.status}`}`);
84
+ }
85
+ // refresh_token 은 갱신 시 재발급될 수도, 안 될 수도 있다(기존 유지).
86
+ return { accessToken: j.access_token, refreshToken: j.refresh_token, expiresIn: j.expires_in, scope: j.scope };
87
+ }
@@ -0,0 +1,53 @@
1
+ export type RelationType = 'reference' | 'dependency' | 'similarity';
2
+ export interface KnowledgeItem {
3
+ id: string;
4
+ content: string;
5
+ }
6
+ export interface GraphEdge {
7
+ source: string;
8
+ target: string;
9
+ type: RelationType;
10
+ /** similarity 는 코사인∈[0,1], reference/dependency 는 1(존재). */
11
+ weight: number;
12
+ }
13
+ export interface KnowledgeGraph {
14
+ nodes: string[];
15
+ edges: GraphEdge[];
16
+ }
17
+ export interface ParseOptions {
18
+ /** similarity 엣지 코사인 임계값(기본 0.5). */
19
+ similarityThreshold?: number;
20
+ /** 노드당 similarity 상위 K(기본 3). */
21
+ similarityTopK?: number;
22
+ /** similarity 엣지 생성 여부(기본 true). */
23
+ includeSimilarity?: boolean;
24
+ }
25
+ /**
26
+ * 지식 항목 배열에서 관계 그래프를 추출한다. 자기참조(X→X)는 제외, 같은 (source,target,type)는 1회.
27
+ */
28
+ export declare function parseKnowledgeGraph(items: KnowledgeItem[], opts?: ParseOptions): KnowledgeGraph;
29
+ export interface GoldLabel {
30
+ source: string;
31
+ target: string;
32
+ type: RelationType;
33
+ /** 이 관계가 실제로 존재하는가(인간/문서 검증). */
34
+ present: boolean;
35
+ }
36
+ export interface EvalResult {
37
+ type: RelationType | 'all';
38
+ labeled: number;
39
+ positives: number;
40
+ tp: number;
41
+ fp: number;
42
+ fn: number;
43
+ tn: number;
44
+ precision: number | null;
45
+ recall: number | null;
46
+ f1: number | null;
47
+ }
48
+ /**
49
+ * 예측 엣지 집합을 골드 라벨로 채점. 라벨된 (source,target,type) 쌍만 평가한다
50
+ * (열린세계 페널티 방지 — 라벨 외 엣지는 무시, 라벨된 음성으로 precision 측정).
51
+ * @param type 평가할 관계 종류(생략 시 'all' — 라벨 전체).
52
+ */
53
+ export declare function evaluateRelations(edges: GraphEdge[], gold: GoldLabel[], type?: RelationType): EvalResult;