@triflux/remote 10.51.0 → 10.53.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 (62) hide show
  1. package/cto/brief.mjs +0 -8
  2. package/cto/collect.mjs +1 -127
  3. package/cto/current.schema.json +2 -19
  4. package/cto/hygiene.mjs +2 -61
  5. package/cto/lake-root.mjs +0 -56
  6. package/cto/status.mjs +5 -139
  7. package/hub/index.mjs +0 -9
  8. package/hub/team/agents-row-attach.py +120 -0
  9. package/hub/team/agents-row.mjs +200 -0
  10. package/hub/team/claude-daemon-control.mjs +1 -2
  11. package/hub/team/claude-session-projection.mjs +5 -73
  12. package/hub/team/claude-transcript.mjs +19 -0
  13. package/hub/team/cli/commands/debug.mjs +1 -2
  14. package/hub/team/cli/commands/start/index.mjs +2 -1
  15. package/hub/team/cli/commands/start/start-headless.mjs +2 -0
  16. package/hub/team/cli/commands/start/start-mux.mjs +2 -4
  17. package/hub/team/cli/services/state-store.mjs +5 -20
  18. package/hub/team/headless.mjs +132 -551
  19. package/hub/team/psmux.mjs +3 -33
  20. package/hub/team/results-index.mjs +92 -0
  21. package/hub/team/session-context.mjs +1 -1
  22. package/hub/team/tui-viewer.mjs +9 -56
  23. package/hub/team/tui.mjs +0 -37
  24. package/hub/team/uds-orchestrator.mjs +20 -599
  25. package/hub/workers/factory.mjs +6 -51
  26. package/hub/workers/interface.mjs +1 -7
  27. package/hub/workers/lib/jsonrpc-core.mjs +11 -0
  28. package/hub/workers/lib/jsonrpc-ws-uds.mjs +5 -6
  29. package/package.json +3 -8
  30. package/scripts/lib/agent-route-policy.mjs +0 -67
  31. package/scripts/lib/cli-claude.mjs +0 -12
  32. package/scripts/lib/env-probe.mjs +0 -70
  33. package/scripts/lib/legacy-mcp-cleanup.mjs +283 -0
  34. package/scripts/lib/mcp-guard-engine.mjs +42 -101
  35. package/hub/hub-lifecycle.mjs +0 -248
  36. package/hub/pipe.mjs +0 -825
  37. package/hub/promote-penalties.mjs +0 -138
  38. package/hub/public/dashboard.html +0 -416
  39. package/hub/schema.sql +0 -209
  40. package/hub/server.mjs +0 -3048
  41. package/hub/store-adapter.mjs +0 -182
  42. package/hub/store.mjs +0 -1736
  43. package/hub/team/cli/services/hub-client.mjs +0 -178
  44. package/hub/team/conductor-registry.mjs +0 -121
  45. package/hub/team/cto-auto-collect.mjs +0 -115
  46. package/hub/team/lead-control.mjs +0 -191
  47. package/hub/team/session-sync.mjs +0 -316
  48. package/hub/team/swarm-intent.mjs +0 -18
  49. package/hub/team/synapse-cli.mjs +0 -458
  50. package/hub/team/synapse-http.mjs +0 -311
  51. package/hub/team/synapse-registry.mjs +0 -618
  52. package/hub/team/tui-synapse.mjs +0 -223
  53. package/hub/team/worker-sandbox.mjs +0 -125
  54. package/hub/tools.mjs +0 -900
  55. package/hub/workers/codex-app-server-worker.mjs +0 -1067
  56. package/hub/workers/delegator-mcp.mjs +0 -1098
  57. package/hub/workers/lib/jsonrpc-stdio.mjs +0 -204
  58. package/scripts/lib/claudemd-scanner.mjs +0 -26
  59. package/scripts/lib/context.mjs +0 -51
  60. package/scripts/lib/handoff.mjs +0 -187
  61. package/scripts/lib/logger.mjs +0 -122
  62. package/scripts/lib/stealth-fetch.mjs +0 -176
