@dotobokuri/fleet-cli 1.16.1 → 1.17.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.
package/dist/index.js CHANGED
@@ -17625,13 +17625,51 @@ function buildWindowsCmdArgs(command2, args) {
17625
17625
  const line = [command2, ...args].map(quoteForCmd).join(" ");
17626
17626
  return ["/S", "/C", `"${line}"`];
17627
17627
  }
17628
- var BaseConnection;
17628
+ function sanitizeDiagnosticStderrLine(value, isPemLine) {
17629
+ const cleaned = (isPemLine ? "[REDACTED:pem_private_key]" : redactDiagnosticSecrets(value.replace(ANSI_PATTERN, "").replace(CONTROL_PATTERN, ""))).trim();
17630
+ if (cleaned.length <= STDERR_DIAGNOSTIC_LINE_CHAR_LIMIT) {
17631
+ return cleaned;
17632
+ }
17633
+ const omitted = cleaned.length - STDERR_DIAGNOSTIC_LINE_CHAR_LIMIT;
17634
+ return `${cleaned.slice(0, STDERR_DIAGNOSTIC_LINE_CHAR_LIMIT)} [truncated ${omitted} chars]`;
17635
+ }
17636
+ function normalizePemMarkerLine(value) {
17637
+ return value.replace(ANSI_PATTERN, "").replace(CONTROL_PATTERN, "").trim();
17638
+ }
17639
+ function redactDiagnosticSecrets(value) {
17640
+ return SECRET_PATTERNS.reduce((text, { label, pattern }) => text.replace(pattern, `[REDACTED:${label}]`), value);
17641
+ }
17642
+ function byteLength(value) {
17643
+ return Buffer.byteLength(value, "utf8");
17644
+ }
17645
+ var STDERR_DIAGNOSTIC_LINE_LIMIT, STDERR_DIAGNOSTIC_LINE_CHAR_LIMIT, STDERR_DIAGNOSTIC_TOTAL_BYTE_LIMIT, ANSI_PATTERN, CONTROL_PATTERN, SECRET_PATTERNS, PEM_BEGIN_PATTERN, PEM_END_PATTERN, BaseConnection;
17629
17646
  var init_BaseConnection = __esm({
17630
17647
  "../../packages/core-unified-agent/dist/connection/BaseConnection.js"() {
17631
17648
  "use strict";
17632
17649
  init_acp();
17633
17650
  init_env();
17634
17651
  init_process();
17652
+ STDERR_DIAGNOSTIC_LINE_LIMIT = 20;
17653
+ STDERR_DIAGNOSTIC_LINE_CHAR_LIMIT = 2e3;
17654
+ STDERR_DIAGNOSTIC_TOTAL_BYTE_LIMIT = 8e3;
17655
+ ANSI_PATTERN = /\x1b\[[0-?]*[ -/]*[@-~]/g;
17656
+ CONTROL_PATTERN = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g;
17657
+ SECRET_PATTERNS = [
17658
+ { label: "aws_access_key", pattern: /AKIA[0-9A-Z]{16}/g },
17659
+ { label: "github_token", pattern: /gh[psour]_[A-Za-z0-9]{36}/g },
17660
+ { label: "jwt", pattern: /eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g },
17661
+ { label: "openai_key", pattern: /\bsk-[A-Za-z0-9_-]{20,}\b/g },
17662
+ {
17663
+ label: "generic_secret",
17664
+ pattern: /\b[A-Z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL)[A-Z0-9_]*\s*[:=]\s*["']?[^\s"']+["']?/gi
17665
+ },
17666
+ {
17667
+ label: "pem_private_key",
17668
+ pattern: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]+?-----END [A-Z ]*PRIVATE KEY-----/g
17669
+ }
17670
+ ];
17671
+ PEM_BEGIN_PATTERN = /-----BEGIN [A-Z ]*PRIVATE KEY-----/;
17672
+ PEM_END_PATTERN = /-----END [A-Z ]*PRIVATE KEY-----/;
17635
17673
  BaseConnection = class extends EventEmitter {
17636
17674
  constructor(options2) {
17637
17675
  super();
@@ -17640,6 +17678,8 @@ var init_BaseConnection = __esm({
17640
17678
  this.acpStream = null;
17641
17679
  this.childExitPromise = null;
17642
17680
  this.stderrBuffer = "";
17681
+ this.diagnosticStderrTail = [];
17682
+ this.inPemBlock = false;
17643
17683
  this.command = options2.command;
17644
17684
  this.args = options2.args;
17645
17685
  this.cwd = options2.cwd;
@@ -17765,9 +17805,29 @@ var init_BaseConnection = __esm({
17765
17805
  if (!message) {
17766
17806
  return;
17767
17807
  }
17808
+ this.recordDiagnosticStderrLine(message);
17768
17809
  this.emit("log", message);
17769
17810
  this.emit("logEntry", this.createStructuredLogEntry(message));
17770
17811
  }
17812
+ /** 실패 메시지에 붙일 수 있는 짧고 마스킹된 stderr tail을 반환합니다. */
17813
+ getStderrDiagnosticTail() {
17814
+ return this.diagnosticStderrTail.join("\n");
17815
+ }
17816
+ /** 원본 에러에 stderr tail 진단을 붙여 상위 계층으로 전달합니다. */
17817
+ withStderrDiagnostics(error51, phase) {
17818
+ const baseError = error51 instanceof Error ? error51 : new Error(String(error51));
17819
+ this.flushStderrBuffer();
17820
+ const stderrTail = this.getStderrDiagnosticTail();
17821
+ if (!stderrTail || baseError.message.includes(`${phase} stderr tail:`)) {
17822
+ return baseError;
17823
+ }
17824
+ const diagnosticError = new Error(`${baseError.message}
17825
+
17826
+ ${phase} stderr tail:
17827
+ ${stderrTail}`, { cause: baseError });
17828
+ diagnosticError.name = baseError.name;
17829
+ return diagnosticError;
17830
+ }
17771
17831
  /** 기본 구조화 stderr 로그 항목을 생성합니다. */
17772
17832
  createStructuredLogEntry(message) {
17773
17833
  return {
@@ -17804,6 +17864,27 @@ var init_BaseConnection = __esm({
17804
17864
  })
17805
17865
  ]);
17806
17866
  }
17867
+ recordDiagnosticStderrLine(message) {
17868
+ const pemMarkerLine = normalizePemMarkerLine(message);
17869
+ if (PEM_BEGIN_PATTERN.test(pemMarkerLine)) {
17870
+ this.inPemBlock = true;
17871
+ }
17872
+ const inBlock = this.inPemBlock;
17873
+ if (PEM_END_PATTERN.test(pemMarkerLine)) {
17874
+ this.inPemBlock = false;
17875
+ }
17876
+ const sanitized = sanitizeDiagnosticStderrLine(message, inBlock);
17877
+ if (!sanitized) {
17878
+ return;
17879
+ }
17880
+ this.diagnosticStderrTail.push(sanitized);
17881
+ while (this.diagnosticStderrTail.length > STDERR_DIAGNOSTIC_LINE_LIMIT) {
17882
+ this.diagnosticStderrTail.shift();
17883
+ }
17884
+ while (byteLength(this.getStderrDiagnosticTail()) > STDERR_DIAGNOSTIC_TOTAL_BYTE_LIMIT && this.diagnosticStderrTail.length > 1) {
17885
+ this.diagnosticStderrTail.shift();
17886
+ }
17887
+ }
17807
17888
  };
17808
17889
  }
17809
17890
  });
@@ -17908,7 +17989,7 @@ var init_AcpConnection = __esm({
17908
17989
  await this.disconnect();
17909
17990
  } catch {
17910
17991
  }
17911
- throw error51;
17992
+ throw this.withStderrDiagnostics(error51, "ACP initialize");
17912
17993
  }
17913
17994
  }
17914
17995
  /**
@@ -17920,38 +18001,42 @@ var init_AcpConnection = __esm({
17920
18001
  * @returns 세션 정보
17921
18002
  */
17922
18003
  async createSession(workspace, sessionId, mcpServers, systemPrompt, strictMcp, effort) {
17923
- const agent = this.getAgent();
17924
- const servers = mcpServers ?? [];
17925
- let session;
17926
- if (sessionId) {
17927
- if (!agent.loadSession) {
17928
- throw new Error("\uC5F0\uACB0\uB41C \uC5D0\uC774\uC804\uD2B8\uAC00 session/load\uB97C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
17929
- }
17930
- const loadSessionParams = {
17931
- sessionId,
17932
- cwd: workspace,
17933
- mcpServers: servers
17934
- };
17935
- const meta3 = this.buildClaudeSessionMeta(systemPrompt, strictMcp, effort);
17936
- if (meta3) {
17937
- loadSessionParams._meta = meta3;
17938
- }
17939
- const loadResult = await this.withFixedTimeout(agent.loadSession(loadSessionParams), this.initTimeout, "session/load");
17940
- session = { ...loadResult, sessionId };
17941
- } else {
17942
- const newSessionParams = {
17943
- cwd: workspace,
17944
- mcpServers: servers
17945
- };
17946
- const meta3 = this.buildClaudeSessionMeta(systemPrompt, strictMcp, effort);
17947
- if (meta3) {
17948
- newSessionParams._meta = meta3;
18004
+ try {
18005
+ const agent = this.getAgent();
18006
+ const servers = mcpServers ?? [];
18007
+ let session;
18008
+ if (sessionId) {
18009
+ if (!agent.loadSession) {
18010
+ throw new Error("\uC5F0\uACB0\uB41C \uC5D0\uC774\uC804\uD2B8\uAC00 session/load\uB97C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
18011
+ }
18012
+ const loadSessionParams = {
18013
+ sessionId,
18014
+ cwd: workspace,
18015
+ mcpServers: servers
18016
+ };
18017
+ const meta3 = this.buildClaudeSessionMeta(systemPrompt, strictMcp, effort);
18018
+ if (meta3) {
18019
+ loadSessionParams._meta = meta3;
18020
+ }
18021
+ const loadResult = await this.withFixedTimeout(agent.loadSession(loadSessionParams), this.initTimeout, "session/load");
18022
+ session = { ...loadResult, sessionId };
18023
+ } else {
18024
+ const newSessionParams = {
18025
+ cwd: workspace,
18026
+ mcpServers: servers
18027
+ };
18028
+ const meta3 = this.buildClaudeSessionMeta(systemPrompt, strictMcp, effort);
18029
+ if (meta3) {
18030
+ newSessionParams._meta = meta3;
18031
+ }
18032
+ session = await this.withFixedTimeout(agent.newSession(newSessionParams), this.initTimeout, "session/new");
17949
18033
  }
17950
- session = await this.withFixedTimeout(agent.newSession(newSessionParams), this.initTimeout, "session/new");
18034
+ this.setState("ready");
18035
+ this.activeSessionId = session.sessionId;
18036
+ return session;
18037
+ } catch (error51) {
18038
+ throw this.withStderrDiagnostics(error51, sessionId ? "ACP session/load" : "ACP session/new");
17951
18039
  }
17952
- this.setState("ready");
17953
- this.activeSessionId = session.sessionId;
17954
- return session;
17955
18040
  }
17956
18041
  /**
17957
18042
  * ACP 연결을 시작합니다.
@@ -17994,10 +18079,14 @@ var init_AcpConnection = __esm({
17994
18079
  if (meta3) {
17995
18080
  loadSessionParams._meta = meta3;
17996
18081
  }
17997
- const result = await this.withFixedTimeout(agent.loadSession(loadSessionParams), this.requestTimeout, "session/load");
17998
- this.activeSessionId = params.sessionId;
17999
- this.setState("ready");
18000
- return result;
18082
+ try {
18083
+ const result = await this.withFixedTimeout(agent.loadSession(loadSessionParams), this.requestTimeout, "session/load");
18084
+ this.activeSessionId = params.sessionId;
18085
+ this.setState("ready");
18086
+ return result;
18087
+ } catch (error51) {
18088
+ throw this.withStderrDiagnostics(error51, "ACP session/load");
18089
+ }
18001
18090
  }
18002
18091
  /**
18003
18092
  * 현재 세션을 종료합니다 (프로세스는 유지).
@@ -31081,9 +31170,9 @@ function buildJobSummaryText(prefix, status, successCount, failureCount, error51
31081
31170
  var HEAD_BYTE_RATIO = 0.25;
31082
31171
  var MAX_TEXT_CHARS = 24e3;
31083
31172
  var MAX_RAW_OUTPUT_CHARS = 12e3;
31084
- var ANSI_PATTERN = /\x1b\[[0-?]*[ -/]*[@-~]/g;
31085
- var CONTROL_PATTERN = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g;
31086
- var SECRET_PATTERNS = [
31173
+ var ANSI_PATTERN2 = /\x1b\[[0-?]*[ -/]*[@-~]/g;
31174
+ var CONTROL_PATTERN2 = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g;
31175
+ var SECRET_PATTERNS2 = [
31087
31176
  { label: "aws_access_key", pattern: /AKIA[0-9A-Z]{16}/g },
31088
31177
  { label: "jwt", pattern: /eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g },
31089
31178
  { label: "github_token", pattern: /gh[psour]_[A-Za-z0-9]{36}/g },
@@ -31165,7 +31254,7 @@ function emptyGroupPlaceholderBlock(label, timestamp) {
31165
31254
  function applyByteCap(blocks, maxBytes, truncatedInLabel, enableSingleBlockCharSlice = false) {
31166
31255
  if (!maxBytes || maxBytes <= 0) return blocks;
31167
31256
  const full = blocks.map((block) => renderBlock(block)).join("\n\n").trimEnd();
31168
- if (byteLength(full) <= maxBytes) return blocks;
31257
+ if (byteLength2(full) <= maxBytes) return blocks;
31169
31258
  if (enableSingleBlockCharSlice) {
31170
31259
  const sliced = trySliceOversizedSingleOrHeaderPayload(blocks, maxBytes, truncatedInLabel);
31171
31260
  if (sliced) return sliced;
@@ -31204,7 +31293,7 @@ function trySliceOversizedSingleOrHeaderPayload(blocks, maxBytes, truncatedInLab
31204
31293
  if (blocks.length === 1) {
31205
31294
  const block = blocks[0];
31206
31295
  const rendered = renderBlock(block);
31207
- if (byteLength(rendered) <= maxBytes) return null;
31296
+ if (byteLength2(rendered) <= maxBytes) return null;
31208
31297
  return sliceSingleOversizedTextBlock(block, rendered, maxBytes, truncatedInLabel);
31209
31298
  }
31210
31299
  if (blocks.length === 2 && isSerializerGroupHeaderBlock(blocks[0]) && blocks[1]?.kind === "text") {
@@ -31213,12 +31302,12 @@ function trySliceOversizedSingleOrHeaderPayload(blocks, maxBytes, truncatedInLab
31213
31302
  const headerRendered = renderBlock(headerBlock);
31214
31303
  const bodyRendered = renderBlock(payloadBlock);
31215
31304
  const sep = "\n\n";
31216
- const prefixBytes = byteLength(headerRendered) + byteLength(sep);
31305
+ const prefixBytes = byteLength2(headerRendered) + byteLength2(sep);
31217
31306
  const innerBudget = maxBytes - prefixBytes;
31218
31307
  if (innerBudget <= 0) {
31219
31308
  return [headerBlock, buildCharTruncatedMarkerBlock(payloadBlock.timestamp, countCodepointsInUtf8Buffer(Buffer.from(bodyRendered, "utf8")), truncatedInLabel)];
31220
31309
  }
31221
- if (byteLength(bodyRendered) <= innerBudget) return null;
31310
+ if (byteLength2(bodyRendered) <= innerBudget) return null;
31222
31311
  const { head, marker, tail } = splitRenderedUtf8AtByteCap(bodyRendered, innerBudget, truncatedInLabel);
31223
31312
  return [
31224
31313
  headerBlock,
@@ -31254,7 +31343,7 @@ function splitRenderedUtf8AtByteCap(rendered, maxBytes, charLabel) {
31254
31343
  if (buf.length <= maxBytes) {
31255
31344
  return { head: rendered, marker: "", tail: "" };
31256
31345
  }
31257
- const sepLen = byteLength("\n\n");
31346
+ const sepLen = byteLength2("\n\n");
31258
31347
  let headBudget = Math.min(buf.length, Math.floor(maxBytes * HEAD_BYTE_RATIO));
31259
31348
  const tailBudget = Math.min(buf.length, Math.floor(maxBytes * (1 - HEAD_BYTE_RATIO)));
31260
31349
  for (let iter = 0; iter < 200; iter++) {
@@ -31271,7 +31360,7 @@ function splitRenderedUtf8AtByteCap(rendered, maxBytes, charLabel) {
31271
31360
  const marker2 = buildCharTruncatedMarker(omittedChars, charLabel);
31272
31361
  const headStr = buf.subarray(0, headLen2).toString("utf8");
31273
31362
  const tailStr = buf.subarray(tailStart2).toString("utf8");
31274
- const total = byteLength(headStr) + sepLen + byteLength(marker2) + sepLen + byteLength(tailStr);
31363
+ const total = byteLength2(headStr) + sepLen + byteLength2(marker2) + sepLen + byteLength2(tailStr);
31275
31364
  if (total <= maxBytes) {
31276
31365
  return { head: headStr, marker: marker2, tail: tailStr };
31277
31366
  }
@@ -31279,7 +31368,7 @@ function splitRenderedUtf8AtByteCap(rendered, maxBytes, charLabel) {
31279
31368
  if (headBudget === 0) break;
31280
31369
  }
31281
31370
  const marker = buildCharTruncatedMarker(Math.max(1, countCodepointsInUtf8Buffer(buf) - 1), charLabel);
31282
- const markerTotal = byteLength(marker) + 2 * sepLen;
31371
+ const markerTotal = byteLength2(marker) + 2 * sepLen;
31283
31372
  const room = Math.max(1, maxBytes - markerTotal);
31284
31373
  const tailBudgetFallback = Math.min(buf.length, Math.max(1, Math.floor(room * (1 - HEAD_BYTE_RATIO))));
31285
31374
  let tailStart = utf8SuffixStartIndex(buf, tailBudgetFallback);
@@ -31351,12 +31440,12 @@ function buildTruncatedMarker(blocks, omittedStart, omittedCount, truncatedInLab
31351
31440
  };
31352
31441
  }
31353
31442
  function serializedBlocksBytes(blocks) {
31354
- return byteLength(blocks.map((block) => renderBlock(block)).join("\n\n").trimEnd());
31443
+ return byteLength2(blocks.map((block) => renderBlock(block)).join("\n\n").trimEnd());
31355
31444
  }
31356
31445
  function serializedBlockBytes(block, includeSeparator) {
31357
- return byteLength(`${includeSeparator ? "\n\n" : ""}${renderBlock(block)}`);
31446
+ return byteLength2(`${includeSeparator ? "\n\n" : ""}${renderBlock(block)}`);
31358
31447
  }
31359
- function byteLength(value) {
31448
+ function byteLength2(value) {
31360
31449
  return Buffer.byteLength(value, "utf8");
31361
31450
  }
31362
31451
  function toArchiveBlock(kind, source, text, label, timestamp = Date.now()) {
@@ -31387,13 +31476,13 @@ function toToolCallArchiveBlock(source, title, status, rawOutput, toolCallId, la
31387
31476
  };
31388
31477
  }
31389
31478
  function sanitizeArchiveText(value, maxChars = MAX_TEXT_CHARS) {
31390
- const cleaned = value.replace(ANSI_PATTERN, "").replace(CONTROL_PATTERN, "");
31479
+ const cleaned = value.replace(ANSI_PATTERN2, "").replace(CONTROL_PATTERN2, "");
31391
31480
  if (cleaned.length <= maxChars) return cleaned;
31392
31481
  return `${cleaned.slice(0, maxChars)}
31393
31482
  [truncated ${cleaned.length - maxChars} chars]`;
31394
31483
  }
31395
31484
  function redactSecrets(value) {
31396
- return SECRET_PATTERNS.reduce(
31485
+ return SECRET_PATTERNS2.reduce(
31397
31486
  (text, { label, pattern }) => text.replace(pattern, `[REDACTED:${label}]`),
31398
31487
  value
31399
31488
  );
@@ -32815,6 +32904,9 @@ async function runCarrierJobInBackground(opts) {
32815
32904
  try {
32816
32905
  result = await runSingleCarrier(opts);
32817
32906
  finalStatus = result.status;
32907
+ if (finalStatus === "error") {
32908
+ finalError = result.error ?? result.responseText;
32909
+ }
32818
32910
  } catch (error51) {
32819
32911
  finalStatus = "error";
32820
32912
  finalError = error51 instanceof Error ? error51.message : String(error51);
@@ -43203,7 +43295,7 @@ function buildQueueIdHelp(prefix, availableIds) {
43203
43295
  }
43204
43296
  return `${prefix}. Available patch IDs: ${availableIds.join(", ")}`;
43205
43297
  }
43206
- var SECRET_PATTERNS2 = [
43298
+ var SECRET_PATTERNS3 = [
43207
43299
  /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/i,
43208
43300
  /\b(?:api[_-]?key|secret|password|token)\s*[:=]\s*["']?[a-z0-9_\-]{16,}/i,
43209
43301
  /\bghp_[a-z0-9_]{20,}\b/i,
@@ -43216,7 +43308,7 @@ var PROMPT_INJECTION_PATTERNS = [
43216
43308
  ];
43217
43309
  function findUnsafeMemoryText(content) {
43218
43310
  const issues = [];
43219
- if (SECRET_PATTERNS2.some((pattern) => pattern.test(content))) {
43311
+ if (SECRET_PATTERNS3.some((pattern) => pattern.test(content))) {
43220
43312
  issues.push({
43221
43313
  code: "unsafe_secret",
43222
43314
  severity: "error",