triflux 3.2.0-dev.9 → 3.3.0-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/hub/tools.mjs CHANGED
@@ -8,16 +8,25 @@ import {
8
8
  teamTaskUpdate,
9
9
  teamSendMessage,
10
10
  } from './team/nativeProxy.mjs';
11
+ import {
12
+ ensurePipelineTable,
13
+ createPipeline,
14
+ } from './pipeline/index.mjs';
15
+ import {
16
+ readPipelineState,
17
+ initPipelineState,
18
+ listPipelineStates,
19
+ } from './pipeline/state.mjs';
11
20
 
12
21
  /**
13
22
  * MCP 도구 목록 생성
14
23
  * @param {object} store — createStore() 반환
15
24
  * @param {object} router — createRouter() 반환
16
- * @param {object} hitl — createHitlManager() 반환
17
- * @param {object} pipe — createPipeServer() 반환
18
- * @returns {Array<{name, description, inputSchema, handler}>}
19
- */
20
- export function createTools(store, router, hitl, pipe = null) {
25
+ * @param {object} hitl — createHitlManager() 반환
26
+ * @param {object} pipe — createPipeServer() 반환
27
+ * @returns {Array<{name, description, inputSchema, handler}>}
28
+ */
29
+ export function createTools(store, router, hitl, pipe = null) {
21
30
  /** 도구 핸들러 래퍼 — 에러 처리 + MCP content 형식 변환 */
22
31
  function wrap(code, fn) {
23
32
  return async (args) => {
@@ -49,10 +58,10 @@ export function createTools(store, router, hitl, pipe = null) {
49
58
  heartbeat_ttl_ms: { type: 'integer', minimum: 10000, maximum: 7200000 },
50
59
  },
51
60
  },
52
- handler: wrap('REGISTER_FAILED', (args) => {
53
- const data = router.registerAgent(args);
54
- return { ok: true, data };
55
- }),
61
+ handler: wrap('REGISTER_FAILED', (args) => {
62
+ const data = router.registerAgent(args);
63
+ return { ok: true, data };
64
+ }),
56
65
  },
57
66
 
58
67
  // ── 2. status ──
@@ -122,10 +131,10 @@ export function createTools(store, router, hitl, pipe = null) {
122
131
  }),
123
132
  },
124
133
 
125
- // ── 5. poll_messages ──
126
- {
127
- name: 'poll_messages',
128
- description: 'Deprecated. poll_messages 대신 Named Pipe subscribe/publish 채널을 사용합니다',
134
+ // ── 5. poll_messages ──
135
+ {
136
+ name: 'poll_messages',
137
+ description: 'Deprecated. poll_messages 대신 Named Pipe subscribe/publish 채널을 사용합니다',
129
138
  inputSchema: {
130
139
  type: 'object',
131
140
  required: ['agent_id'],
@@ -137,34 +146,34 @@ export function createTools(store, router, hitl, pipe = null) {
137
146
  ack_ids: { type: 'array', items: { type: 'string' }, maxItems: 100 },
138
147
  auto_ack: { type: 'boolean', default: false },
139
148
  },
140
- },
141
- handler: wrap('POLL_DEPRECATED', async (args) => {
142
- const replay = router.drainAgent(args.agent_id, {
143
- max_messages: args.max_messages,
144
- include_topics: args.include_topics,
145
- auto_ack: args.auto_ack,
146
- });
147
- if (args.ack_ids?.length) {
148
- router.ackMessages(args.ack_ids, args.agent_id);
149
- }
150
- return {
151
- ok: false,
152
- error: {
153
- code: 'POLL_DEPRECATED',
154
- message: 'poll_messages는 deprecated 되었습니다. pipe subscribe/publish 채널을 사용하세요.',
155
- },
156
- data: {
157
- pipe_path: pipe?.path || null,
158
- delivery_mode: 'pipe_push',
159
- protocol: 'ndjson',
160
- replay: {
161
- messages: replay,
162
- count: replay.length,
163
- },
164
- server_time_ms: Date.now(),
165
- },
166
- };
167
- }),
149
+ },
150
+ handler: wrap('POLL_DEPRECATED', async (args) => {
151
+ const replay = router.drainAgent(args.agent_id, {
152
+ max_messages: args.max_messages,
153
+ include_topics: args.include_topics,
154
+ auto_ack: args.auto_ack,
155
+ });
156
+ if (args.ack_ids?.length) {
157
+ router.ackMessages(args.ack_ids, args.agent_id);
158
+ }
159
+ return {
160
+ ok: false,
161
+ error: {
162
+ code: 'POLL_DEPRECATED',
163
+ message: 'poll_messages는 deprecated 되었습니다. pipe subscribe/publish 채널을 사용하세요.',
164
+ },
165
+ data: {
166
+ pipe_path: pipe?.path || null,
167
+ delivery_mode: 'pipe_push',
168
+ protocol: 'ndjson',
169
+ replay: {
170
+ messages: replay,
171
+ count: replay.length,
172
+ },
173
+ server_time_ms: Date.now(),
174
+ },
175
+ };
176
+ }),
168
177
  },
