sentix 2.0.21 → 2.0.22

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sentix",
3
- "version": "2.0.21",
3
+ "version": "2.0.22",
4
4
  "description": "Autonomous multi-agent DevSecOps pipeline CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,6 +14,8 @@
14
14
  */
15
15
 
16
16
  import { spawnSync } from 'node:child_process';
17
+ import { existsSync } from 'node:fs';
18
+ import { join } from 'node:path';
17
19
  import { runGates } from './verify-gates.js';
18
20
 
19
21
  /**
@@ -191,27 +193,59 @@ export async function runChainedPipeline(request, cycleId, state, ctx, options =
191
193
  };
192
194
  }
193
195
 
196
+ // ── 에이전트 이름 → phase 이름 매핑 ────────────────────
197
+
198
+ const AGENT_MAP = {
199
+ plan: 'planner',
200
+ dev: 'dev',
201
+ review: 'pr-review',
202
+ finalize: null, // finalize는 전용 에이전트 없음
203
+ };
204
+
194
205
  // ── Phase 실행 ────────────────────────────────────────
195
206
 
196
207
  function runPhase(name, prompt, ctx) {
197
- const result = spawnSync('claude', ['-p', prompt], {
208
+ const args = ['-p', prompt, '--output-format', 'json'];
209
+
210
+ // .claude/agents/ 에 에이전트가 있으면 --agent 플래그 추가
211
+ const agentName = AGENT_MAP[name];
212
+ if (agentName && existsSync(join(ctx.cwd, '.claude', 'agents', `${agentName}.md`))) {
213
+ args.push('--agent', agentName);
214
+ }
215
+
216
+ const result = spawnSync('claude', args, {
198
217
  cwd: ctx.cwd,
199
- stdio: 'inherit',
200
- timeout: 300_000, // 5분 per phase (전체 10분 대신)
218
+ encoding: 'utf-8',
219
+ stdio: 'pipe',
220
+ timeout: 300_000, // 5분 per phase
201
221
  });
202
222
 
203
223
  if (result.error) {
204
224
  ctx.error(`Phase ${name} failed: ${result.error.message}`);
205
- return { success: false, error: result.error.message, exit_code: null };
225
+ return { success: false, error: result.error.message, exit_code: null, output: null };
206
226
  }
207
227
 
208
228
  if (result.status !== 0) {
209
229
  ctx.error(`Phase ${name} exited with code ${result.status}`);
210
- return { success: false, error: `exit code ${result.status}`, exit_code: result.status };
230
+ // stderr가 있으면 출력
231
+ if (result.stderr?.trim()) {
232
+ ctx.log(result.stderr.slice(-500));
233
+ }
234
+ return { success: false, error: `exit code ${result.status}`, exit_code: result.status, output: null };
235
+ }
236
+
237
+ // JSON 출력 파싱
238
+ let output = null;
239
+ try {
240
+ output = JSON.parse(result.stdout);
241
+ ctx.success(`Phase ${name} completed (${output.usage?.output_tokens || '?'} tokens)`);
242
+ } catch {
243
+ // JSON 파싱 실패 — 텍스트 그대로 사용
244
+ output = { content: result.stdout };
245
+ ctx.success(`Phase ${name} completed`);
211
246
  }
212
247
 
213
- ctx.success(`Phase ${name} completed`);
214
- return { success: true, error: null, exit_code: 0 };
248
+ return { success: true, error: null, exit_code: 0, output };
215
249
  }
216
250
 
217
251
  // ── 최근 티켓 내용 가져오기 ───────────────────────────