{"version":3,"file":"fableFlow-D4K01Whn.cjs","names":["Buffer"],"sources":["../src/services/fableFlow/index.ts"],"sourcesContent":["import { Buffer } from 'node:buffer';\n\nexport const FABLE_PROVIDER_SOURCE = '@agimon-ai/doompi-team';\nexport const FABLE_PLAN_REQUESTER = '@agimon-ai/doompi-plan';\nexport const FABLE_PLAN_RUNTIME = 'claude';\nexport const FABLE_PLAN_MODEL = 'fable';\nexport const FABLE_PLAN_PROFILE = 'claude/fable-plan-v1';\nexport const MAX_FABLE_PACKET_BYTES = 32 * 1024;\nexport const MAX_FABLE_TEXT_BYTES = 4 * 1024;\nexport const MAX_FABLE_ARRAY_ITEMS = 24;\n\nconst SECRET_PATTERNS = [\n  /(?:api[_-]?key|access[_-]?token|client[_-]?secret|password|private[_-]?key|authorization|bearer)\\s*[:=]/iu,\n  /-----BEGIN [A-Z ]*PRIVATE KEY-----/u,\n  /\\bsk-[A-Za-z0-9_-]{16,}\\b/u,\n  /\\bgh[pousr]_[A-Za-z0-9_]{16,}\\b/u,\n];\nconst CONTROL_CHARACTER_MAX = 31;\nconst DELETE_CHARACTER = 127;\nconst MAX_SOURCE_PATH_LENGTH = 512;\n\nexport interface FablePlanFinding {\n  path: string;\n  finding: string;\n}\n\nexport interface FablePlanPacket {\n  goal: string[];\n  constraints: string[];\n  decisions: string[];\n  verifiedFindings: FablePlanFinding[];\n  inferredFindings: string[];\n  unresolvedQuestions: string[];\n  currentPlan?: string;\n}\n\nexport type FablePlanStatus = 'completed' | 'failed' | 'timed_out' | 'cancelled' | 'interrupted';\nexport type FablePlanStage = 'draft' | 'review' | 'completed' | 'failed' | 'cancelled' | 'interrupted';\n\nexport interface FablePlanResult {\n  operationId: string;\n  status: FablePlanStatus;\n  stage: FablePlanStage;\n  draft?: string;\n  review?: string;\n  draftRunId?: string;\n  reviewRunId?: string;\n  durationMs: number;\n  errorCode?: string;\n}\n\nexport interface FablePlanRequest {\n  requester: typeof FABLE_PLAN_REQUESTER;\n  operationId: string;\n  runtime: typeof FABLE_PLAN_RUNTIME;\n  model: typeof FABLE_PLAN_MODEL;\n  profile: typeof FABLE_PLAN_PROFILE;\n  packet: FablePlanPacket;\n}\n\nexport interface FablePlanBroker {\n  start(request: FablePlanRequest, signal: AbortSignal): Promise<FablePlanResult>;\n  cancel(operationId: string, reason: string): void;\n}\n\nexport interface FableFlowOptions {\n  broker?: FablePlanBroker;\n  isAuthorized: () => boolean;\n  /** Supplies operation ids. Injected so a test can pin them. */\n  newOperationId?: () => string;\n  timeoutMs?: number;\n  onStage?: (stage: FableStage) => void;\n  onError?: (error: unknown) => void;\n}\n\nexport type FableStage = 'idle' | 'draft' | 'review' | 'completed' | 'failed' | 'cancelled' | 'interrupted';\n\nexport interface FablePlanFlow {\n  run(value: unknown, signal?: AbortSignal): Promise<FablePlanResult>;\n  cancel(reason?: string): void;\n  isActive(): boolean;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction hasControlCharacter(value: string): boolean {\n  for (const character of value) {\n    const code = character.codePointAt(0);\n    if (code !== undefined && (code <= CONTROL_CHARACTER_MAX || code === DELETE_CHARACTER)) return true;\n  }\n  return false;\n}\n\nexport function containsSuspectedCredential(value: string): boolean {\n  return SECRET_PATTERNS.some((pattern) => pattern.test(value));\n}\n\nfunction boundedText(value: unknown, field: string, required = true): string {\n  if (typeof value !== 'string') throw new Error(`${field} must be a string.`);\n  const text = value.trim();\n  if (!text && required) throw new Error(`${field} must not be empty.`);\n  if (Buffer.byteLength(text, 'utf8') > MAX_FABLE_TEXT_BYTES || hasControlCharacter(text)) {\n    throw new Error(`${field} exceeds the bounded Fable text limit or contains control characters.`);\n  }\n  if (containsSuspectedCredential(text)) throw new Error(`${field} appears to contain a credential.`);\n  return text;\n}\n\nfunction boundedList(value: unknown, field: string, required = true): string[] {\n  if (!Array.isArray(value)) throw new Error(`${field} must be an array.`);\n  if (value.length > MAX_FABLE_ARRAY_ITEMS) throw new Error(`${field} exceeds the bounded item limit.`);\n  const items = value.map((item, index) => boundedText(item, `${field}[${index}]`));\n  if (required && items.length === 0) throw new Error(`${field} must contain at least one item.`);\n  return items;\n}\n\nfunction boundedPath(value: unknown, field: string): string {\n  if (typeof value !== 'string') throw new Error(`${field} must be a string.`);\n  const sourcePath = value.trim();\n  if (!sourcePath || sourcePath.length > MAX_SOURCE_PATH_LENGTH || hasControlCharacter(sourcePath)) {\n    throw new Error(`${field} is not a safe source path.`);\n  }\n  if (containsSuspectedCredential(sourcePath)) throw new Error(`${field} appears to contain a credential.`);\n  return sourcePath;\n}\n\nfunction boundedFindings(value: unknown): FablePlanFinding[] {\n  if (!Array.isArray(value)) throw new Error('verifiedFindings must be an array.');\n  if (value.length > MAX_FABLE_ARRAY_ITEMS) throw new Error('verifiedFindings exceeds the bounded item limit.');\n  return value.map((item, index) => {\n    if (!isRecord(item)) throw new Error(`verifiedFindings[${index}] must be an object.`);\n    const keys = Object.keys(item);\n    if (keys.some((key) => key !== 'path' && key !== 'finding')) {\n      throw new Error(`verifiedFindings[${index}] contains an unsupported field.`);\n    }\n    return {\n      path: boundedPath(item.path, `verifiedFindings[${index}].path`),\n      finding: boundedText(item.finding, `verifiedFindings[${index}].finding`),\n    };\n  });\n}\n\nfunction assertAllowedKeys(value: Record<string, unknown>, keys: readonly string[], field: string): void {\n  const allowed = new Set(keys);\n  const unexpected = Object.keys(value).find((key) => !allowed.has(key));\n  if (unexpected) throw new Error(`${field} contains unsupported field '${unexpected}'.`);\n}\n\nexport function sanitizeFablePacket(value: unknown): FablePlanPacket {\n  if (!isRecord(value)) throw new Error('Fable packet must be an object.');\n  assertAllowedKeys(\n    value,\n    ['goal', 'constraints', 'decisions', 'verifiedFindings', 'inferredFindings', 'unresolvedQuestions', 'currentPlan'],\n    'Fable packet',\n  );\n  const packet: FablePlanPacket = {\n    goal: boundedList(value.goal, 'goal'),\n    constraints: boundedList(value.constraints, 'constraints', false),\n    decisions: boundedList(value.decisions, 'decisions', false),\n    verifiedFindings: boundedFindings(value.verifiedFindings),\n    inferredFindings: boundedList(value.inferredFindings, 'inferredFindings', false),\n    unresolvedQuestions: boundedList(value.unresolvedQuestions, 'unresolvedQuestions', false),\n    ...(value.currentPlan === undefined ? {} : { currentPlan: boundedText(value.currentPlan, 'currentPlan', false) }),\n  };\n  if (Buffer.byteLength(JSON.stringify(packet), 'utf8') > MAX_FABLE_PACKET_BYTES) {\n    throw new Error('Fable packet exceeds the bounded packet size.');\n  }\n  return packet;\n}\n\nfunction safeResult(result: FablePlanResult): FablePlanResult {\n  const output = [result.draft, result.review].filter((value): value is string => value !== undefined).join('\\n');\n  if (containsSuspectedCredential(output)) {\n    return {\n      operationId: result.operationId,\n      status: 'failed',\n      stage: 'failed',\n      durationMs: result.durationMs,\n      errorCode: 'unsafe_output',\n    };\n  }\n  return result;\n}\n\nfunction timedOutResult(operationId: string, startedAt: number): FablePlanResult {\n  return {\n    operationId,\n    status: 'timed_out',\n    stage: 'interrupted',\n    durationMs: Math.max(0, Date.now() - startedAt),\n    errorCode: 'timeout',\n  };\n}\n\nexport function createFablePlanFlow(options: FableFlowOptions): FablePlanFlow {\n  const newOperationId = options.newOperationId ?? (() => crypto.randomUUID());\n  let active:\n    | {\n        operationId: string;\n        controller: AbortController;\n        cancelSent: boolean;\n      }\n    | undefined;\n\n  const cancel = (reason = 'Fable operation cancelled.'): void => {\n    const current = active;\n    if (!current) return;\n    if (!current.cancelSent) {\n      current.cancelSent = true;\n      try {\n        options.broker?.cancel(current.operationId, reason);\n      } catch (error) {\n        options.onError?.(error);\n      }\n    }\n    current.controller.abort(new Error(reason));\n  };\n\n  const run = async (value: unknown, signal?: AbortSignal): Promise<FablePlanResult> => {\n    if (active) throw new Error('A Fable operation is already active for this session.');\n    if (!options.isAuthorized()) throw new Error('The Fable capability profile is not authorized.');\n    const packet = sanitizeFablePacket(value);\n    const operationId = `fable-${newOperationId()}`;\n    const startedAt = Date.now();\n    const controller = new AbortController();\n    active = { operationId, controller, cancelSent: false };\n    options.onStage?.('draft');\n\n    const parentAbort = (): void => controller.abort(signal?.reason);\n    if (signal) {\n      signal.addEventListener('abort', parentAbort, { once: true });\n      if (signal.aborted) parentAbort();\n    }\n\n    const brokerRequest: FablePlanRequest = {\n      requester: FABLE_PLAN_REQUESTER,\n      operationId,\n      runtime: FABLE_PLAN_RUNTIME,\n      model: FABLE_PLAN_MODEL,\n      profile: FABLE_PLAN_PROFILE,\n      packet,\n    };\n    let timeout: ReturnType<typeof setTimeout> | undefined;\n    let timeoutTriggered = false;\n    try {\n      if (!options.broker) return timedOutResult(operationId, startedAt);\n      const brokerResult = options.broker.start(brokerRequest, controller.signal);\n      const cancelledResult = new Promise<FablePlanResult>((resolve) => {\n        const onAbort = (): void => {\n          if (timeoutTriggered) return;\n          resolve({\n            operationId,\n            status: 'cancelled',\n            stage: 'cancelled',\n            durationMs: Math.max(0, Date.now() - startedAt),\n            errorCode: 'cancelled',\n          });\n        };\n        controller.signal.addEventListener('abort', onAbort, { once: true });\n      });\n      const timeoutResult =\n        options.timeoutMs === undefined\n          ? undefined\n          : new Promise<FablePlanResult>((resolve) => {\n              timeout = setTimeout(() => {\n                timeoutTriggered = true;\n                cancel('Fable operation timed out.');\n                resolve(timedOutResult(operationId, startedAt));\n              }, options.timeoutMs);\n            });\n      const result =\n        timeoutResult === undefined\n          ? await Promise.race([brokerResult, cancelledResult])\n          : await Promise.race([brokerResult, timeoutResult, cancelledResult]);\n      const safe = safeResult(result);\n      options.onStage?.(\n        safe.status === 'completed' ? 'completed' : safe.status === 'cancelled' ? 'cancelled' : safe.stage,\n      );\n      return safe;\n    } catch (error) {\n      options.onError?.(error);\n      const failure: FablePlanResult = {\n        operationId,\n        status: 'failed',\n        stage: 'failed',\n        durationMs: Math.max(0, Date.now() - startedAt),\n        errorCode: 'unavailable',\n      };\n      options.onStage?.('failed');\n      return failure;\n    } finally {\n      if (timeout) clearTimeout(timeout);\n      if (signal) signal.removeEventListener('abort', parentAbort);\n      active = undefined;\n    }\n  };\n\n  return {\n    run,\n    cancel,\n    isActive: () => active !== undefined,\n  };\n}\n"],"mappings":";;AAEA,MAAa,wBAAwB;AACrC,MAAa,uBAAuB;AACpC,MAAa,qBAAqB;AAClC,MAAa,mBAAmB;AAChC,MAAa,qBAAqB;AAClC,MAAa,yBAAyB;AACtC,MAAa,uBAAuB;AACpC,MAAa,wBAAwB;AAErC,MAAM,kBAAkB;CACtB;CACA;CACA;CACA;AACF;AACA,MAAM,wBAAwB;AAC9B,MAAM,mBAAmB;AACzB,MAAM,yBAAyB;AAgE/B,SAAS,SAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,oBAAoB,OAAwB;CACnD,KAAK,MAAM,aAAa,OAAO;EAC7B,MAAM,OAAO,UAAU,YAAY,CAAC;EACpC,IAAI,SAAS,KAAA,MAAc,QAAQ,yBAAyB,SAAS,mBAAmB,OAAO;CACjG;CACA,OAAO;AACT;AAEA,SAAgB,4BAA4B,OAAwB;CAClE,OAAO,gBAAgB,MAAM,YAAY,QAAQ,KAAK,KAAK,CAAC;AAC9D;AAEA,SAAS,YAAY,OAAgB,OAAe,WAAW,MAAc;CAC3E,IAAI,OAAO,UAAU,UAAU,MAAM,IAAI,MAAM,GAAG,MAAM,mBAAmB;CAC3E,MAAM,OAAO,MAAM,KAAK;CACxB,IAAI,CAAC,QAAQ,UAAU,MAAM,IAAI,MAAM,GAAG,MAAM,oBAAoB;CACpE,IAAIA,YAAAA,OAAO,WAAW,MAAM,MAAM,IAAA,QAA4B,oBAAoB,IAAI,GACpF,MAAM,IAAI,MAAM,GAAG,MAAM,sEAAsE;CAEjG,IAAI,4BAA4B,IAAI,GAAG,MAAM,IAAI,MAAM,GAAG,MAAM,kCAAkC;CAClG,OAAO;AACT;AAEA,SAAS,YAAY,OAAgB,OAAe,WAAW,MAAgB;CAC7E,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,MAAM,IAAI,MAAM,GAAG,MAAM,mBAAmB;CACvE,IAAI,MAAM,SAAA,IAAgC,MAAM,IAAI,MAAM,GAAG,MAAM,iCAAiC;CACpG,MAAM,QAAQ,MAAM,KAAK,MAAM,UAAU,YAAY,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;CAChF,IAAI,YAAY,MAAM,WAAW,GAAG,MAAM,IAAI,MAAM,GAAG,MAAM,iCAAiC;CAC9F,OAAO;AACT;AAEA,SAAS,YAAY,OAAgB,OAAuB;CAC1D,IAAI,OAAO,UAAU,UAAU,MAAM,IAAI,MAAM,GAAG,MAAM,mBAAmB;CAC3E,MAAM,aAAa,MAAM,KAAK;CAC9B,IAAI,CAAC,cAAc,WAAW,SAAS,0BAA0B,oBAAoB,UAAU,GAC7F,MAAM,IAAI,MAAM,GAAG,MAAM,4BAA4B;CAEvD,IAAI,4BAA4B,UAAU,GAAG,MAAM,IAAI,MAAM,GAAG,MAAM,kCAAkC;CACxG,OAAO;AACT;AAEA,SAAS,gBAAgB,OAAoC;CAC3D,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,MAAM,IAAI,MAAM,oCAAoC;CAC/E,IAAI,MAAM,SAAA,IAAgC,MAAM,IAAI,MAAM,kDAAkD;CAC5G,OAAO,MAAM,KAAK,MAAM,UAAU;EAChC,IAAI,CAAC,SAAS,IAAI,GAAG,MAAM,IAAI,MAAM,oBAAoB,MAAM,qBAAqB;EAEpF,IADa,OAAO,KAAK,IAClB,CAAC,CAAC,MAAM,QAAQ,QAAQ,UAAU,QAAQ,SAAS,GACxD,MAAM,IAAI,MAAM,oBAAoB,MAAM,iCAAiC;EAE7E,OAAO;GACL,MAAM,YAAY,KAAK,MAAM,oBAAoB,MAAM,OAAO;GAC9D,SAAS,YAAY,KAAK,SAAS,oBAAoB,MAAM,UAAU;EACzE;CACF,CAAC;AACH;AAEA,SAAS,kBAAkB,OAAgC,MAAyB,OAAqB;CACvG,MAAM,UAAU,IAAI,IAAI,IAAI;CAC5B,MAAM,aAAa,OAAO,KAAK,KAAK,CAAC,CAAC,MAAM,QAAQ,CAAC,QAAQ,IAAI,GAAG,CAAC;CACrE,IAAI,YAAY,MAAM,IAAI,MAAM,GAAG,MAAM,+BAA+B,WAAW,GAAG;AACxF;AAEA,SAAgB,oBAAoB,OAAiC;CACnE,IAAI,CAAC,SAAS,KAAK,GAAG,MAAM,IAAI,MAAM,iCAAiC;CACvE,kBACE,OACA;EAAC;EAAQ;EAAe;EAAa;EAAoB;EAAoB;EAAuB;CAAa,GACjH,cACF;CACA,MAAM,SAA0B;EAC9B,MAAM,YAAY,MAAM,MAAM,MAAM;EACpC,aAAa,YAAY,MAAM,aAAa,eAAe,KAAK;EAChE,WAAW,YAAY,MAAM,WAAW,aAAa,KAAK;EAC1D,kBAAkB,gBAAgB,MAAM,gBAAgB;EACxD,kBAAkB,YAAY,MAAM,kBAAkB,oBAAoB,KAAK;EAC/E,qBAAqB,YAAY,MAAM,qBAAqB,uBAAuB,KAAK;EACxF,GAAI,MAAM,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,YAAY,MAAM,aAAa,eAAe,KAAK,EAAE;CACjH;CACA,IAAIA,YAAAA,OAAO,WAAW,KAAK,UAAU,MAAM,GAAG,MAAM,IAAA,OAClD,MAAM,IAAI,MAAM,+CAA+C;CAEjE,OAAO;AACT;AAEA,SAAS,WAAW,QAA0C;CAE5D,IAAI,4BADW,CAAC,OAAO,OAAO,OAAO,MAAM,CAAC,CAAC,QAAQ,UAA2B,UAAU,KAAA,CAAS,CAAC,CAAC,KAAK,IACrE,CAAC,GACpC,OAAO;EACL,aAAa,OAAO;EACpB,QAAQ;EACR,OAAO;EACP,YAAY,OAAO;EACnB,WAAW;CACb;CAEF,OAAO;AACT;AAEA,SAAS,eAAe,aAAqB,WAAoC;CAC/E,OAAO;EACL;EACA,QAAQ;EACR,OAAO;EACP,YAAY,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,SAAS;EAC9C,WAAW;CACb;AACF;AAEA,SAAgB,oBAAoB,SAA0C;CAC5E,MAAM,iBAAiB,QAAQ,yBAAyB,OAAO,WAAW;CAC1E,IAAI;CAQJ,MAAM,UAAU,SAAS,iCAAuC;EAC9D,MAAM,UAAU;EAChB,IAAI,CAAC,SAAS;EACd,IAAI,CAAC,QAAQ,YAAY;GACvB,QAAQ,aAAa;GACrB,IAAI;IACF,QAAQ,QAAQ,OAAO,QAAQ,aAAa,MAAM;GACpD,SAAS,OAAO;IACd,QAAQ,UAAU,KAAK;GACzB;EACF;EACA,QAAQ,WAAW,MAAM,IAAI,MAAM,MAAM,CAAC;CAC5C;CAEA,MAAM,MAAM,OAAO,OAAgB,WAAmD;EACpF,IAAI,QAAQ,MAAM,IAAI,MAAM,uDAAuD;EACnF,IAAI,CAAC,QAAQ,aAAa,GAAG,MAAM,IAAI,MAAM,iDAAiD;EAC9F,MAAM,SAAS,oBAAoB,KAAK;EACxC,MAAM,cAAc,SAAS,eAAe;EAC5C,MAAM,YAAY,KAAK,IAAI;EAC3B,MAAM,aAAa,IAAI,gBAAgB;EACvC,SAAS;GAAE;GAAa;GAAY,YAAY;EAAM;EACtD,QAAQ,UAAU,OAAO;EAEzB,MAAM,oBAA0B,WAAW,MAAM,QAAQ,MAAM;EAC/D,IAAI,QAAQ;GACV,OAAO,iBAAiB,SAAS,aAAa,EAAE,MAAM,KAAK,CAAC;GAC5D,IAAI,OAAO,SAAS,YAAY;EAClC;EAEA,MAAM,gBAAkC;GACtC,WAAW;GACX;GACA,SAAS;GACT,OAAO;GACP,SAAS;GACT;EACF;EACA,IAAI;EACJ,IAAI,mBAAmB;EACvB,IAAI;GACF,IAAI,CAAC,QAAQ,QAAQ,OAAO,eAAe,aAAa,SAAS;GACjE,MAAM,eAAe,QAAQ,OAAO,MAAM,eAAe,WAAW,MAAM;GAC1E,MAAM,kBAAkB,IAAI,SAA0B,YAAY;IAChE,MAAM,gBAAsB;KAC1B,IAAI,kBAAkB;KACtB,QAAQ;MACN;MACA,QAAQ;MACR,OAAO;MACP,YAAY,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,SAAS;MAC9C,WAAW;KACb,CAAC;IACH;IACA,WAAW,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;GACrE,CAAC;GACD,MAAM,gBACJ,QAAQ,cAAc,KAAA,IAClB,KAAA,IACA,IAAI,SAA0B,YAAY;IACxC,UAAU,iBAAiB;KACzB,mBAAmB;KACnB,OAAO,4BAA4B;KACnC,QAAQ,eAAe,aAAa,SAAS,CAAC;IAChD,GAAG,QAAQ,SAAS;GACtB,CAAC;GAKP,MAAM,OAAO,WAHX,kBAAkB,KAAA,IACd,MAAM,QAAQ,KAAK,CAAC,cAAc,eAAe,CAAC,IAClD,MAAM,QAAQ,KAAK;IAAC;IAAc;IAAe;GAAe,CAAC,CACzC;GAC9B,QAAQ,UACN,KAAK,WAAW,cAAc,cAAc,KAAK,WAAW,cAAc,cAAc,KAAK,KAC/F;GACA,OAAO;EACT,SAAS,OAAO;GACd,QAAQ,UAAU,KAAK;GACvB,MAAM,UAA2B;IAC/B;IACA,QAAQ;IACR,OAAO;IACP,YAAY,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,SAAS;IAC9C,WAAW;GACb;GACA,QAAQ,UAAU,QAAQ;GAC1B,OAAO;EACT,UAAU;GACR,IAAI,SAAS,aAAa,OAAO;GACjC,IAAI,QAAQ,OAAO,oBAAoB,SAAS,WAAW;GAC3D,SAAS,KAAA;EACX;CACF;CAEA,OAAO;EACL;EACA;EACA,gBAAgB,WAAW,KAAA;CAC7B;AACF"}