169
178
 
170
179
  // ── 6. handoff ──
@@ -325,5 +334,81 @@ export function createTools(store, router, hitl, pipe = null) {
325
334
  return teamSendMessage(args);
326
335
  }),
327
336
  },
337
+
338
+ // ── 13. pipeline_state ──
339
+ {
340
+ name: 'pipeline_state',
341
+ description: '파이프라인 상태를 조회합니다 (--thorough 모드)',
342
+ inputSchema: {
343
+ type: 'object',
344
+ required: ['team_name'],
345
+ properties: {
346
+ team_name: { type: 'string', pattern: '^[a-z0-9][a-z0-9-]*$' },
347
+ },
348
+ },
349
+ handler: wrap('PIPELINE_STATE_FAILED', (args) => {
350
+ ensurePipelineTable(store.db);
351
+ const state = readPipelineState(store.db, args.team_name);
352
+ return state
353
+ ? { ok: true, data: state }
354
+ : { ok: false, error: { code: 'PIPELINE_NOT_FOUND', message: `파이프라인 없음: ${args.team_name}` } };
355
+ }),
356
+ },
357
+
358
+ // ── 14. pipeline_advance ──
359
+ {
360
+ name: 'pipeline_advance',
361
+ description: '파이프라인을 다음 단계로 전이합니다 (전이 규칙 + fix loop 바운딩 적용)',
362
+ inputSchema: {
363
+ type: 'object',
364
+ required: ['team_name', 'phase'],
365
+ properties: {
366
+ team_name: { type: 'string', pattern: '^[a-z0-9][a-z0-9-]*$' },
367
+ phase: { type: 'string', enum: ['plan', 'prd', 'exec', 'verify', 'fix', 'complete', 'failed'] },
368
+ },
369
+ },
370
+ handler: wrap('PIPELINE_ADVANCE_FAILED', (args) => {
371
+ ensurePipelineTable(store.db);
372
+ const pipeline = createPipeline(store.db, args.team_name);
373
+ return pipeline.advance(args.phase);
374
+ }),
375
+ },
376
+
377
+ // ── 15. pipeline_init ──
378
+ {
379
+ name: 'pipeline_init',
380
+ description: '새 파이프라인을 초기화합니다 (기존 상태 덮어쓰기)',
381
+ inputSchema: {
382
+ type: 'object',
383
+ required: ['team_name'],
384
+ properties: {
385
+ team_name: { type: 'string', pattern: '^[a-z0-9][a-z0-9-]*$' },
386
+ fix_max: { type: 'integer', minimum: 1, maximum: 20, default: 3 },
387
+ ralph_max: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
388
+ },
389
+ },
390
+ handler: wrap('PIPELINE_INIT_FAILED', (args) => {
391
+ ensurePipelineTable(store.db);
392
+ const state = initPipelineState(store.db, args.team_name, {
393
+ fix_max: args.fix_max,
394
+ ralph_max: args.ralph_max,
395
+ });
396
+ return { ok: true, data: state };
397
+ }),
398
+ },
399
+
400
+ // ── 16. pipeline_list ──
401
+ {
402
+ name: 'pipeline_list',
403
+ description: '활성 파이프라인 목록을 조회합니다',
404
+ inputSchema: {
405
+ type: 'object',
406
+ properties: {},
407
+ },
408
+ handler: wrap('PIPELINE_LIST_FAILED', () => {
409
+ ensurePipelineTable(store.db);
410
+ return { ok: true, data: listPipelineStates(store.db) };
411
+ }),
412
+ },
328
413
  ];
329
414
  }