package/hub/tools.mjs DELETED
@@ -1,900 +0,0 @@
1
- // hub/tools.mjs — MCP 도구 정의
2
- // register/status/publish/ask/poll/handoff/HITL + team proxy
3
- // 모든 도구 응답: { ok: boolean, error?: { code, message }, data?: ... }
4
-
5
- import {
6
- DEFAULT_ASSIGN_TIMEOUT_MS,
7
- DEFAULT_ASSIGN_TTL_MS,
8
- DEFAULT_HANDOFF_TTL_MS,
9
- } from "@triflux/core/hub/lib/timeout-defaults.mjs";
10
- import { createPipeline, ensurePipelineTable } from "@triflux/core/hub/pipeline/index.mjs";
11
- import {
12
- initPipelineState,
13
- listPipelineStates,
14
- readPipelineState,
15
- } from "@triflux/core/hub/pipeline/state.mjs";
16
- import { sendInputToConductorSession } from "./team/conductor-registry.mjs";
17
- import { getTeamBridge } from "@triflux/core/hub/team-bridge.mjs";
18
-
19
- const TEAM_BRIDGE_NOT_REGISTERED = "bridge_not_registered";
20
-
21
- function getTeamBridgeMethod(methodName) {
22
- const method = getTeamBridge()?.[methodName];
23
- return typeof method === "function" ? method : null;
24
- }
25
-
26
- function teamInfoFallback(args = {}) {
27
- return {
28
- ok: true,
29
- data: {
30
- team: {
31
- team_name: args.team_name ?? null,
32
- description: null,
33
- },
34
- lead: {
35
- lead_agent_id: null,
36
- lead_session_id: null,
37
- },
38
- ...(args.include_members !== false ? { members: [] } : {}),
39
- ...(args.include_paths !== false
40
- ? {
41
- paths: {
42
- config_path: null,
43
- tasks_dir: null,
44
- inboxes_dir: null,
45
- tasks_dir_resolution: TEAM_BRIDGE_NOT_REGISTERED,
46
- },
47
- }
48
- : {}),
49
- bridge_installed: false,
50
- skipped: true,
51
- },
52
- };
53
- }
54
-
55
- function teamTaskListFallback() {
56
- return {
57
- ok: true,
58
- data: {
59
- tasks: [],
60
- count: 0,
61
- parse_warnings: 0,
62
- tasks_dir: null,
63
- tasks_dir_resolution: TEAM_BRIDGE_NOT_REGISTERED,
64
- bridge_installed: false,
65
- skipped: true,
66
- },
67
- };
68
- }
69
-
70
- function teamTaskUpdateFallback(args = {}) {
71
- return {
72
- ok: true,
73
- data: {
74
- claimed: false,
75
- updated: false,
76
- task_before: null,
77
- task_after: null,
78
- task_file: null,
79
- task_id: args.task_id ?? null,
80
- mtime_ms: null,
81
- bridge_installed: false,
82
- skipped: true,
83
- },
84
- };
85
- }
86
-
87
- function teamSendMessageFallback(args = {}) {
88
- return {
89
- ok: true,
90
- data: {
91
- message_id: null,
92
- recipient: args.to ?? "team-lead",
93
- inbox_file: null,
94
- queued_at: null,
95
- unread_count: 0,
96
- bridge_installed: false,
97
- skipped: true,
98
- },
99
- };
100
- }
101
-
102
- /**
103
- * MCP 도구 목록 생성
104
- * @param {object} store — createStore() 반환
105
- * @param {object} router — createRouter() 반환
106
- * @param {object} hitl — createHitlManager() 반환
107
- * @param {object} pipe — createPipeServer() 반환
108
- * @returns {Array<{name, description, inputSchema, handler}>}
109
- */
110
- export function createTools(store, router, hitl, pipe = null) {
111
- /** 도구 핸들러 래퍼 — 에러 처리 + MCP content 형식 변환 */
112
- function wrap(code, fn) {
113
- return async (args) => {
114
- try {
115
- const result = await fn(args);
116
- return { content: [{ type: "text", text: JSON.stringify(result) }] };
117
- } catch (e) {
118
- const err = { ok: false, error: { code, message: e.message } };
119
- return {
120
- content: [{ type: "text", text: JSON.stringify(err) }],
121
- isError: true,
122
- };
123
- }
124
- };
125
- }
126
-
127
- return [
128
- // ── 1. register ──
129
- {
130
- name: "register",
131
- description: "에이전트를 허브에 등록하고 lease를 발급받습니다",
132
- inputSchema: {
133
- type: "object",
134
- required: [
135
- "agent_id",
136
- "cli",
137
- "capabilities",
138
- "topics",
139
- "heartbeat_ttl_ms",
140
- ],
141
- properties: {
142
- agent_id: { type: "string", pattern: "^[a-zA-Z0-9._:-]{3,64}$" },
143
- cli: {
144
- type: "string",
145
- enum: ["codex", "antigravity", "gemini", "claude", "other"],
146
- },
147
- pid: { type: "integer", minimum: 1 },
148
- capabilities: {
149
- type: "array",
150
- items: { type: "string" },
151
- minItems: 1,
152
- maxItems: 64,
153
- },
154
- topics: { type: "array", items: { type: "string" }, maxItems: 64 },
155
- metadata: { type: "object" },
156
- project_id: { type: "string", pattern: "^prj_[A-Za-z0-9_-]{22}$" },
157
- session_id: { type: "string", minLength: 1, maxLength: 256 },
158
- host_id: { type: "string", pattern: "^hst_[A-Za-z0-9_-]+$" },
159
- transport_locators_json: {
160
- description:
161
- "tfx.transport-locator.v1 객체 배열 또는 그 JSON 문자열",
162
- oneOf: [
163
- { type: "array", items: { type: "object" } },
164
- { type: "string" },
165
- ],
166
- },
167
- hub_instance_id: { type: "string" },
168
- store_fingerprint: { type: "string" },
169
- heartbeat_ttl_ms: {
170
- type: "integer",
171
- minimum: 10000,
172
- maximum: 7200000,
173
- },
174
- },
175
- },
176
- handler: wrap("REGISTER_FAILED", (args) => router.registerAgent(args)),
177
- },
178
-
179
- // ── 2. status ──
180
- {
181
- name: "status",
182
- description: "허브, 에이전트, 큐, 트레이스 상태를 조회합니다",
183
- inputSchema: {
184
- type: "object",
185
- properties: {
186
- scope: {
187
- type: "string",
188
- enum: ["hub", "agent", "queue", "trace"],
189
- default: "hub",
190
- },
191
- agent_id: { type: "string" },
192
- trace_id: { type: "string" },
193
- include_metrics: { type: "boolean", default: true },
194
- hub_instance_id: { type: "string" },
195
- store_fingerprint: { type: "string" },
196
- },
197
- },
198
- handler: wrap("STATUS_FAILED", (args) => {
199
- return router.getStatus(args.scope || "hub", args);
200
- }),
201
- },
202
-
203
- // ── 2-1. takeover_role ──
204
- {
205
- name: "takeover_role",
206
- description:
207
- "CTO 같은 허브 역할의 active leader를 명시적으로 승계하고 미처리 역할 메시지를 새 leader에게 이전합니다",
208
- inputSchema: {
209
- type: "object",
210
- required: ["role", "agent_id"],
211
- properties: {
212
- role: { type: "string", enum: ["cto"], default: "cto" },
213
- agent_id: { type: "string", pattern: "^[a-zA-Z0-9._:-]{3,64}$" },
214
- reason: { type: "string" },
215
- requested_by: { type: "string" },
216
- hub_instance_id: { type: "string" },
217
- store_fingerprint: { type: "string" },
218
- },
219
- },
220
- handler: wrap("TAKEOVER_ROLE_FAILED", (args) => {
221
- return router.takeoverRole(args);
222
- }),
223
- },
224
-
225
- // ── 3. publish ──
226
- {
227
- name: "publish",
228
- description:
229
- '이벤트 또는 응답 메시지를 발행합니다. to에 "topic:XXX" 지정 시 구독자 전체 fanout',
230
- inputSchema: {
231
- type: "object",
232
- required: ["from", "to", "topic", "payload"],
233
- properties: {
234
- from: { type: "string", pattern: "^[a-zA-Z0-9._:-]{3,64}$" },
235
- to: { type: "string" },
236
- topic: { type: "string", pattern: "^[a-zA-Z0-9._:-]+$" },
237
- priority: { type: "integer", minimum: 1, maximum: 9, default: 5 },
238
- ttl_ms: {
239
- type: "integer",
240
- minimum: 1000,
241
- maximum: 86400000,
242
- default: 300000,
243
- },
244
- payload: { type: "object" },
245
- trace_id: { type: "string" },
246
- correlation_id: { type: "string" },
247
- },
248
- },
249
- handler: wrap("PUBLISH_FAILED", (args) => {
250
- return router.handlePublish(args);
251
- }),
252
- },
253
-
254
- // ── 4. ask ──
255
- {
256
- name: "ask",
257
- description:
258
- "다른 에이전트에게 질문합니다. await_response_ms > 0이면 짧은 폴링으로 응답 대기",
259
- inputSchema: {
260
- type: "object",
261
- required: ["from", "to", "topic", "question"],
262
- properties: {
263
- from: { type: "string", pattern: "^[a-zA-Z0-9._:-]{3,64}$" },
264
- to: { type: "string" },
265
- topic: { type: "string", pattern: "^[a-zA-Z0-9._:-]+$" },
266
- question: { type: "string", minLength: 1, maxLength: 20000 },
267
- context_refs: {
268
- type: "array",
269
- items: { type: "string" },
270
- maxItems: 32,
271
- },
272
- payload: { type: "object" },
273
- priority: { type: "integer", minimum: 1, maximum: 9, default: 5 },
274
- ttl_ms: {
275
- type: "integer",
276
- minimum: 1000,
277
- maximum: 86400000,
278
- default: 300000,
279
- },
280
- await_response_ms: {
281
- type: "integer",
282
- minimum: 0,
283
- maximum: 30000,
284
- default: 0,
285
- },
286
- trace_id: { type: "string" },
287
- correlation_id: { type: "string" },
288
- },
289
- },
290
- handler: wrap("ASK_FAILED", async (args) => {
291
- return await router.handleAsk(args);
292
- }),
293
- },
294
-
295
- // ── 5. poll_messages ──
296
- {
297
- name: "poll_messages",
298
- description:
299
- "Deprecated. poll_messages 대신 Named Pipe subscribe/publish 채널을 사용합니다",
300
- inputSchema: {
301
- type: "object",
302
- required: ["agent_id"],
303
- properties: {
304
- agent_id: { type: "string", pattern: "^[a-zA-Z0-9._:-]{3,64}$" },
305
- wait_ms: {
306
- type: "integer",
307
- minimum: 0,
308
- maximum: 30000,
309
- default: 1000,
310
- },
311
- max_messages: {
312
- type: "integer",
313
- minimum: 1,
314
- maximum: 100,
315
- default: 20,
316
- },
317
- include_topics: {
318
- type: "array",
319
- items: { type: "string" },
320
- maxItems: 64,
321
- },
322
- ack_ids: { type: "array", items: { type: "string" }, maxItems: 100 },
323
- auto_ack: { type: "boolean", default: false },
324
- },
325
- },
326
- handler: wrap("POLL_DEPRECATED", async (args) => {
327
- const replay = router.drainAgent(args.agent_id, {
328
- max_messages: args.max_messages,
329
- include_topics: args.include_topics,
330
- auto_ack: args.auto_ack,
331
- });
332
- if (args.ack_ids?.length) {
333
- router.ackMessages(args.ack_ids, args.agent_id);
334
- }
335
- return {
336
- ok: false,
337
- error: {
338
- code: "POLL_DEPRECATED",
339
- message:
340
- "poll_messages는 deprecated 되었습니다. pipe subscribe/publish 채널을 사용하세요.",
341
- },
342
- data: {
343
- pipe_path: pipe?.path || null,
344
- delivery_mode: "pipe_push",
345
- protocol: "ndjson",
346
- replay: {
347
- messages: replay,
348
- count: replay.length,
349
- },
350
- server_time_ms: Date.now(),
351
- },
352
- };
353
- }),
354
- },
355
-
356
- // ── 6. handoff ──
357
- {
358
- name: "handoff",
359
- description:
360
- "다른 에이전트에게 작업을 인계합니다. acceptance_criteria로 완료 기준 지정 가능",
361
- inputSchema: {
362
- type: "object",
363
- required: ["from", "to", "topic", "task"],
364
- properties: {
365
- from: { type: "string", pattern: "^[a-zA-Z0-9._:-]{3,64}$" },
366
- to: { type: "string" },
367
- topic: { type: "string", pattern: "^[a-zA-Z0-9._:-]+$" },
368
- task: { type: "string", minLength: 1, maxLength: 20000 },
369
- acceptance_criteria: {
370
- type: "array",
371
- items: { type: "string" },
372
- maxItems: 32,
373
- },
374
- context_refs: {
375
- type: "array",
376
- items: { type: "string" },
377
- maxItems: 32,
378
- },
379
- priority: { type: "integer", minimum: 1, maximum: 9, default: 5 },
380
- ttl_ms: {
381
- type: "integer",
382
- minimum: 1000,
383
- maximum: 86400000,
384
- default: DEFAULT_HANDOFF_TTL_MS,
385
- },
386
- trace_id: { type: "string" },
387
- correlation_id: { type: "string" },
388
- },
389
- },
390
- handler: wrap("HANDOFF_FAILED", (args) => {
391
- return router.handleHandoff(args);
392
- }),
393
- },
394
-
395
- // ── 7. assign_async ──
396
- {
397
- name: "assign_async",
398
- description:
399
- "AWS CAO 스타일 비차단 assign job을 생성하고 워커에게 실시간 전달합니다",
400
- inputSchema: {
401
- type: "object",
402
- required: ["supervisor_agent", "worker_agent", "task"],
403
- properties: {
404
- supervisor_agent: {
405
- type: "string",
406
- pattern: "^[a-zA-Z0-9._:-]{3,64}$",
407
- },
408
- worker_agent: { type: "string", pattern: "^[a-zA-Z0-9._:-]{3,64}$" },
409
- topic: {
410
- type: "string",
411
- pattern: "^[a-zA-Z0-9._:-]+$",
412
- default: "assign.job",
413
- },
414
- task: { type: "string", minLength: 1, maxLength: 20000 },
415
- payload: { type: "object" },
416
- priority: { type: "integer", minimum: 1, maximum: 9, default: 5 },
417
- ttl_ms: {
418
- type: "integer",
419
- minimum: 1000,
420
- maximum: 86400000,
421
- default: DEFAULT_ASSIGN_TTL_MS,
422
- },
423
- timeout_ms: {
424
- type: "integer",
425
- minimum: 1000,
426
- maximum: 86400000,
427
- default: DEFAULT_ASSIGN_TIMEOUT_MS,
428
- },
429
- max_retries: { type: "integer", minimum: 0, maximum: 20, default: 0 },
430
- trace_id: { type: "string" },
431
- correlation_id: { type: "string" },
432
- },
433
- },
434
- handler: wrap("ASSIGN_ASYNC_FAILED", (args) => {
435
- return router.assignAsync(args);
436
- }),
437
- },
438
-
439
- // ── 8. assign_result ──
440
- {
441
- name: "assign_result",
442
- description:
443
- "assign job의 진행/완료 결과를 보고합니다. completed + metadata.result 관례를 지원합니다",
444
- inputSchema: {
445
- type: "object",
446
- required: ["job_id", "status"],
447
- properties: {
448
- job_id: { type: "string", minLength: 1, maxLength: 128 },
449
- worker_agent: { type: "string", pattern: "^[a-zA-Z0-9._:-]{3,64}$" },
450
- status: {
451
- type: "string",
452
- enum: [
453
- "queued",
454
- "running",
455
- "in_progress",
456
- "completed",
457
- "succeeded",
458
- "success",
459
- "failed",
460
- "error",
461
- "timed_out",
462
- "timeout",
463
- ],
464
- },
465
- attempt: { type: "integer", minimum: 1 },
466
- result: {},
467
- error: {},
468
- metadata: { type: "object" },
469
- payload: { type: "object" },
470
- },
471
- },
472
- handler: wrap("ASSIGN_RESULT_FAILED", (args) => {
473
- return router.reportAssignResult(args);
474
- }),
475
- },
476
-
477
- // ── 9. assign_status ──
478
- {
479
- name: "assign_status",
480
- description:
481
- "assign job 단건 상태 또는 supervisor/worker/status 기준 목록을 조회합니다",
482
- inputSchema: {
483
- type: "object",
484
- properties: {
485
- job_id: { type: "string", minLength: 1, maxLength: 128 },
486
- supervisor_agent: {
487
- type: "string",
488
- pattern: "^[a-zA-Z0-9._:-]{3,64}$",
489
- },
490
- worker_agent: { type: "string", pattern: "^[a-zA-Z0-9._:-]{3,64}$" },
491
- status: {
492
- type: "string",
493
- enum: ["queued", "running", "succeeded", "failed", "timed_out"],
494
- },
495
- statuses: {
496
- type: "array",
497
- items: {
498
- type: "string",
499
- enum: ["queued", "running", "succeeded", "failed", "timed_out"],
500
- },
501
- maxItems: 8,
502
- },
503
- trace_id: { type: "string" },
504
- correlation_id: { type: "string" },
505
- limit: { type: "integer", minimum: 1, maximum: 100, default: 50 },
506
- },
507
- },
508
- handler: wrap("ASSIGN_STATUS_FAILED", (args) => {
509
- return router.getAssignStatus(args);
510
- }),
511
- },
512
-
513
- // ── 10. request_human_input ──
514
- {
515
- name: "request_human_input",
516
- description:
517
- "사용자에게 입력을 요청합니다 (CAPTCHA, 승인, 자격증명, 선택, 텍스트)",
518
- inputSchema: {
519
- type: "object",
520
- required: [
521
- "requester_agent",
522
- "kind",
523
- "prompt",
524
- "requested_schema",
525
- "deadline_ms",
526
- "default_action",
527
- ],
528
- properties: {
529
- requester_agent: {
530
- type: "string",
531
- pattern: "^[a-zA-Z0-9._:-]{3,64}$",
532
- },
533
- kind: {
534
- type: "string",
535
- enum: ["captcha", "approval", "credential", "choice", "text"],
536
- },
537
- prompt: { type: "string", minLength: 1, maxLength: 20000 },
538
- requested_schema: { type: "object" },
539
- deadline_ms: { type: "integer", minimum: 1000 },
540
- default_action: {
541
- type: "string",
542
- enum: ["decline", "cancel", "timeout_continue"],
543
- },
544
- channel_preference: {
545
- type: "string",
546
- enum: ["terminal", "pipe", "file_polling"],
547
- default: "terminal",
548
- },
549
- trace_id: { type: "string" },
550
- correlation_id: { type: "string" },
551
- },
552
- },
553
- handler: wrap("HITL_REQUEST_FAILED", (args) => {
554
- return hitl.requestHumanInput(args);
555
- }),
556
- },
557
-
558
- // ── 11. submit_human_input ──
559
- {
560
- name: "submit_human_input",
561
- description: "사용자 입력 요청에 응답합니다 (accept, decline, cancel)",
562
- inputSchema: {
563
- type: "object",
564
- required: ["request_id", "action"],
565
- properties: {
566
- request_id: { type: "string" },
567
- action: { type: "string", enum: ["accept", "decline", "cancel"] },
568
- content: { type: "object" },
569
- submitted_by: { type: "string", default: "human" },
570
- },
571
- },
572
- handler: wrap("HITL_SUBMIT_FAILED", (args) => {
573
- return hitl.submitHumanInput(args);
574
- }),
575
- },
576
-
577
- // ── 12. team_info ──
578
- {
579
- name: "team_info",
580
- description: "Claude Native Teams 메타/멤버/경로 정보를 조회합니다",
581
- inputSchema: {
582
- type: "object",
583
- required: ["team_name"],
584
- properties: {
585
- team_name: {
586
- type: "string",
587
- minLength: 1,
588
- maxLength: 128,
589
- pattern: "^[a-z0-9][a-z0-9-]*$",
590
- },
591
- include_members: { type: "boolean", default: true },
592
- include_paths: { type: "boolean", default: true },
593
- },
594
- },
595
- handler: wrap("TEAM_INFO_FAILED", (args) => {
596
- const teamInfo = getTeamBridgeMethod("teamInfo");
597
- return teamInfo ? teamInfo(args) : teamInfoFallback(args);
598
- }),
599
- },
600
-
601
- // ── 13. team_task_list ──
602
- {
603
- name: "team_task_list",
604
- description:
605
- "Claude Native Teams task 목록을 owner/status 조건으로 조회합니다. 실패 판정은 completed + metadata.result도 함께 확인해야 합니다",
606
- inputSchema: {
607
- type: "object",
608
- required: ["team_name"],
609
- properties: {
610
- team_name: { type: "string", pattern: "^[a-z0-9][a-z0-9-]*$" },
611
- owner: { type: "string" },
612
- statuses: {
613
- type: "array",
614
- items: {
615
- type: "string",
616
- enum: [
617
- "pending",
618
- "in_progress",
619
- "completed",
620
- "failed",
621
- "deleted",
622
- ],
623
- },
624
- maxItems: 8,
625
- },
626
- include_internal: { type: "boolean", default: false },
627
- limit: { type: "integer", minimum: 1, maximum: 1000, default: 200 },
628
- },
629
- },
630
- handler: wrap("TEAM_TASK_LIST_FAILED", (args) => {
631
- const teamTaskList = getTeamBridgeMethod("teamTaskList");
632
- return teamTaskList ? teamTaskList(args) : teamTaskListFallback(args);
633
- }),
634
- },
635
-
636
- // ── 14. team_task_update ──
637
- {
638
- name: "team_task_update",
639
- description:
640
- 'Claude Native Teams task를 claim/update 합니다. status: "failed" 입력은 completed + metadata.result="failed"로 정규화됩니다',
641
- inputSchema: {
642
- type: "object",
643
- required: ["team_name", "task_id"],
644
- properties: {
645
- team_name: { type: "string", pattern: "^[a-z0-9][a-z0-9-]*$" },
646
- task_id: { type: "string", minLength: 1, maxLength: 64 },
647
- claim: { type: "boolean", default: false },
648
- owner: { type: "string" },
649
- status: {
650
- type: "string",
651
- enum: ["pending", "in_progress", "completed", "failed", "deleted"],
652
- },
653
- subject: { type: "string" },
654
- description: { type: "string" },
655
- activeForm: { type: "string" },
656
- add_blocks: { type: "array", items: { type: "string" } },
657
- add_blocked_by: { type: "array", items: { type: "string" } },
658
- metadata_patch: { type: "object" },
659
- if_match_mtime_ms: { type: "number" },
660
- actor: { type: "string" },
661
- },
662
- },
663
- handler: wrap("TEAM_TASK_UPDATE_FAILED", (args) => {
664
- const teamTaskUpdate = getTeamBridgeMethod("teamTaskUpdate");
665
- return teamTaskUpdate
666
- ? teamTaskUpdate(args)
667
- : teamTaskUpdateFallback(args);
668
- }),
669
- },
670
-
671
- // ── 15. team_send_message ──
672
- {
673
- name: "team_send_message",
674
- description: "Claude Native Teams inbox에 메시지를 append 합니다",
675
- inputSchema: {
676
- type: "object",
677
- required: ["team_name", "from", "text"],
678
- properties: {
679
- team_name: { type: "string", pattern: "^[a-z0-9][a-z0-9-]*$" },
680
- from: { type: "string", minLength: 1, maxLength: 128 },
681
- to: { type: "string", default: "team-lead" },
682
- text: { type: "string", minLength: 1, maxLength: 200000 },
683
- summary: { type: "string", maxLength: 1000 },
684
- color: { type: "string", default: "blue" },
685
- },
686
- },
687
- handler: wrap("TEAM_SEND_MESSAGE_FAILED", (args) => {
688
- const teamSendMessage = getTeamBridgeMethod("teamSendMessage");
689
- return teamSendMessage
690
- ? teamSendMessage(args)
691
- : teamSendMessageFallback(args);
692
- }),
693
- },
694
-
695
- // ── 16. pipeline_state ──
696
- {
697
- name: "pipeline_state",
698
- description: "파이프라인 상태를 조회합니다 (--thorough 모드)",
699
- inputSchema: {
700
- type: "object",
701
- required: ["team_name"],
702
- properties: {
703
- team_name: { type: "string", pattern: "^[a-z0-9][a-z0-9-]*$" },
704
- },
705
- },
706
- handler: wrap("PIPELINE_STATE_FAILED", (args) => {
707
- ensurePipelineTable(store.db);
708
- const state = readPipelineState(store.db, args.team_name);
709
- return state
710
- ? { ok: true, data: state }
711
- : {
712
- ok: false,
713
- error: {
714
- code: "PIPELINE_NOT_FOUND",
715
- message: `파이프라인 없음: ${args.team_name}`,
716
- },
717
- };
718
- }),
719
- },
720
-
721
- // ── 17. pipeline_advance ──
722
- {
723
- name: "pipeline_advance",
724
- description:
725
- "파이프라인을 다음 단계로 전이합니다 (전이 규칙 + fix loop 바운딩 적용)",
726
- inputSchema: {
727
- type: "object",
728
- required: ["team_name", "phase"],
729
- properties: {
730
- team_name: { type: "string", pattern: "^[a-z0-9][a-z0-9-]*$" },
731
- phase: {
732
- type: "string",
733
- enum: [
734
- "plan",
735
- "prd",
736
- "exec",
737
- "verify",
738
- "fix",
739
- "complete",
740
- "failed",
741
- ],
742
- },
743
- },
744
- },
745
- handler: wrap("PIPELINE_ADVANCE_FAILED", (args) => {
746
- ensurePipelineTable(store.db);
747
- const pipeline = createPipeline(store.db, args.team_name);
748
- return pipeline.advance(args.phase);
749
- }),
750
- },
751
-
752
- // ── 18. pipeline_init ──
753
- {
754
- name: "pipeline_init",
755
- description: "새 파이프라인을 초기화합니다 (기존 상태 덮어쓰기)",
756
- inputSchema: {
757
- type: "object",
758
- required: ["team_name"],
759
- properties: {
760
- team_name: { type: "string", pattern: "^[a-z0-9][a-z0-9-]*$" },
761
- fix_max: { type: "integer", minimum: 1, maximum: 20, default: 3 },
762
- ralph_max: { type: "integer", minimum: 1, maximum: 100, default: 10 },
763
- },
764
- },
765
- handler: wrap("PIPELINE_INIT_FAILED", (args) => {
766
- ensurePipelineTable(store.db);
767
- const state = initPipelineState(store.db, args.team_name, {
768
- fix_max: args.fix_max,
769
- ralph_max: args.ralph_max,
770
- });
771
- return { ok: true, data: state };
772
- }),
773
- },
774
-
775
- // ── 19. pipeline_advance_gated (HITL 승인 게이트) ──
776
- {
777
- name: "pipeline_advance_gated",
778
- description:
779
- "HITL 승인 게이트가 포함된 파이프라인 전이. 지정 단계로의 전이 전 사용자 승인을 요청하고, 승인 후 전이를 실행합니다. deadline 초과 시 default_action에 따라 자동 처리됩니다.",
780
- inputSchema: {
781
- type: "object",
782
- required: ["team_name", "phase"],
783
- properties: {
784
- team_name: { type: "string", pattern: "^[a-z0-9][a-z0-9-]*$" },
785
- phase: {
786
- type: "string",
787
- enum: [
788
- "plan",
789
- "prd",
790
- "exec",
791
- "verify",
792
- "fix",
793
- "complete",
794
- "failed",
795
- ],
796
- },
797
- prompt: {
798
- type: "string",
799
- description: "사용자에게 표시할 승인 요청 메시지",
800
- },
801
- deadline_ms: {
802
- type: "integer",
803
- minimum: 5000,
804
- maximum: 600000,
805
- default: 120000,
806
- },
807
- default_action: {
808
- type: "string",
809
- enum: ["timeout_continue", "timeout_abort"],
810
- default: "timeout_continue",
811
- },
812
- requester_agent: {
813
- type: "string",
814
- description: "요청자 에이전트 이름",
815
- },
816
- },
817
- },
818
- handler: wrap("PIPELINE_ADVANCE_GATED_FAILED", (args) => {
819
- ensurePipelineTable(store.db);
820
- const pipeline = createPipeline(store.db, args.team_name);
821
-
822
- // 전이 가능 여부 사전 확인
823
- if (!pipeline.canAdvance(args.phase)) {
824
- const current = pipeline.getState();
825
- return {
826
- ok: false,
827
- error: {
828
- code: "TRANSITION_BLOCKED",
829
- message: `전이 불가: ${current.phase} → ${args.phase}`,
830
- },
831
- };
832
- }
833
-
834
- // HITL 승인 요청 생성
835
- const approvalPrompt =
836
- args.prompt ||
837
- `파이프라인 ${args.team_name}: ${pipeline.getState().phase} → ${args.phase} 전이를 승인하시겠습니까?`;
838
- const deadlineMs = args.deadline_ms || 120000;
839
- const now = Date.now();
840
-
841
- const hitlResult = hitl.requestHumanInput({
842
- requester_agent: args.requester_agent || `pipeline:${args.team_name}`,
843
- kind: "approval",
844
- prompt: approvalPrompt,
845
- deadline_ms: now + deadlineMs,
846
- default_action: args.default_action || "timeout_continue",
847
- });
848
-
849
- if (!hitlResult.ok) {
850
- return hitlResult;
851
- }
852
-
853
- return {
854
- ok: true,
855
- data: {
856
- pending: true,
857
- request_id: hitlResult.data.request_id,
858
- team_name: args.team_name,
859
- target_phase: args.phase,
860
- current_phase: pipeline.getState().phase,
861
- deadline_ms: now + deadlineMs,
862
- default_action: args.default_action || "timeout_continue",
863
- message: `승인 대기 중. ID: ${hitlResult.data.request_id}. ${Math.round(deadlineMs / 1000)}초 후 ${args.default_action || "timeout_continue"} 자동 실행.`,
864
- },
865
- };
866
- }),
867
- },
868
-
869
- // ── 20. pipeline_list ──
870
- {
871
- name: "pipeline_list",
872
- description: "활성 파이프라인 목록을 조회합니다",
873
- inputSchema: {
874
- type: "object",
875
- properties: {},
876
- },
877
- handler: wrap("PIPELINE_LIST_FAILED", () => {
878
- ensurePipelineTable(store.db);
879
- return { ok: true, data: listPipelineStates(store.db) };
880
- }),
881
- },
882
-
883
- // ── 22. send_input ──
884
- {
885
- name: "send_input",
886
- description: "Send input text to a worker in INPUT_WAIT state",
887
- inputSchema: {
888
- type: "object",
889
- properties: {
890
- session_id: { type: "string", description: "Conductor session ID" },
891
- text: { type: "string", description: "Input text to send" },
892
- },
893
- required: ["session_id", "text"],
894
- },
895
- handler: wrap("SEND_INPUT_FAILED", (args) => {
896
- return sendInputToConductorSession(args.session_id, args.text);
897
- }),
898
- },
899
- ];
900
- }