@refrainai/cli 0.4.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.
Files changed (69) hide show
  1. package/dist/ai-model-FM6GWCID.js +37 -0
  2. package/dist/ai-model-FM6GWCID.js.map +1 -0
  3. package/dist/chunk-2BVDAJZT.js +236 -0
  4. package/dist/chunk-2BVDAJZT.js.map +1 -0
  5. package/dist/chunk-2H7UOFLK.js +11 -0
  6. package/dist/chunk-2H7UOFLK.js.map +1 -0
  7. package/dist/chunk-7UCVPKD4.js +902 -0
  8. package/dist/chunk-7UCVPKD4.js.map +1 -0
  9. package/dist/chunk-AG3CFMYU.js +36 -0
  10. package/dist/chunk-AG3CFMYU.js.map +1 -0
  11. package/dist/chunk-CLYJHKPY.js +1131 -0
  12. package/dist/chunk-CLYJHKPY.js.map +1 -0
  13. package/dist/chunk-D5SI2PHK.js +74 -0
  14. package/dist/chunk-D5SI2PHK.js.map +1 -0
  15. package/dist/chunk-DJVUITRB.js +9084 -0
  16. package/dist/chunk-DJVUITRB.js.map +1 -0
  17. package/dist/chunk-H47NWH7N.js +4427 -0
  18. package/dist/chunk-H47NWH7N.js.map +1 -0
  19. package/dist/chunk-HQDXLWAY.js +109 -0
  20. package/dist/chunk-HQDXLWAY.js.map +1 -0
  21. package/dist/chunk-IGFCYKHC.js +1974 -0
  22. package/dist/chunk-IGFCYKHC.js.map +1 -0
  23. package/dist/chunk-RT664YIO.js +245 -0
  24. package/dist/chunk-RT664YIO.js.map +1 -0
  25. package/dist/chunk-RYIJPYM3.js +164 -0
  26. package/dist/chunk-RYIJPYM3.js.map +1 -0
  27. package/dist/chunk-TDSM3UXI.js +40 -0
  28. package/dist/chunk-TDSM3UXI.js.map +1 -0
  29. package/dist/chunk-UGPXCQY3.js +778 -0
  30. package/dist/chunk-UGPXCQY3.js.map +1 -0
  31. package/dist/chunk-VPK2MQAZ.js +589 -0
  32. package/dist/chunk-VPK2MQAZ.js.map +1 -0
  33. package/dist/chunk-WEYR56ZN.js +953 -0
  34. package/dist/chunk-WEYR56ZN.js.map +1 -0
  35. package/dist/chunk-XMFCXPYU.js +275 -0
  36. package/dist/chunk-XMFCXPYU.js.map +1 -0
  37. package/dist/chunk-Z33FCOTZ.js +251 -0
  38. package/dist/chunk-Z33FCOTZ.js.map +1 -0
  39. package/dist/cli.js +59 -0
  40. package/dist/cli.js.map +1 -0
  41. package/dist/compose-MTSIJY5D.js +547 -0
  42. package/dist/compose-MTSIJY5D.js.map +1 -0
  43. package/dist/config-ZSUNCFXR.js +9 -0
  44. package/dist/config-ZSUNCFXR.js.map +1 -0
  45. package/dist/fix-runbook-ZSBOTLC2.js +294 -0
  46. package/dist/fix-runbook-ZSBOTLC2.js.map +1 -0
  47. package/dist/google-sheets-DRWIVEVC.js +482 -0
  48. package/dist/google-sheets-DRWIVEVC.js.map +1 -0
  49. package/dist/registry-LZLYTNDJ.js +17 -0
  50. package/dist/registry-LZLYTNDJ.js.map +1 -0
  51. package/dist/runbook-data-helpers-KRR2SH76.js +16 -0
  52. package/dist/runbook-data-helpers-KRR2SH76.js.map +1 -0
  53. package/dist/runbook-executor-K7T6RJWJ.js +1480 -0
  54. package/dist/runbook-executor-K7T6RJWJ.js.map +1 -0
  55. package/dist/runbook-generator-MPXJBQ5N.js +800 -0
  56. package/dist/runbook-generator-MPXJBQ5N.js.map +1 -0
  57. package/dist/runbook-schema-3T6TP3JJ.js +35 -0
  58. package/dist/runbook-schema-3T6TP3JJ.js.map +1 -0
  59. package/dist/runbook-store-G5GUOWRR.js +11 -0
  60. package/dist/runbook-store-G5GUOWRR.js.map +1 -0
  61. package/dist/schema-5G6UQSPT.js +91 -0
  62. package/dist/schema-5G6UQSPT.js.map +1 -0
  63. package/dist/server-AG3LXQBI.js +8778 -0
  64. package/dist/server-AG3LXQBI.js.map +1 -0
  65. package/dist/tenant-ai-config-QPFEJUVJ.js +14 -0
  66. package/dist/tenant-ai-config-QPFEJUVJ.js.map +1 -0
  67. package/dist/yaml-patcher-VGUS2JGH.js +15 -0
  68. package/dist/yaml-patcher-VGUS2JGH.js.map +1 -0
  69. package/package.json +37 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/server/store/runbook-store.ts","../../../src/server/store/runbook-version-store.ts"],"sourcesContent":["/**\n * RunbookStore — Runbook テーブルの CRUD + VersionStore 委譲\n *\n * Runbook 単位の操作(作成・一覧・更新・削除)を担当。\n * バージョン操作は this.versions (VersionStore) に委譲する。\n */\n\nimport { eq, and, desc, sql, count } from \"drizzle-orm\";\nimport type { getDb } from \"../db/client.js\";\nimport {\n runbooks,\n runbookVersions,\n runbookSettings,\n runbookVariables,\n runbookSecrets,\n runbookSteps,\n jobs,\n} from \"../db/schema.js\";\nimport type { ParsedRunbook } from \"../../runbook-executor/types.js\";\nimport { VersionStore, type VersionUpdateData } from \"./runbook-version-store.js\";\nimport { buildFlatRunbook, insertSteps } from \"./runbook-data-helpers.js\";\nimport { isEditable, resolveDisplayStatus } from \"./version-lifecycle.js\";\nimport type { VersionStatus } from \"./version-lifecycle.js\";\n\ntype Db = ReturnType<typeof getDb>;\ntype VariableSource = \"prompt\" | \"fixed\" | \"context\" | \"env\" | \"expression\" | \"data\";\n\n// re-export for backward compatibility\nexport type { VersionStatus } from \"./version-lifecycle.js\";\nexport type { VersionUpdateData } from \"./runbook-version-store.js\";\n\nexport interface RunbookInsertData {\n tenantId: string;\n createdBy?: string;\n runbook: ParsedRunbook;\n secrets?: Record<string, string>;\n context: string;\n settings?: RunbookSettingsOverride;\n}\n\nexport interface RunbookSettingsOverride {\n defaultTimeout?: number;\n pauseBetweenSteps?: number;\n stopOnError?: boolean;\n stepDelay?: number;\n enableSelectorCache?: boolean;\n enableAgentFallback?: boolean;\n enableVisionFallback?: boolean;\n modelId?: string;\n modelProvider?: string;\n}\n\nexport interface RunbookUpdateData {\n runbook?: ParsedRunbook;\n secrets?: Record<string, string>;\n context?: string;\n settings?: RunbookSettingsOverride;\n variables?: Record<string, { source: VariableSource; description?: string; required: boolean; sensitive: boolean; value?: string }>;\n skipStatusReset?: boolean;\n}\n\n// レガシー互換: 旧 RunbookStatus のエイリアス\nexport type RunbookStatus = \"draft\" | \"pending_verification\" | \"active\" | \"disabled\";\n\nexport class RunbookStore {\n public readonly versions: VersionStore;\n\n constructor(private db: Db) {\n this.versions = new VersionStore(db);\n }\n\n // ── 作成 ──\n\n /**\n * Runbook + 初期バージョン(v1)を作成する。\n * ParsedRunbook を含むフル作成。ステータスは pending_verification。\n */\n async insert(data: RunbookInsertData) {\n const { tenantId, createdBy, runbook, secrets, context, settings } = data;\n\n return await this.db.transaction(async (tx) => {\n // 1. Runbook(アイデンティティ)作成\n const [rbRow] = await tx\n .insert(runbooks)\n .values({\n tenantId,\n title: runbook.title,\n createdBy: createdBy ?? null,\n })\n .returning();\n\n // 2. 初期バージョン作成(VersionStore に委譲)\n const verRow = await this.versions.createInitialVersion(tx, rbRow.id, {\n goal: runbook.metadata.goal,\n startUrl: runbook.metadata.startUrl,\n context: context ?? null,\n generatedAt: runbook.metadata.generatedAt,\n createdBy: createdBy ?? null,\n settings,\n secrets,\n variables: runbook.variables,\n steps: runbook.steps,\n });\n\n // 3. activeVersionId を設定\n await tx\n .update(runbooks)\n .set({ activeVersionId: verRow.id })\n .where(eq(runbooks.id, rbRow.id));\n\n return { ...rbRow, activeVersionId: verRow.id };\n });\n }\n\n /**\n * Draft の Runbook + 初期 draft バージョンを作成する。\n */\n async insertDraft(data: {\n tenantId: string;\n createdBy?: string;\n title: string;\n goal?: string;\n startUrl?: string;\n context?: string;\n secrets?: Record<string, string>;\n variables?: Record<string, { source: VariableSource; description?: string; required: boolean; sensitive: boolean; value?: string }>;\n }) {\n return await this.db.transaction(async (tx) => {\n // 1. Runbook 作成(activeVersionId は null — draft はまだ公開されていない)\n const [rbRow] = await tx\n .insert(runbooks)\n .values({\n tenantId: data.tenantId,\n title: data.title,\n createdBy: data.createdBy ?? null,\n })\n .returning();\n\n // 2. 初期バージョン作成(steps なし → draft)\n const verRow = await this.versions.createInitialVersion(tx, rbRow.id, {\n goal: data.goal ?? \"\",\n startUrl: data.startUrl ?? null,\n context: data.context ?? null,\n createdBy: data.createdBy ?? null,\n secrets: data.secrets,\n variables: data.variables,\n });\n\n return { ...rbRow, versionId: verRow.id };\n });\n }\n\n // ── クエリ ──\n\n /**\n * Runbook 詳細取得(active バージョンの情報を含む)\n * 旧 API との互換性を維持するためにフラット構造で返す。\n */\n async findById(tenantId: string, id: string) {\n const row = await this.db.query.runbooks.findFirst({\n where: and(eq(runbooks.id, id), eq(runbooks.tenantId, tenantId)),\n });\n if (!row) return null;\n\n // active バージョンまたは最新バージョンのデータを読み込む\n const versionId = row.activeVersionId;\n if (!versionId) {\n // active バージョンがない場合、最新の draft を探す\n const latestDraft = await this.db.query.runbookVersions.findFirst({\n where: eq(runbookVersions.runbookId, id),\n orderBy: [desc(runbookVersions.versionNumber)],\n });\n if (!latestDraft) {\n const status = row.disabled ? \"disabled\" as const : \"draft\" as const;\n return {\n ...row,\n goal: \"\",\n startUrl: null,\n context: null,\n generatedAt: null,\n status,\n verificationJobId: null,\n verificationJobStatus: null,\n displayStatus: resolveDisplayStatus(status, null, null),\n settings: null,\n variables: [],\n secrets: [],\n steps: [],\n activeVersionId: null,\n currentVersionId: null,\n };\n }\n return await buildFlatRunbook(this.db, row, latestDraft);\n }\n\n const [ver] = await this.db\n .select()\n .from(runbookVersions)\n .where(eq(runbookVersions.id, versionId));\n if (!ver) return null;\n\n return await buildFlatRunbook(this.db, row, ver);\n }\n\n /**\n * Runbook 一覧\n */\n async list(\n tenantId: string,\n opts: { limit?: number; offset?: number; status?: RunbookStatus; includeDisabled?: boolean } = {},\n ) {\n const { limit = 50, offset = 0, status, includeDisabled = false } = opts;\n\n const conditions = [eq(runbooks.tenantId, tenantId)];\n\n if (status === \"disabled\") {\n conditions.push(eq(runbooks.disabled, true));\n } else if (status) {\n conditions.push(eq(runbooks.disabled, false));\n } else if (!includeDisabled) {\n conditions.push(eq(runbooks.disabled, false));\n }\n\n const where = and(...conditions);\n\n const rows = await this.db\n .select({\n id: runbooks.id,\n title: runbooks.title,\n disabled: runbooks.disabled,\n activeVersionId: runbooks.activeVersionId,\n createdAt: runbooks.createdAt,\n updatedAt: runbooks.updatedAt,\n goal: sql<string>`COALESCE((\n SELECT rv.goal FROM runbook_versions rv\n WHERE rv.id = ${runbooks.activeVersionId}\n ), (\n SELECT rv.goal FROM runbook_versions rv\n WHERE rv.runbook_id = ${runbooks.id}\n ORDER BY rv.version_number DESC LIMIT 1\n ), '')`.as(\"goal\"),\n startUrl: sql<string | null>`COALESCE((\n SELECT rv.start_url FROM runbook_versions rv\n WHERE rv.id = ${runbooks.activeVersionId}\n ), (\n SELECT rv.start_url FROM runbook_versions rv\n WHERE rv.runbook_id = ${runbooks.id}\n ORDER BY rv.version_number DESC LIMIT 1\n ))`.as(\"startUrl\"),\n generatedAt: sql<string | null>`COALESCE((\n SELECT rv.generated_at FROM runbook_versions rv\n WHERE rv.id = ${runbooks.activeVersionId}\n ), (\n SELECT rv.generated_at FROM runbook_versions rv\n WHERE rv.runbook_id = ${runbooks.id}\n ORDER BY rv.version_number DESC LIMIT 1\n ))`.as(\"generatedAt\"),\n versionStatus: sql<string | null>`COALESCE((\n SELECT rv.status FROM runbook_versions rv\n WHERE rv.id = ${runbooks.activeVersionId}\n ), (\n SELECT rv.status FROM runbook_versions rv\n WHERE rv.runbook_id = ${runbooks.id}\n ORDER BY rv.version_number DESC LIMIT 1\n ))`.as(\"versionStatus\"),\n verificationJobId: sql<string | null>`COALESCE((\n SELECT rv.verification_job_id FROM runbook_versions rv\n WHERE rv.id = ${runbooks.activeVersionId}\n ), (\n SELECT rv.verification_job_id FROM runbook_versions rv\n WHERE rv.runbook_id = ${runbooks.id}\n ORDER BY rv.version_number DESC LIMIT 1\n ))`.as(\"verificationJobId\"),\n stepsCount: sql<number>`COALESCE((\n SELECT count(*)::int FROM runbook_steps rs\n JOIN runbook_versions rv ON rv.id = rs.version_id\n WHERE rv.id = COALESCE(${runbooks.activeVersionId}, (\n SELECT rv2.id FROM runbook_versions rv2\n WHERE rv2.runbook_id = ${runbooks.id}\n ORDER BY rv2.version_number DESC LIMIT 1\n ))\n AND rs.parent_step_id IS NULL\n ), 0)`.as(\"stepsCount\"),\n lastJobStatus: sql<string | null>`(\n SELECT ${jobs.status} FROM ${jobs}\n WHERE ${jobs.runbookId} = ${runbooks.id}\n AND ${jobs.mode} IN ('execute', 'self_heal')\n ORDER BY ${jobs.createdAt} DESC\n LIMIT 1\n )`.as(\"lastJobStatus\"),\n lastJobCompletedAt: sql<string | null>`(\n SELECT ${jobs.completedAt} FROM ${jobs}\n WHERE ${jobs.runbookId} = ${runbooks.id}\n AND ${jobs.mode} IN ('execute', 'self_heal')\n ORDER BY ${jobs.createdAt} DESC\n LIMIT 1\n )`.as(\"lastJobCompletedAt\"),\n verificationJobStatus: sql<string | null>`(\n SELECT j.status FROM jobs j\n WHERE j.id = COALESCE((\n SELECT rv.verification_job_id FROM runbook_versions rv\n WHERE rv.id = ${runbooks.activeVersionId}\n ), (\n SELECT rv.verification_job_id FROM runbook_versions rv\n WHERE rv.runbook_id = ${runbooks.id}\n ORDER BY rv.version_number DESC LIMIT 1\n ))\n )`.as(\"verificationJobStatus\"),\n versionCount: sql<number>`(\n SELECT count(*)::int FROM runbook_versions rv\n WHERE rv.runbook_id = ${runbooks.id}\n )`.as(\"versionCount\"),\n hasDraft: sql<boolean>`EXISTS(\n SELECT 1 FROM runbook_versions rv\n WHERE rv.runbook_id = ${runbooks.id} AND rv.status = 'draft'\n )`.as(\"hasDraft\"),\n })\n .from(runbooks)\n .where(where)\n .orderBy(desc(runbooks.createdAt))\n .limit(limit)\n .offset(offset);\n\n // ステータスフィルタ(バージョンステータス)\n let filteredRows = rows;\n if (status && status !== \"disabled\") {\n const mappedStatus = status === \"active\" ? \"active\" : status === \"pending_verification\" ? \"pending_verification\" : status;\n filteredRows = rows.filter((r) => r.versionStatus === mappedStatus);\n }\n\n const items = filteredRows.map((r) => {\n const itemStatus = r.disabled ? \"disabled\" as const : (r.versionStatus as RunbookStatus) ?? \"draft\";\n return {\n id: r.id,\n title: r.title,\n goal: r.goal ?? \"\",\n startUrl: r.startUrl,\n generatedAt: r.generatedAt ?? \"\",\n status: itemStatus,\n verificationJobId: r.verificationJobId,\n verificationJobStatus: r.verificationJobStatus,\n displayStatus: resolveDisplayStatus(itemStatus, r.verificationJobId, r.verificationJobStatus),\n createdAt: r.createdAt,\n updatedAt: r.updatedAt,\n stepsCount: r.stepsCount,\n lastJobStatus: r.lastJobStatus,\n lastJobCompletedAt: r.lastJobCompletedAt,\n versionCount: r.versionCount,\n hasDraft: r.hasDraft,\n activeVersionId: r.activeVersionId,\n };\n });\n\n const [totalResult] = await this.db\n .select({ count: count() })\n .from(runbooks)\n .where(where);\n\n return { items, total: totalResult.count };\n }\n\n // ── 更新 ──\n\n /**\n * Runbook の active バージョンを更新する(旧 API 互換)。\n */\n async update(tenantId: string, id: string, data: RunbookUpdateData) {\n const existing = await this.findById(tenantId, id);\n if (!existing) return null;\n\n const versionId = existing.currentVersionId;\n if (!versionId) return null;\n\n return await this.db.transaction(async (tx) => {\n if (data.runbook) {\n const rb = data.runbook;\n const versionStatus = existing.status;\n const statusReset =\n versionStatus === \"active\" && !data.skipStatusReset\n ? { status: \"pending_verification\" as const, verificationJobId: null }\n : versionStatus === \"draft\"\n ? { status: \"pending_verification\" as const }\n : {};\n\n await tx\n .update(runbookVersions)\n .set({\n goal: rb.metadata.goal,\n startUrl: rb.metadata.startUrl,\n context: data.context ?? existing.context,\n generatedAt: rb.metadata.generatedAt,\n ...statusReset,\n })\n .where(eq(runbookVersions.id, versionId));\n\n await tx\n .update(runbooks)\n .set({ title: rb.title })\n .where(eq(runbooks.id, id));\n\n const nextVariables = data.variables ?? rb.variables;\n if (nextVariables !== undefined) {\n await tx.delete(runbookVariables).where(eq(runbookVariables.versionId, versionId));\n const vars = Object.entries(nextVariables).map(([name, def]) => ({\n versionId,\n name,\n source: def.source,\n description: def.description ?? null,\n required: def.required,\n sensitive: def.sensitive,\n value: def.value ?? null,\n }));\n if (vars.length > 0) {\n await tx.insert(runbookVariables).values(vars);\n }\n }\n\n await tx.delete(runbookSteps).where(eq(runbookSteps.versionId, versionId));\n await insertSteps(tx, versionId, rb.steps, null);\n } else if (data.context !== undefined) {\n await tx\n .update(runbookVersions)\n .set({ context: data.context })\n .where(eq(runbookVersions.id, versionId));\n }\n\n if (!data.runbook && data.variables !== undefined) {\n await tx.delete(runbookVariables).where(eq(runbookVariables.versionId, versionId));\n const vars = Object.entries(data.variables).map(([name, def]) => ({\n versionId,\n name,\n source: def.source,\n description: def.description ?? null,\n required: def.required,\n sensitive: def.sensitive,\n value: def.value ?? null,\n }));\n if (vars.length > 0) {\n await tx.insert(runbookVariables).values(vars);\n }\n }\n\n if (data.settings !== undefined) {\n await tx.delete(runbookSettings).where(eq(runbookSettings.versionId, versionId));\n if (data.settings) {\n await tx.insert(runbookSettings).values({ versionId, ...data.settings });\n }\n }\n\n if (data.secrets !== undefined) {\n await tx.delete(runbookSecrets).where(eq(runbookSecrets.versionId, versionId));\n const secretRows = Object.entries(data.secrets).map(([key, val]) => ({\n versionId,\n key,\n encryptedValue: val,\n }));\n if (secretRows.length > 0) {\n await tx.insert(runbookSecrets).values(secretRows);\n }\n }\n\n return await this.findById(tenantId, id);\n });\n }\n\n /**\n * updateDraft: draft/pending_verification ステータスのバージョンを更新\n */\n async updateDraft(\n tenantId: string,\n id: string,\n data: {\n title?: string;\n goal?: string;\n startUrl?: string;\n context?: string;\n settings?: RunbookSettingsOverride;\n secrets?: Record<string, string>;\n variables?: Record<string, { source: VariableSource; description?: string; required: boolean; sensitive: boolean; value?: string }>;\n },\n ) {\n const existing = await this.findById(tenantId, id);\n if (!existing) return null;\n\n const versionId = existing.currentVersionId;\n if (!versionId) return null;\n if (!isEditable(existing.versionStatus as VersionStatus)) return null;\n\n const result = await this.versions.updateVersion(tenantId, id, versionId, {\n ...data,\n });\n if (!result) return null;\n\n // FlatRunbook 形式で返す(旧 API 互換)\n return await this.findById(tenantId, id);\n }\n\n /**\n * completeDraft: draft → pending_verification\n */\n async completeDraft(\n tenantId: string,\n id: string,\n data: {\n title?: string;\n goal?: string;\n startUrl?: string;\n context?: string;\n settings?: RunbookSettingsOverride;\n secrets?: Record<string, string>;\n variables?: Record<string, { source: VariableSource; description?: string; required: boolean; sensitive: boolean; value?: string }>;\n },\n ) {\n const existing = await this.findById(tenantId, id);\n if (!existing) return null;\n\n const versionId = existing.currentVersionId;\n if (!versionId) return null;\n\n const result = await this.versions.completeVersion(tenantId, id, versionId, data);\n if (!result) return null;\n\n return await this.findById(tenantId, id);\n }\n\n /**\n * updateStatus: 旧 API 互換。disabled フラグとバージョンステータスを操作。\n */\n async updateStatus(tenantId: string, id: string, status: RunbookStatus) {\n if (status === \"disabled\") {\n const result = await this.db\n .update(runbooks)\n .set({ disabled: true })\n .where(and(eq(runbooks.id, id), eq(runbooks.tenantId, tenantId)))\n .returning({ id: runbooks.id });\n return result.length > 0;\n }\n\n if (status === \"active\") {\n const rb = await this.db.query.runbooks.findFirst({\n where: and(eq(runbooks.id, id), eq(runbooks.tenantId, tenantId)),\n });\n if (!rb) return false;\n\n if (rb.disabled) {\n await this.db\n .update(runbooks)\n .set({ disabled: false })\n .where(eq(runbooks.id, id));\n return true;\n }\n\n if (rb.activeVersionId) {\n const [ver] = await this.db\n .select()\n .from(runbookVersions)\n .where(eq(runbookVersions.id, rb.activeVersionId));\n if (ver && ver.status === \"pending_verification\") {\n await this.db\n .update(runbookVersions)\n .set({ status: \"active\", publishedAt: new Date() })\n .where(eq(runbookVersions.id, rb.activeVersionId));\n return true;\n }\n }\n\n const latestVer = await this.db.query.runbookVersions.findFirst({\n where: and(\n eq(runbookVersions.runbookId, id),\n eq(runbookVersions.status, \"pending_verification\"),\n ),\n orderBy: [desc(runbookVersions.versionNumber)],\n });\n if (latestVer) {\n await this.db\n .update(runbookVersions)\n .set({ status: \"active\", publishedAt: new Date() })\n .where(eq(runbookVersions.id, latestVer.id));\n await this.db\n .update(runbooks)\n .set({ activeVersionId: latestVer.id })\n .where(eq(runbooks.id, id));\n return true;\n }\n return false;\n }\n\n const rb = await this.db.query.runbooks.findFirst({\n where: and(eq(runbooks.id, id), eq(runbooks.tenantId, tenantId)),\n });\n if (!rb) return false;\n\n const targetVersionId = rb.activeVersionId;\n if (!targetVersionId) {\n const latestVer = await this.db.query.runbookVersions.findFirst({\n where: eq(runbookVersions.runbookId, id),\n orderBy: [desc(runbookVersions.versionNumber)],\n });\n if (latestVer) {\n await this.db\n .update(runbookVersions)\n .set({ status })\n .where(eq(runbookVersions.id, latestVer.id));\n return true;\n }\n return false;\n }\n\n await this.db\n .update(runbookVersions)\n .set({ status })\n .where(eq(runbookVersions.id, targetVersionId));\n return true;\n }\n\n /**\n * getStatus: 旧 API 互換\n */\n async getStatus(tenantId: string, id: string): Promise<RunbookStatus | null> {\n const rb = await this.db.query.runbooks.findFirst({\n where: and(eq(runbooks.id, id), eq(runbooks.tenantId, tenantId)),\n columns: { id: true, disabled: true, activeVersionId: true },\n });\n if (!rb) return null;\n if (rb.disabled) return \"disabled\";\n\n const verId = rb.activeVersionId;\n if (verId) {\n const [ver] = await this.db\n .select({ status: runbookVersions.status })\n .from(runbookVersions)\n .where(eq(runbookVersions.id, verId));\n if (ver) return ver.status as RunbookStatus;\n }\n\n const latestVer = await this.db.query.runbookVersions.findFirst({\n where: eq(runbookVersions.runbookId, id),\n orderBy: [desc(runbookVersions.versionNumber)],\n columns: { status: true },\n });\n return (latestVer?.status as RunbookStatus) ?? \"draft\";\n }\n\n /**\n * setVerificationJob: 旧 API 互換\n */\n async setVerificationJob(tenantId: string, runbookId: string, jobId: string) {\n const rb = await this.db.query.runbooks.findFirst({\n where: and(eq(runbooks.id, runbookId), eq(runbooks.tenantId, tenantId)),\n });\n if (!rb) return false;\n\n const targetVer = await this.db.query.runbookVersions.findFirst({\n where: eq(runbookVersions.runbookId, runbookId),\n orderBy: [desc(runbookVersions.versionNumber)],\n });\n if (!targetVer) return false;\n\n return await this.versions.setVerificationJob(targetVer.id, jobId);\n }\n\n /**\n * clearVerificationJob: 旧 API 互換\n */\n async clearVerificationJob(tenantId: string, runbookId: string) {\n const targetVer = await this.db.query.runbookVersions.findFirst({\n where: eq(runbookVersions.runbookId, runbookId),\n orderBy: [desc(runbookVersions.versionNumber)],\n });\n if (!targetVer) return false;\n return await this.versions.clearVerificationJob(targetVer.id);\n }\n\n // ── ライフサイクル ──\n\n /**\n * duplicate: Runbook をコピーする(active バージョンから draft 作成)\n */\n async duplicate(tenantId: string, sourceId: string, createdBy?: string): Promise<{ id: string } | null> {\n const source = await this.findById(tenantId, sourceId);\n if (!source) return null;\n\n return await this.db.transaction(async (tx) => {\n const [newRb] = await tx.insert(runbooks).values({\n tenantId,\n title: `${source.title} (Copy)`,\n createdBy: createdBy ?? null,\n }).returning();\n\n // 初期バージョン作成(コピー元データ付き)\n const verRow = await this.versions.createInitialVersion(tx, newRb.id, {\n goal: source.goal,\n startUrl: source.startUrl,\n context: source.context,\n generatedAt: new Date().toISOString(),\n createdBy: createdBy ?? null,\n });\n\n // コピー元バージョンからデータをコピー\n if (source.currentVersionId) {\n const { copyVersionData } = await import(\"./runbook-data-helpers.js\");\n await copyVersionData(tx, source.currentVersionId, verRow.id);\n }\n\n return { id: newRb.id };\n });\n }\n\n /**\n * patchSteps: ステップの部分更新(最新バージョン対象)\n */\n async patchSteps(\n tenantId: string,\n runbookId: string,\n patches: Array<{ id: string; description?: string; riskLevel?: string; requiresConfirmation?: boolean }>,\n ): Promise<boolean> {\n const targetVer = await this.db.query.runbookVersions.findFirst({\n where: eq(runbookVersions.runbookId, runbookId),\n orderBy: [desc(runbookVersions.versionNumber)],\n });\n if (!targetVer) return false;\n\n return await this.versions.patchSteps(tenantId, runbookId, targetVer.id, patches);\n }\n\n /**\n * delete: Runbook を削除(CASCADE で全バージョン・子テーブルも削除)\n */\n async delete(tenantId: string, id: string): Promise<boolean> {\n const result = await this.db\n .delete(runbooks)\n .where(and(eq(runbooks.id, id), eq(runbooks.tenantId, tenantId)))\n .returning({ id: runbooks.id });\n return result.length > 0;\n }\n\n /**\n * disable: Runbook を無効化\n */\n async disable(tenantId: string, id: string): Promise<boolean> {\n const result = await this.db\n .update(runbooks)\n .set({ disabled: true })\n .where(and(eq(runbooks.id, id), eq(runbooks.tenantId, tenantId)))\n .returning({ id: runbooks.id });\n return result.length > 0;\n }\n\n /**\n * enable: Runbook を有効化\n */\n async enable(tenantId: string, id: string): Promise<boolean> {\n const result = await this.db\n .update(runbooks)\n .set({ disabled: false })\n .where(and(eq(runbooks.id, id), eq(runbooks.tenantId, tenantId)))\n .returning({ id: runbooks.id });\n return result.length > 0;\n }\n}\n","/**\n * VersionStore — バージョン操作を一元管理\n *\n * 3つの作成パターン → createInitialVersion / createVersionFromActive\n * 3つの更新パターン → updateVersion\n * 2つの完了パターン → completeVersion\n */\n\nimport { eq, and, desc, max, inArray, isNull, count } from \"drizzle-orm\";\nimport { sql } from \"drizzle-orm\";\nimport type { getDb } from \"../db/client.js\";\nimport {\n runbooks,\n runbookVersions,\n runbookSettings,\n runbookVariables,\n runbookSecrets,\n runbookSteps,\n runbookVersionReviews,\n jobs,\n} from \"../db/schema.js\";\nimport type { ParsedStep } from \"../../runbook-executor/types.js\";\nimport { isEditable, isDeletable, resolveDisplayStatus, type VersionStatus } from \"./version-lifecycle.js\";\nimport { copyVersionData, insertSteps, loadVersionDetail } from \"./runbook-data-helpers.js\";\n\ntype Db = ReturnType<typeof getDb>;\ntype Tx = Parameters<Parameters<Db[\"transaction\"]>[0]>[0];\ntype VariableSource = \"prompt\" | \"fixed\" | \"context\" | \"env\" | \"expression\" | \"data\";\n\nexport interface VersionCreateData {\n goal: string;\n startUrl?: string | null;\n context?: string | null;\n generatedAt?: string | null;\n createdBy?: string | null;\n changeDescription?: string | null;\n settings?: {\n defaultTimeout?: number;\n pauseBetweenSteps?: number;\n stopOnError?: boolean;\n stepDelay?: number;\n enableSelectorCache?: boolean;\n enableAgentFallback?: boolean;\n enableVisionFallback?: boolean;\n modelId?: string;\n modelProvider?: string;\n };\n secrets?: Record<string, string>;\n variables?: Record<string, { source: VariableSource; description?: string; required: boolean; sensitive: boolean; value?: string }>;\n steps?: ParsedStep[];\n}\n\nexport interface VersionUpdateData {\n goal?: string;\n startUrl?: string;\n context?: string;\n settings?: {\n defaultTimeout?: number;\n pauseBetweenSteps?: number;\n stopOnError?: boolean;\n stepDelay?: number;\n enableSelectorCache?: boolean;\n enableAgentFallback?: boolean;\n enableVisionFallback?: boolean;\n modelId?: string;\n modelProvider?: string;\n };\n secrets?: Record<string, string>;\n variables?: Record<string, { source: VariableSource; description?: string; required: boolean; sensitive: boolean; value?: string }>;\n changeDescription?: string;\n steps?: ParsedStep[];\n title?: string;\n /** システム内部の書き戻し時に verificationJobId クリアをスキップ */\n skipVerificationJobClear?: boolean;\n}\n\nexport interface CreateVersionResult {\n version: typeof runbookVersions.$inferSelect;\n}\n\nexport class VersionStore {\n constructor(private db: Db) {}\n\n // ── 作成 ──\n\n /**\n * 初期バージョン(v1)を作成する。\n * steps ありなら pending_verification、なしなら draft。\n */\n async createInitialVersion(tx: Tx, runbookId: string, data: VersionCreateData) {\n const hasSteps = data.steps && data.steps.length > 0;\n const status: VersionStatus = hasSteps ? \"pending_verification\" : \"draft\";\n\n const [verRow] = await tx\n .insert(runbookVersions)\n .values({\n runbookId,\n versionNumber: 1,\n status,\n goal: data.goal,\n startUrl: data.startUrl ?? null,\n context: data.context ?? null,\n generatedAt: data.generatedAt ?? null,\n createdBy: data.createdBy ?? null,\n changeDescription: data.changeDescription ?? null,\n })\n .returning();\n\n // Settings\n if (data.settings) {\n await tx.insert(runbookSettings).values({\n versionId: verRow.id,\n ...data.settings,\n });\n }\n\n // Variables\n if (data.variables) {\n const vars = Object.entries(data.variables).map(([name, def]) => ({\n versionId: verRow.id,\n name,\n source: def.source,\n description: def.description ?? null,\n required: def.required,\n sensitive: def.sensitive,\n value: def.value ?? null,\n }));\n if (vars.length > 0) {\n await tx.insert(runbookVariables).values(vars);\n }\n }\n\n // Secrets\n if (data.secrets) {\n const secretRows = Object.entries(data.secrets).map(([key, val]) => ({\n versionId: verRow.id,\n key,\n encryptedValue: val,\n }));\n if (secretRows.length > 0) {\n await tx.insert(runbookSecrets).values(secretRows);\n }\n }\n\n // Steps\n if (data.steps && data.steps.length > 0) {\n await insertSteps(tx, verRow.id, data.steps, null);\n }\n\n return verRow;\n }\n\n /**\n * active バージョンからコピーして新 draft 作成。\n * 同時に draft/pending_verification は 1 つまで。\n */\n async createVersionFromActive(tenantId: string, runbookId: string, createdBy?: string, changeDescription?: string) {\n const rb = await this.db.query.runbooks.findFirst({\n where: and(eq(runbooks.id, runbookId), eq(runbooks.tenantId, tenantId)),\n });\n if (!rb) return null;\n\n // 既存 in-progress バージョンチェック\n const existingInProgress = await this.db.query.runbookVersions.findFirst({\n where: and(\n eq(runbookVersions.runbookId, runbookId),\n inArray(runbookVersions.status, [\"draft\", \"pending_verification\"]),\n ),\n });\n if (existingInProgress) {\n return { error: \"DRAFT_EXISTS\" as const, draftVersionId: existingInProgress.id };\n }\n\n return await this.db.transaction(async (tx) => {\n // 次のバージョン番号\n const [maxResult] = await tx\n .select({ maxVer: max(runbookVersions.versionNumber) })\n .from(runbookVersions)\n .where(eq(runbookVersions.runbookId, runbookId));\n const nextVersion = (maxResult?.maxVer ?? 0) + 1;\n\n // active バージョンのデータをコピー元として取得(null なら最新バージョンにフォールバック)\n let sourceVersionId = rb.activeVersionId;\n if (!sourceVersionId) {\n const latestVersion = await tx.query.runbookVersions.findFirst({\n where: eq(runbookVersions.runbookId, runbookId),\n orderBy: [desc(runbookVersions.versionNumber)],\n });\n if (latestVersion) {\n sourceVersionId = latestVersion.id;\n }\n }\n let sourceVersion: typeof runbookVersions.$inferSelect | null = null;\n if (sourceVersionId) {\n const [sv] = await tx\n .select()\n .from(runbookVersions)\n .where(eq(runbookVersions.id, sourceVersionId));\n sourceVersion = sv ?? null;\n }\n\n // 新しいバージョン作成\n const [newVer] = await tx\n .insert(runbookVersions)\n .values({\n runbookId,\n versionNumber: nextVersion,\n status: \"draft\",\n goal: sourceVersion?.goal ?? \"\",\n startUrl: sourceVersion?.startUrl ?? null,\n context: sourceVersion?.context ?? null,\n generatedAt: sourceVersion?.generatedAt ?? null,\n createdBy: createdBy ?? null,\n changeDescription: changeDescription ?? null,\n })\n .returning();\n\n // データのコピー(steps は除外 — verification 時に AI が再生成する)\n if (sourceVersionId) {\n await copyVersionData(tx, sourceVersionId, newVer.id, { skipSteps: true });\n }\n\n return { version: newVer } satisfies CreateVersionResult;\n });\n }\n\n // ── 更新 ──\n\n /**\n * バージョン更新(isEditable ガードつき)\n */\n async updateVersion(tenantId: string, runbookId: string, versionId: string, data: VersionUpdateData) {\n const rb = await this.db.query.runbooks.findFirst({\n where: and(eq(runbooks.id, runbookId), eq(runbooks.tenantId, tenantId)),\n });\n if (!rb) return null;\n\n const [ver] = await this.db\n .select()\n .from(runbookVersions)\n .where(and(\n eq(runbookVersions.id, versionId),\n eq(runbookVersions.runbookId, runbookId),\n ));\n if (!ver) return null;\n if (!isEditable(ver.status as VersionStatus)) return null;\n\n return await this.db.transaction(async (tx) => {\n const updates: Record<string, unknown> = {};\n if (data.goal !== undefined) updates.goal = data.goal;\n if (data.startUrl !== undefined) updates.startUrl = data.startUrl;\n if (data.context !== undefined) updates.context = data.context;\n if (data.changeDescription !== undefined) updates.changeDescription = data.changeDescription;\n\n // pending_verification バージョンの内容更新時は verificationJobId をクリア(再検証が必要)\n // ただしシステム内部の書き戻し(generate-job 等)ではスキップ\n if (ver.status === \"pending_verification\" && ver.verificationJobId && !data.skipVerificationJobClear) {\n updates.verificationJobId = null;\n }\n\n if (Object.keys(updates).length > 0) {\n await tx.update(runbookVersions).set(updates).where(eq(runbookVersions.id, versionId));\n }\n\n if (data.settings !== undefined) {\n await tx.delete(runbookSettings).where(eq(runbookSettings.versionId, versionId));\n if (data.settings) {\n await tx.insert(runbookSettings).values({ versionId, ...data.settings });\n }\n }\n\n if (data.secrets !== undefined) {\n await tx.delete(runbookSecrets).where(eq(runbookSecrets.versionId, versionId));\n const secretRows = Object.entries(data.secrets).map(([key, val]) => ({\n versionId,\n key,\n encryptedValue: val,\n }));\n if (secretRows.length > 0) {\n await tx.insert(runbookSecrets).values(secretRows);\n }\n }\n\n if (data.variables !== undefined) {\n await tx.delete(runbookVariables).where(eq(runbookVariables.versionId, versionId));\n const vars = Object.entries(data.variables).map(([name, def]) => ({\n versionId,\n name,\n source: def.source,\n description: def.description ?? null,\n required: def.required,\n sensitive: def.sensitive,\n value: def.value ?? null,\n }));\n if (vars.length > 0) {\n await tx.insert(runbookVariables).values(vars);\n }\n }\n\n if (data.steps !== undefined) {\n await tx.delete(runbookSteps).where(eq(runbookSteps.versionId, versionId));\n await insertSteps(tx, versionId, data.steps, null);\n }\n\n if (data.title !== undefined) {\n await tx.update(runbooks).set({ title: data.title }).where(eq(runbooks.id, runbookId));\n }\n\n return await this.findById(tenantId, runbookId, versionId);\n });\n }\n\n // ── 状態遷移 ──\n\n /**\n * draft → pending_verification\n */\n async completeVersion(tenantId: string, runbookId: string, versionId: string, data?: VersionUpdateData) {\n if (data) {\n await this.updateVersion(tenantId, runbookId, versionId, data);\n }\n\n const [ver] = await this.db\n .select()\n .from(runbookVersions)\n .where(and(\n eq(runbookVersions.id, versionId),\n eq(runbookVersions.runbookId, runbookId),\n ));\n if (!ver || ver.status !== \"draft\") return null;\n\n await this.db\n .update(runbookVersions)\n .set({ status: \"pending_verification\" })\n .where(eq(runbookVersions.id, versionId));\n\n return await this.findById(tenantId, runbookId, versionId);\n }\n\n /**\n * pending_verification|pending_approval → active(旧 active を archived)\n */\n async publishVersion(\n tenantId: string,\n runbookId: string,\n versionId: string,\n publishedBy: string | undefined,\n maxVersions: number,\n ) {\n const rb = await this.db.query.runbooks.findFirst({\n where: and(eq(runbooks.id, runbookId), eq(runbooks.tenantId, tenantId)),\n });\n if (!rb) return null;\n\n const [ver] = await this.db\n .select()\n .from(runbookVersions)\n .where(and(\n eq(runbookVersions.id, versionId),\n eq(runbookVersions.runbookId, runbookId),\n ));\n if (!ver) return null;\n\n if (ver.status !== \"pending_verification\" && ver.status !== \"pending_approval\") {\n return null;\n }\n\n return await this.db.transaction(async (tx) => {\n // 1. 旧 active → archived or 削除\n if (rb.activeVersionId) {\n if (maxVersions <= 1) {\n await tx\n .delete(runbookVersions)\n .where(eq(runbookVersions.id, rb.activeVersionId));\n } else {\n await tx\n .update(runbookVersions)\n .set({ status: \"archived\" })\n .where(eq(runbookVersions.id, rb.activeVersionId));\n }\n }\n\n // 2. 新バージョンを active に\n await tx\n .update(runbookVersions)\n .set({\n status: \"active\",\n publishedAt: new Date(),\n publishedBy: publishedBy ?? null,\n })\n .where(eq(runbookVersions.id, versionId));\n\n // 3. Runbook の activeVersionId を更新\n await tx\n .update(runbooks)\n .set({ activeVersionId: versionId })\n .where(eq(runbooks.id, runbookId));\n\n // 4. archived 超過分を削除\n if (maxVersions > 1) {\n const archivedVersions = await tx\n .select({ id: runbookVersions.id })\n .from(runbookVersions)\n .where(and(\n eq(runbookVersions.runbookId, runbookId),\n eq(runbookVersions.status, \"archived\"),\n ))\n .orderBy(desc(runbookVersions.versionNumber));\n\n const maxArchived = maxVersions - 1;\n if (archivedVersions.length > maxArchived) {\n const toDelete = archivedVersions.slice(maxArchived);\n for (const v of toDelete) {\n await tx.delete(runbookVersions).where(eq(runbookVersions.id, v.id));\n }\n }\n }\n\n return { status: \"active\" as const };\n });\n }\n\n /**\n * archived → active(現 active を archived)\n */\n async rollbackVersion(\n tenantId: string,\n runbookId: string,\n versionId: string,\n publishedBy: string | undefined,\n _maxVersions: number,\n ) {\n const rb = await this.db.query.runbooks.findFirst({\n where: and(eq(runbooks.id, runbookId), eq(runbooks.tenantId, tenantId)),\n });\n if (!rb) return null;\n\n const [ver] = await this.db\n .select()\n .from(runbookVersions)\n .where(and(\n eq(runbookVersions.id, versionId),\n eq(runbookVersions.runbookId, runbookId),\n ));\n if (!ver || ver.status !== \"archived\") return null;\n\n return await this.db.transaction(async (tx) => {\n // 現在の active → archived\n if (rb.activeVersionId) {\n await tx\n .update(runbookVersions)\n .set({ status: \"archived\" })\n .where(eq(runbookVersions.id, rb.activeVersionId));\n }\n\n // ロールバック先を active に\n await tx\n .update(runbookVersions)\n .set({\n status: \"active\",\n publishedAt: new Date(),\n publishedBy: publishedBy ?? null,\n })\n .where(eq(runbookVersions.id, versionId));\n\n // activeVersionId を更新\n await tx\n .update(runbooks)\n .set({ activeVersionId: versionId })\n .where(eq(runbooks.id, runbookId));\n\n return { status: \"active\" as const };\n });\n }\n\n // ── 検証ジョブ ──\n\n async setVerificationJob(versionId: string, jobId: string) {\n const result = await this.db\n .update(runbookVersions)\n .set({ verificationJobId: jobId })\n .where(eq(runbookVersions.id, versionId))\n .returning({ id: runbookVersions.id });\n return result.length > 0;\n }\n\n async clearVerificationJob(versionId: string) {\n const result = await this.db\n .update(runbookVersions)\n .set({ verificationJobId: null })\n .where(eq(runbookVersions.id, versionId))\n .returning({ id: runbookVersions.id });\n return result.length > 0;\n }\n\n /**\n * バージョンのステータスを直接更新(internal use)\n */\n async updateStatus(versionId: string, status: VersionStatus) {\n const result = await this.db\n .update(runbookVersions)\n .set({ status })\n .where(eq(runbookVersions.id, versionId))\n .returning({ id: runbookVersions.id });\n return result.length > 0;\n }\n\n // ── レビュー ──\n\n async requestReview(versionId: string, requestedBy: string) {\n const [row] = await this.db\n .insert(runbookVersionReviews)\n .values({\n versionId,\n requestedBy,\n })\n .returning();\n return row;\n }\n\n async submitReview(reviewId: string, reviewerId: string, status: \"approved\" | \"rejected\", comment?: string) {\n const result = await this.db\n .update(runbookVersionReviews)\n .set({\n reviewerId,\n reviewedAt: new Date(),\n status,\n comment: comment ?? null,\n })\n .where(eq(runbookVersionReviews.id, reviewId))\n .returning();\n return result.length > 0;\n }\n\n async getReviews(versionId: string) {\n return await this.db.query.runbookVersionReviews.findMany({\n where: eq(runbookVersionReviews.versionId, versionId),\n });\n }\n\n // ── クエリ ──\n\n /**\n * バージョン詳細取得\n */\n async findById(tenantId: string, runbookId: string, versionId: string) {\n const rb = await this.db.query.runbooks.findFirst({\n where: and(eq(runbooks.id, runbookId), eq(runbooks.tenantId, tenantId)),\n columns: { id: true, activeVersionId: true },\n });\n if (!rb) return null;\n\n const [ver] = await this.db\n .select()\n .from(runbookVersions)\n .where(and(\n eq(runbookVersions.id, versionId),\n eq(runbookVersions.runbookId, runbookId),\n ));\n if (!ver) return null;\n\n const detail = await loadVersionDetail(this.db, versionId);\n\n // 検証ジョブのステータスを取得\n let verificationJobStatus: string | null = null;\n if (ver.verificationJobId) {\n const [job] = await this.db.select({ status: jobs.status })\n .from(jobs).where(eq(jobs.id, ver.verificationJobId));\n verificationJobStatus = job?.status ?? null;\n }\n\n return {\n ...ver,\n isActive: rb.activeVersionId === versionId,\n stepsCount: detail.steps.filter((s) => !s.parentStepId).length,\n verificationJobStatus,\n displayStatus: resolveDisplayStatus(ver.status, ver.verificationJobId, verificationJobStatus),\n ...detail,\n };\n }\n\n /**\n * バージョン一覧\n */\n async list(tenantId: string, runbookId: string) {\n const rb = await this.db.query.runbooks.findFirst({\n where: and(eq(runbooks.id, runbookId), eq(runbooks.tenantId, tenantId)),\n columns: { id: true, activeVersionId: true },\n });\n if (!rb) return null;\n\n const versions = await this.db\n .select({\n id: runbookVersions.id,\n versionNumber: runbookVersions.versionNumber,\n status: runbookVersions.status,\n goal: runbookVersions.goal,\n startUrl: runbookVersions.startUrl,\n generatedAt: runbookVersions.generatedAt,\n verificationJobId: runbookVersions.verificationJobId,\n verificationJobStatus: sql<string | null>`(\n SELECT j.status FROM jobs j\n WHERE j.id = ${runbookVersions.verificationJobId}\n )`.as(\"verificationJobStatus\"),\n createdBy: runbookVersions.createdBy,\n createdAt: runbookVersions.createdAt,\n publishedAt: runbookVersions.publishedAt,\n changeDescription: runbookVersions.changeDescription,\n })\n .from(runbookVersions)\n .where(eq(runbookVersions.runbookId, runbookId))\n .orderBy(desc(runbookVersions.versionNumber));\n\n if (versions.length === 0) return [];\n\n const stepCounts = await this.db\n .select({\n versionId: runbookSteps.versionId,\n count: count(),\n })\n .from(runbookSteps)\n .where(\n and(\n inArray(runbookSteps.versionId, versions.map(v => v.id)),\n isNull(runbookSteps.parentStepId),\n )\n )\n .groupBy(runbookSteps.versionId);\n\n const countMap = new Map(stepCounts.map(sc => [sc.versionId, sc.count]));\n\n return versions.map(v => ({\n ...v,\n stepsCount: countMap.get(v.id) ?? 0,\n isActive: rb.activeVersionId === v.id,\n displayStatus: resolveDisplayStatus(v.status, v.verificationJobId, v.verificationJobStatus),\n }));\n }\n\n /**\n * バージョン削除(isDeletable ガードつき)\n */\n async deleteVersion(tenantId: string, runbookId: string, versionId: string) {\n const rb = await this.db.query.runbooks.findFirst({\n where: and(eq(runbooks.id, runbookId), eq(runbooks.tenantId, tenantId)),\n });\n if (!rb) return false;\n\n const [ver] = await this.db\n .select()\n .from(runbookVersions)\n .where(and(\n eq(runbookVersions.id, versionId),\n eq(runbookVersions.runbookId, runbookId),\n ));\n if (!ver || !isDeletable(ver.status as VersionStatus)) return false;\n\n await this.db.delete(runbookVersions).where(eq(runbookVersions.id, versionId));\n return true;\n }\n\n /**\n * ステップの部分更新\n */\n async patchSteps(\n tenantId: string,\n runbookId: string,\n versionId: string,\n patches: Array<{ id: string; description?: string; riskLevel?: string; requiresConfirmation?: boolean }>,\n ): Promise<boolean> {\n const rb = await this.db.query.runbooks.findFirst({\n where: and(eq(runbooks.id, runbookId), eq(runbooks.tenantId, tenantId)),\n });\n if (!rb) return false;\n\n await this.db.transaction(async (tx) => {\n for (const patch of patches) {\n const updates: Record<string, unknown> = {};\n if (patch.description !== undefined) updates.description = patch.description;\n if (patch.riskLevel !== undefined) updates.riskLevel = patch.riskLevel;\n if (patch.requiresConfirmation !== undefined) updates.requiresConfirmation = patch.requiresConfirmation;\n\n if (Object.keys(updates).length > 0) {\n await tx\n .update(runbookSteps)\n .set(updates)\n .where(and(eq(runbookSteps.id, patch.id), eq(runbookSteps.versionId, versionId)));\n }\n }\n });\n\n return true;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAOA,SAAS,MAAAA,KAAI,OAAAC,MAAK,QAAAC,OAAM,OAAAC,MAAK,SAAAC,cAAa;;;ACC1C,SAAS,IAAI,KAAK,MAAM,KAAK,SAAS,QAAQ,aAAa;AAC3D,SAAS,WAAW;AAuEb,IAAM,eAAN,MAAmB;AAAA,EACxB,YAAoB,IAAQ;AAAR;AAAA,EAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ7B,MAAM,qBAAqB,IAAQ,WAAmB,MAAyB;AAC7E,UAAM,WAAW,KAAK,SAAS,KAAK,MAAM,SAAS;AACnD,UAAM,SAAwB,WAAW,yBAAyB;AAElE,UAAM,CAAC,MAAM,IAAI,MAAM,GACpB,OAAO,eAAe,EACtB,OAAO;AAAA,MACN;AAAA,MACA,eAAe;AAAA,MACf;AAAA,MACA,MAAM,KAAK;AAAA,MACX,UAAU,KAAK,YAAY;AAAA,MAC3B,SAAS,KAAK,WAAW;AAAA,MACzB,aAAa,KAAK,eAAe;AAAA,MACjC,WAAW,KAAK,aAAa;AAAA,MAC7B,mBAAmB,KAAK,qBAAqB;AAAA,IAC/C,CAAC,EACA,UAAU;AAGb,QAAI,KAAK,UAAU;AACjB,YAAM,GAAG,OAAO,eAAe,EAAE,OAAO;AAAA,QACtC,WAAW,OAAO;AAAA,QAClB,GAAG,KAAK;AAAA,MACV,CAAC;AAAA,IACH;AAGA,QAAI,KAAK,WAAW;AAClB,YAAM,OAAO,OAAO,QAAQ,KAAK,SAAS,EAAE,IAAI,CAAC,CAAC,MAAM,GAAG,OAAO;AAAA,QAChE,WAAW,OAAO;AAAA,QAClB;AAAA,QACA,QAAQ,IAAI;AAAA,QACZ,aAAa,IAAI,eAAe;AAAA,QAChC,UAAU,IAAI;AAAA,QACd,WAAW,IAAI;AAAA,QACf,OAAO,IAAI,SAAS;AAAA,MACtB,EAAE;AACF,UAAI,KAAK,SAAS,GAAG;AACnB,cAAM,GAAG,OAAO,gBAAgB,EAAE,OAAO,IAAI;AAAA,MAC/C;AAAA,IACF;AAGA,QAAI,KAAK,SAAS;AAChB,YAAM,aAAa,OAAO,QAAQ,KAAK,OAAO,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,OAAO;AAAA,QACnE,WAAW,OAAO;AAAA,QAClB;AAAA,QACA,gBAAgB;AAAA,MAClB,EAAE;AACF,UAAI,WAAW,SAAS,GAAG;AACzB,cAAM,GAAG,OAAO,cAAc,EAAE,OAAO,UAAU;AAAA,MACnD;AAAA,IACF;AAGA,QAAI,KAAK,SAAS,KAAK,MAAM,SAAS,GAAG;AACvC,YAAM,YAAY,IAAI,OAAO,IAAI,KAAK,OAAO,IAAI;AAAA,IACnD;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,wBAAwB,UAAkB,WAAmB,WAAoB,mBAA4B;AACjH,UAAM,KAAK,MAAM,KAAK,GAAG,MAAM,SAAS,UAAU;AAAA,MAChD,OAAO,IAAI,GAAG,SAAS,IAAI,SAAS,GAAG,GAAG,SAAS,UAAU,QAAQ,CAAC;AAAA,IACxE,CAAC;AACD,QAAI,CAAC,GAAI,QAAO;AAGhB,UAAM,qBAAqB,MAAM,KAAK,GAAG,MAAM,gBAAgB,UAAU;AAAA,MACvE,OAAO;AAAA,QACL,GAAG,gBAAgB,WAAW,SAAS;AAAA,QACvC,QAAQ,gBAAgB,QAAQ,CAAC,SAAS,sBAAsB,CAAC;AAAA,MACnE;AAAA,IACF,CAAC;AACD,QAAI,oBAAoB;AACtB,aAAO,EAAE,OAAO,gBAAyB,gBAAgB,mBAAmB,GAAG;AAAA,IACjF;AAEA,WAAO,MAAM,KAAK,GAAG,YAAY,OAAO,OAAO;AAE7C,YAAM,CAAC,SAAS,IAAI,MAAM,GACvB,OAAO,EAAE,QAAQ,IAAI,gBAAgB,aAAa,EAAE,CAAC,EACrD,KAAK,eAAe,EACpB,MAAM,GAAG,gBAAgB,WAAW,SAAS,CAAC;AACjD,YAAM,eAAe,WAAW,UAAU,KAAK;AAG/C,UAAI,kBAAkB,GAAG;AACzB,UAAI,CAAC,iBAAiB;AACpB,cAAM,gBAAgB,MAAM,GAAG,MAAM,gBAAgB,UAAU;AAAA,UAC7D,OAAO,GAAG,gBAAgB,WAAW,SAAS;AAAA,UAC9C,SAAS,CAAC,KAAK,gBAAgB,aAAa,CAAC;AAAA,QAC/C,CAAC;AACD,YAAI,eAAe;AACjB,4BAAkB,cAAc;AAAA,QAClC;AAAA,MACF;AACA,UAAI,gBAA4D;AAChE,UAAI,iBAAiB;AACnB,cAAM,CAAC,EAAE,IAAI,MAAM,GAChB,OAAO,EACP,KAAK,eAAe,EACpB,MAAM,GAAG,gBAAgB,IAAI,eAAe,CAAC;AAChD,wBAAgB,MAAM;AAAA,MACxB;AAGA,YAAM,CAAC,MAAM,IAAI,MAAM,GACpB,OAAO,eAAe,EACtB,OAAO;AAAA,QACN;AAAA,QACA,eAAe;AAAA,QACf,QAAQ;AAAA,QACR,MAAM,eAAe,QAAQ;AAAA,QAC7B,UAAU,eAAe,YAAY;AAAA,QACrC,SAAS,eAAe,WAAW;AAAA,QACnC,aAAa,eAAe,eAAe;AAAA,QAC3C,WAAW,aAAa;AAAA,QACxB,mBAAmB,qBAAqB;AAAA,MAC1C,CAAC,EACA,UAAU;AAGb,UAAI,iBAAiB;AACnB,cAAM,gBAAgB,IAAI,iBAAiB,OAAO,IAAI,EAAE,WAAW,KAAK,CAAC;AAAA,MAC3E;AAEA,aAAO,EAAE,SAAS,OAAO;AAAA,IAC3B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cAAc,UAAkB,WAAmB,WAAmB,MAAyB;AACnG,UAAM,KAAK,MAAM,KAAK,GAAG,MAAM,SAAS,UAAU;AAAA,MAChD,OAAO,IAAI,GAAG,SAAS,IAAI,SAAS,GAAG,GAAG,SAAS,UAAU,QAAQ,CAAC;AAAA,IACxE,CAAC;AACD,QAAI,CAAC,GAAI,QAAO;AAEhB,UAAM,CAAC,GAAG,IAAI,MAAM,KAAK,GACtB,OAAO,EACP,KAAK,eAAe,EACpB,MAAM;AAAA,MACL,GAAG,gBAAgB,IAAI,SAAS;AAAA,MAChC,GAAG,gBAAgB,WAAW,SAAS;AAAA,IACzC,CAAC;AACH,QAAI,CAAC,IAAK,QAAO;AACjB,QAAI,CAAC,WAAW,IAAI,MAAuB,EAAG,QAAO;AAErD,WAAO,MAAM,KAAK,GAAG,YAAY,OAAO,OAAO;AAC7C,YAAM,UAAmC,CAAC;AAC1C,UAAI,KAAK,SAAS,OAAW,SAAQ,OAAO,KAAK;AACjD,UAAI,KAAK,aAAa,OAAW,SAAQ,WAAW,KAAK;AACzD,UAAI,KAAK,YAAY,OAAW,SAAQ,UAAU,KAAK;AACvD,UAAI,KAAK,sBAAsB,OAAW,SAAQ,oBAAoB,KAAK;AAI3E,UAAI,IAAI,WAAW,0BAA0B,IAAI,qBAAqB,CAAC,KAAK,0BAA0B;AACpG,gBAAQ,oBAAoB;AAAA,MAC9B;AAEA,UAAI,OAAO,KAAK,OAAO,EAAE,SAAS,GAAG;AACnC,cAAM,GAAG,OAAO,eAAe,EAAE,IAAI,OAAO,EAAE,MAAM,GAAG,gBAAgB,IAAI,SAAS,CAAC;AAAA,MACvF;AAEA,UAAI,KAAK,aAAa,QAAW;AAC/B,cAAM,GAAG,OAAO,eAAe,EAAE,MAAM,GAAG,gBAAgB,WAAW,SAAS,CAAC;AAC/E,YAAI,KAAK,UAAU;AACjB,gBAAM,GAAG,OAAO,eAAe,EAAE,OAAO,EAAE,WAAW,GAAG,KAAK,SAAS,CAAC;AAAA,QACzE;AAAA,MACF;AAEA,UAAI,KAAK,YAAY,QAAW;AAC9B,cAAM,GAAG,OAAO,cAAc,EAAE,MAAM,GAAG,eAAe,WAAW,SAAS,CAAC;AAC7E,cAAM,aAAa,OAAO,QAAQ,KAAK,OAAO,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,OAAO;AAAA,UACnE;AAAA,UACA;AAAA,UACA,gBAAgB;AAAA,QAClB,EAAE;AACF,YAAI,WAAW,SAAS,GAAG;AACzB,gBAAM,GAAG,OAAO,cAAc,EAAE,OAAO,UAAU;AAAA,QACnD;AAAA,MACF;AAEA,UAAI,KAAK,cAAc,QAAW;AAChC,cAAM,GAAG,OAAO,gBAAgB,EAAE,MAAM,GAAG,iBAAiB,WAAW,SAAS,CAAC;AACjF,cAAM,OAAO,OAAO,QAAQ,KAAK,SAAS,EAAE,IAAI,CAAC,CAAC,MAAM,GAAG,OAAO;AAAA,UAChE;AAAA,UACA;AAAA,UACA,QAAQ,IAAI;AAAA,UACZ,aAAa,IAAI,eAAe;AAAA,UAChC,UAAU,IAAI;AAAA,UACd,WAAW,IAAI;AAAA,UACf,OAAO,IAAI,SAAS;AAAA,QACtB,EAAE;AACF,YAAI,KAAK,SAAS,GAAG;AACnB,gBAAM,GAAG,OAAO,gBAAgB,EAAE,OAAO,IAAI;AAAA,QAC/C;AAAA,MACF;AAEA,UAAI,KAAK,UAAU,QAAW;AAC5B,cAAM,GAAG,OAAO,YAAY,EAAE,MAAM,GAAG,aAAa,WAAW,SAAS,CAAC;AACzE,cAAM,YAAY,IAAI,WAAW,KAAK,OAAO,IAAI;AAAA,MACnD;AAEA,UAAI,KAAK,UAAU,QAAW;AAC5B,cAAM,GAAG,OAAO,QAAQ,EAAE,IAAI,EAAE,OAAO,KAAK,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,IAAI,SAAS,CAAC;AAAA,MACvF;AAEA,aAAO,MAAM,KAAK,SAAS,UAAU,WAAW,SAAS;AAAA,IAC3D,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBAAgB,UAAkB,WAAmB,WAAmB,MAA0B;AACtG,QAAI,MAAM;AACR,YAAM,KAAK,cAAc,UAAU,WAAW,WAAW,IAAI;AAAA,IAC/D;AAEA,UAAM,CAAC,GAAG,IAAI,MAAM,KAAK,GACtB,OAAO,EACP,KAAK,eAAe,EACpB,MAAM;AAAA,MACL,GAAG,gBAAgB,IAAI,SAAS;AAAA,MAChC,GAAG,gBAAgB,WAAW,SAAS;AAAA,IACzC,CAAC;AACH,QAAI,CAAC,OAAO,IAAI,WAAW,QAAS,QAAO;AAE3C,UAAM,KAAK,GACR,OAAO,eAAe,EACtB,IAAI,EAAE,QAAQ,uBAAuB,CAAC,EACtC,MAAM,GAAG,gBAAgB,IAAI,SAAS,CAAC;AAE1C,WAAO,MAAM,KAAK,SAAS,UAAU,WAAW,SAAS;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eACJ,UACA,WACA,WACA,aACA,aACA;AACA,UAAM,KAAK,MAAM,KAAK,GAAG,MAAM,SAAS,UAAU;AAAA,MAChD,OAAO,IAAI,GAAG,SAAS,IAAI,SAAS,GAAG,GAAG,SAAS,UAAU,QAAQ,CAAC;AAAA,IACxE,CAAC;AACD,QAAI,CAAC,GAAI,QAAO;AAEhB,UAAM,CAAC,GAAG,IAAI,MAAM,KAAK,GACtB,OAAO,EACP,KAAK,eAAe,EACpB,MAAM;AAAA,MACL,GAAG,gBAAgB,IAAI,SAAS;AAAA,MAChC,GAAG,gBAAgB,WAAW,SAAS;AAAA,IACzC,CAAC;AACH,QAAI,CAAC,IAAK,QAAO;AAEjB,QAAI,IAAI,WAAW,0BAA0B,IAAI,WAAW,oBAAoB;AAC9E,aAAO;AAAA,IACT;AAEA,WAAO,MAAM,KAAK,GAAG,YAAY,OAAO,OAAO;AAE7C,UAAI,GAAG,iBAAiB;AACtB,YAAI,eAAe,GAAG;AACpB,gBAAM,GACH,OAAO,eAAe,EACtB,MAAM,GAAG,gBAAgB,IAAI,GAAG,eAAe,CAAC;AAAA,QACrD,OAAO;AACL,gBAAM,GACH,OAAO,eAAe,EACtB,IAAI,EAAE,QAAQ,WAAW,CAAC,EAC1B,MAAM,GAAG,gBAAgB,IAAI,GAAG,eAAe,CAAC;AAAA,QACrD;AAAA,MACF;AAGA,YAAM,GACH,OAAO,eAAe,EACtB,IAAI;AAAA,QACH,QAAQ;AAAA,QACR,aAAa,oBAAI,KAAK;AAAA,QACtB,aAAa,eAAe;AAAA,MAC9B,CAAC,EACA,MAAM,GAAG,gBAAgB,IAAI,SAAS,CAAC;AAG1C,YAAM,GACH,OAAO,QAAQ,EACf,IAAI,EAAE,iBAAiB,UAAU,CAAC,EAClC,MAAM,GAAG,SAAS,IAAI,SAAS,CAAC;AAGnC,UAAI,cAAc,GAAG;AACnB,cAAM,mBAAmB,MAAM,GAC5B,OAAO,EAAE,IAAI,gBAAgB,GAAG,CAAC,EACjC,KAAK,eAAe,EACpB,MAAM;AAAA,UACL,GAAG,gBAAgB,WAAW,SAAS;AAAA,UACvC,GAAG,gBAAgB,QAAQ,UAAU;AAAA,QACvC,CAAC,EACA,QAAQ,KAAK,gBAAgB,aAAa,CAAC;AAE9C,cAAM,cAAc,cAAc;AAClC,YAAI,iBAAiB,SAAS,aAAa;AACzC,gBAAM,WAAW,iBAAiB,MAAM,WAAW;AACnD,qBAAW,KAAK,UAAU;AACxB,kBAAM,GAAG,OAAO,eAAe,EAAE,MAAM,GAAG,gBAAgB,IAAI,EAAE,EAAE,CAAC;AAAA,UACrE;AAAA,QACF;AAAA,MACF;AAEA,aAAO,EAAE,QAAQ,SAAkB;AAAA,IACrC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBACJ,UACA,WACA,WACA,aACA,cACA;AACA,UAAM,KAAK,MAAM,KAAK,GAAG,MAAM,SAAS,UAAU;AAAA,MAChD,OAAO,IAAI,GAAG,SAAS,IAAI,SAAS,GAAG,GAAG,SAAS,UAAU,QAAQ,CAAC;AAAA,IACxE,CAAC;AACD,QAAI,CAAC,GAAI,QAAO;AAEhB,UAAM,CAAC,GAAG,IAAI,MAAM,KAAK,GACtB,OAAO,EACP,KAAK,eAAe,EACpB,MAAM;AAAA,MACL,GAAG,gBAAgB,IAAI,SAAS;AAAA,MAChC,GAAG,gBAAgB,WAAW,SAAS;AAAA,IACzC,CAAC;AACH,QAAI,CAAC,OAAO,IAAI,WAAW,WAAY,QAAO;AAE9C,WAAO,MAAM,KAAK,GAAG,YAAY,OAAO,OAAO;AAE7C,UAAI,GAAG,iBAAiB;AACtB,cAAM,GACH,OAAO,eAAe,EACtB,IAAI,EAAE,QAAQ,WAAW,CAAC,EAC1B,MAAM,GAAG,gBAAgB,IAAI,GAAG,eAAe,CAAC;AAAA,MACrD;AAGA,YAAM,GACH,OAAO,eAAe,EACtB,IAAI;AAAA,QACH,QAAQ;AAAA,QACR,aAAa,oBAAI,KAAK;AAAA,QACtB,aAAa,eAAe;AAAA,MAC9B,CAAC,EACA,MAAM,GAAG,gBAAgB,IAAI,SAAS,CAAC;AAG1C,YAAM,GACH,OAAO,QAAQ,EACf,IAAI,EAAE,iBAAiB,UAAU,CAAC,EAClC,MAAM,GAAG,SAAS,IAAI,SAAS,CAAC;AAEnC,aAAO,EAAE,QAAQ,SAAkB;AAAA,IACrC,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,MAAM,mBAAmB,WAAmB,OAAe;AACzD,UAAM,SAAS,MAAM,KAAK,GACvB,OAAO,eAAe,EACtB,IAAI,EAAE,mBAAmB,MAAM,CAAC,EAChC,MAAM,GAAG,gBAAgB,IAAI,SAAS,CAAC,EACvC,UAAU,EAAE,IAAI,gBAAgB,GAAG,CAAC;AACvC,WAAO,OAAO,SAAS;AAAA,EACzB;AAAA,EAEA,MAAM,qBAAqB,WAAmB;AAC5C,UAAM,SAAS,MAAM,KAAK,GACvB,OAAO,eAAe,EACtB,IAAI,EAAE,mBAAmB,KAAK,CAAC,EAC/B,MAAM,GAAG,gBAAgB,IAAI,SAAS,CAAC,EACvC,UAAU,EAAE,IAAI,gBAAgB,GAAG,CAAC;AACvC,WAAO,OAAO,SAAS;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,WAAmB,QAAuB;AAC3D,UAAM,SAAS,MAAM,KAAK,GACvB,OAAO,eAAe,EACtB,IAAI,EAAE,OAAO,CAAC,EACd,MAAM,GAAG,gBAAgB,IAAI,SAAS,CAAC,EACvC,UAAU,EAAE,IAAI,gBAAgB,GAAG,CAAC;AACvC,WAAO,OAAO,SAAS;AAAA,EACzB;AAAA;AAAA,EAIA,MAAM,cAAc,WAAmB,aAAqB;AAC1D,UAAM,CAAC,GAAG,IAAI,MAAM,KAAK,GACtB,OAAO,qBAAqB,EAC5B,OAAO;AAAA,MACN;AAAA,MACA;AAAA,IACF,CAAC,EACA,UAAU;AACb,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,aAAa,UAAkB,YAAoB,QAAiC,SAAkB;AAC1G,UAAM,SAAS,MAAM,KAAK,GACvB,OAAO,qBAAqB,EAC5B,IAAI;AAAA,MACH;AAAA,MACA,YAAY,oBAAI,KAAK;AAAA,MACrB;AAAA,MACA,SAAS,WAAW;AAAA,IACtB,CAAC,EACA,MAAM,GAAG,sBAAsB,IAAI,QAAQ,CAAC,EAC5C,UAAU;AACb,WAAO,OAAO,SAAS;AAAA,EACzB;AAAA,EAEA,MAAM,WAAW,WAAmB;AAClC,WAAO,MAAM,KAAK,GAAG,MAAM,sBAAsB,SAAS;AAAA,MACxD,OAAO,GAAG,sBAAsB,WAAW,SAAS;AAAA,IACtD,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,SAAS,UAAkB,WAAmB,WAAmB;AACrE,UAAM,KAAK,MAAM,KAAK,GAAG,MAAM,SAAS,UAAU;AAAA,MAChD,OAAO,IAAI,GAAG,SAAS,IAAI,SAAS,GAAG,GAAG,SAAS,UAAU,QAAQ,CAAC;AAAA,MACtE,SAAS,EAAE,IAAI,MAAM,iBAAiB,KAAK;AAAA,IAC7C,CAAC;AACD,QAAI,CAAC,GAAI,QAAO;AAEhB,UAAM,CAAC,GAAG,IAAI,MAAM,KAAK,GACtB,OAAO,EACP,KAAK,eAAe,EACpB,MAAM;AAAA,MACL,GAAG,gBAAgB,IAAI,SAAS;AAAA,MAChC,GAAG,gBAAgB,WAAW,SAAS;AAAA,IACzC,CAAC;AACH,QAAI,CAAC,IAAK,QAAO;AAEjB,UAAM,SAAS,MAAM,kBAAkB,KAAK,IAAI,SAAS;AAGzD,QAAI,wBAAuC;AAC3C,QAAI,IAAI,mBAAmB;AACzB,YAAM,CAAC,GAAG,IAAI,MAAM,KAAK,GAAG,OAAO,EAAE,QAAQ,KAAK,OAAO,CAAC,EACvD,KAAK,IAAI,EAAE,MAAM,GAAG,KAAK,IAAI,IAAI,iBAAiB,CAAC;AACtD,8BAAwB,KAAK,UAAU;AAAA,IACzC;AAEA,WAAO;AAAA,MACL,GAAG;AAAA,MACH,UAAU,GAAG,oBAAoB;AAAA,MACjC,YAAY,OAAO,MAAM,OAAO,CAAC,MAAM,CAAC,EAAE,YAAY,EAAE;AAAA,MACxD;AAAA,MACA,eAAe,qBAAqB,IAAI,QAAQ,IAAI,mBAAmB,qBAAqB;AAAA,MAC5F,GAAG;AAAA,IACL;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAK,UAAkB,WAAmB;AAC9C,UAAM,KAAK,MAAM,KAAK,GAAG,MAAM,SAAS,UAAU;AAAA,MAChD,OAAO,IAAI,GAAG,SAAS,IAAI,SAAS,GAAG,GAAG,SAAS,UAAU,QAAQ,CAAC;AAAA,MACtE,SAAS,EAAE,IAAI,MAAM,iBAAiB,KAAK;AAAA,IAC7C,CAAC;AACD,QAAI,CAAC,GAAI,QAAO;AAEhB,UAAM,WAAW,MAAM,KAAK,GACzB,OAAO;AAAA,MACN,IAAI,gBAAgB;AAAA,MACpB,eAAe,gBAAgB;AAAA,MAC/B,QAAQ,gBAAgB;AAAA,MACxB,MAAM,gBAAgB;AAAA,MACtB,UAAU,gBAAgB;AAAA,MAC1B,aAAa,gBAAgB;AAAA,MAC7B,mBAAmB,gBAAgB;AAAA,MACnC,uBAAuB;AAAA;AAAA,yBAEN,gBAAgB,iBAAiB;AAAA,WAC/C,GAAG,uBAAuB;AAAA,MAC7B,WAAW,gBAAgB;AAAA,MAC3B,WAAW,gBAAgB;AAAA,MAC3B,aAAa,gBAAgB;AAAA,MAC7B,mBAAmB,gBAAgB;AAAA,IACrC,CAAC,EACA,KAAK,eAAe,EACpB,MAAM,GAAG,gBAAgB,WAAW,SAAS,CAAC,EAC9C,QAAQ,KAAK,gBAAgB,aAAa,CAAC;AAE9C,QAAI,SAAS,WAAW,EAAG,QAAO,CAAC;AAEnC,UAAM,aAAa,MAAM,KAAK,GAC3B,OAAO;AAAA,MACN,WAAW,aAAa;AAAA,MACxB,OAAO,MAAM;AAAA,IACf,CAAC,EACA,KAAK,YAAY,EACjB;AAAA,MACC;AAAA,QACE,QAAQ,aAAa,WAAW,SAAS,IAAI,OAAK,EAAE,EAAE,CAAC;AAAA,QACvD,OAAO,aAAa,YAAY;AAAA,MAClC;AAAA,IACF,EACC,QAAQ,aAAa,SAAS;AAEjC,UAAM,WAAW,IAAI,IAAI,WAAW,IAAI,QAAM,CAAC,GAAG,WAAW,GAAG,KAAK,CAAC,CAAC;AAEvE,WAAO,SAAS,IAAI,QAAM;AAAA,MACxB,GAAG;AAAA,MACH,YAAY,SAAS,IAAI,EAAE,EAAE,KAAK;AAAA,MAClC,UAAU,GAAG,oBAAoB,EAAE;AAAA,MACnC,eAAe,qBAAqB,EAAE,QAAQ,EAAE,mBAAmB,EAAE,qBAAqB;AAAA,IAC5F,EAAE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAc,UAAkB,WAAmB,WAAmB;AAC1E,UAAM,KAAK,MAAM,KAAK,GAAG,MAAM,SAAS,UAAU;AAAA,MAChD,OAAO,IAAI,GAAG,SAAS,IAAI,SAAS,GAAG,GAAG,SAAS,UAAU,QAAQ,CAAC;AAAA,IACxE,CAAC;AACD,QAAI,CAAC,GAAI,QAAO;AAEhB,UAAM,CAAC,GAAG,IAAI,MAAM,KAAK,GACtB,OAAO,EACP,KAAK,eAAe,EACpB,MAAM;AAAA,MACL,GAAG,gBAAgB,IAAI,SAAS;AAAA,MAChC,GAAG,gBAAgB,WAAW,SAAS;AAAA,IACzC,CAAC;AACH,QAAI,CAAC,OAAO,CAAC,YAAY,IAAI,MAAuB,EAAG,QAAO;AAE9D,UAAM,KAAK,GAAG,OAAO,eAAe,EAAE,MAAM,GAAG,gBAAgB,IAAI,SAAS,CAAC;AAC7E,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WACJ,UACA,WACA,WACA,SACkB;AAClB,UAAM,KAAK,MAAM,KAAK,GAAG,MAAM,SAAS,UAAU;AAAA,MAChD,OAAO,IAAI,GAAG,SAAS,IAAI,SAAS,GAAG,GAAG,SAAS,UAAU,QAAQ,CAAC;AAAA,IACxE,CAAC;AACD,QAAI,CAAC,GAAI,QAAO;AAEhB,UAAM,KAAK,GAAG,YAAY,OAAO,OAAO;AACtC,iBAAW,SAAS,SAAS;AAC3B,cAAM,UAAmC,CAAC;AAC1C,YAAI,MAAM,gBAAgB,OAAW,SAAQ,cAAc,MAAM;AACjE,YAAI,MAAM,cAAc,OAAW,SAAQ,YAAY,MAAM;AAC7D,YAAI,MAAM,yBAAyB,OAAW,SAAQ,uBAAuB,MAAM;AAEnF,YAAI,OAAO,KAAK,OAAO,EAAE,SAAS,GAAG;AACnC,gBAAM,GACH,OAAO,YAAY,EACnB,IAAI,OAAO,EACX,MAAM,IAAI,GAAG,aAAa,IAAI,MAAM,EAAE,GAAG,GAAG,aAAa,WAAW,SAAS,CAAC,CAAC;AAAA,QACpF;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT;AACF;;;ADrnBO,IAAM,eAAN,MAAmB;AAAA,EAGxB,YAAoB,IAAQ;AAAR;AAClB,SAAK,WAAW,IAAI,aAAa,EAAE;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAO,MAAyB;AACpC,UAAM,EAAE,UAAU,WAAW,SAAS,SAAS,SAAS,SAAS,IAAI;AAErE,WAAO,MAAM,KAAK,GAAG,YAAY,OAAO,OAAO;AAE7C,YAAM,CAAC,KAAK,IAAI,MAAM,GACnB,OAAO,QAAQ,EACf,OAAO;AAAA,QACN;AAAA,QACA,OAAO,QAAQ;AAAA,QACf,WAAW,aAAa;AAAA,MAC1B,CAAC,EACA,UAAU;AAGb,YAAM,SAAS,MAAM,KAAK,SAAS,qBAAqB,IAAI,MAAM,IAAI;AAAA,QACpE,MAAM,QAAQ,SAAS;AAAA,QACvB,UAAU,QAAQ,SAAS;AAAA,QAC3B,SAAS,WAAW;AAAA,QACpB,aAAa,QAAQ,SAAS;AAAA,QAC9B,WAAW,aAAa;AAAA,QACxB;AAAA,QACA;AAAA,QACA,WAAW,QAAQ;AAAA,QACnB,OAAO,QAAQ;AAAA,MACjB,CAAC;AAGD,YAAM,GACH,OAAO,QAAQ,EACf,IAAI,EAAE,iBAAiB,OAAO,GAAG,CAAC,EAClC,MAAMC,IAAG,SAAS,IAAI,MAAM,EAAE,CAAC;AAElC,aAAO,EAAE,GAAG,OAAO,iBAAiB,OAAO,GAAG;AAAA,IAChD,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,MASf;AACD,WAAO,MAAM,KAAK,GAAG,YAAY,OAAO,OAAO;AAE7C,YAAM,CAAC,KAAK,IAAI,MAAM,GACnB,OAAO,QAAQ,EACf,OAAO;AAAA,QACN,UAAU,KAAK;AAAA,QACf,OAAO,KAAK;AAAA,QACZ,WAAW,KAAK,aAAa;AAAA,MAC/B,CAAC,EACA,UAAU;AAGb,YAAM,SAAS,MAAM,KAAK,SAAS,qBAAqB,IAAI,MAAM,IAAI;AAAA,QACpE,MAAM,KAAK,QAAQ;AAAA,QACnB,UAAU,KAAK,YAAY;AAAA,QAC3B,SAAS,KAAK,WAAW;AAAA,QACzB,WAAW,KAAK,aAAa;AAAA,QAC7B,SAAS,KAAK;AAAA,QACd,WAAW,KAAK;AAAA,MAClB,CAAC;AAED,aAAO,EAAE,GAAG,OAAO,WAAW,OAAO,GAAG;AAAA,IAC1C,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,SAAS,UAAkB,IAAY;AAC3C,UAAM,MAAM,MAAM,KAAK,GAAG,MAAM,SAAS,UAAU;AAAA,MACjD,OAAOC,KAAID,IAAG,SAAS,IAAI,EAAE,GAAGA,IAAG,SAAS,UAAU,QAAQ,CAAC;AAAA,IACjE,CAAC;AACD,QAAI,CAAC,IAAK,QAAO;AAGjB,UAAM,YAAY,IAAI;AACtB,QAAI,CAAC,WAAW;AAEd,YAAM,cAAc,MAAM,KAAK,GAAG,MAAM,gBAAgB,UAAU;AAAA,QAChE,OAAOA,IAAG,gBAAgB,WAAW,EAAE;AAAA,QACvC,SAAS,CAACE,MAAK,gBAAgB,aAAa,CAAC;AAAA,MAC/C,CAAC;AACD,UAAI,CAAC,aAAa;AAChB,cAAM,SAAS,IAAI,WAAW,aAAsB;AACpD,eAAO;AAAA,UACL,GAAG;AAAA,UACH,MAAM;AAAA,UACN,UAAU;AAAA,UACV,SAAS;AAAA,UACT,aAAa;AAAA,UACb;AAAA,UACA,mBAAmB;AAAA,UACnB,uBAAuB;AAAA,UACvB,eAAe,qBAAqB,QAAQ,MAAM,IAAI;AAAA,UACtD,UAAU;AAAA,UACV,WAAW,CAAC;AAAA,UACZ,SAAS,CAAC;AAAA,UACV,OAAO,CAAC;AAAA,UACR,iBAAiB;AAAA,UACjB,kBAAkB;AAAA,QACpB;AAAA,MACF;AACA,aAAO,MAAM,iBAAiB,KAAK,IAAI,KAAK,WAAW;AAAA,IACzD;AAEA,UAAM,CAAC,GAAG,IAAI,MAAM,KAAK,GACtB,OAAO,EACP,KAAK,eAAe,EACpB,MAAMF,IAAG,gBAAgB,IAAI,SAAS,CAAC;AAC1C,QAAI,CAAC,IAAK,QAAO;AAEjB,WAAO,MAAM,iBAAiB,KAAK,IAAI,KAAK,GAAG;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KACJ,UACA,OAA+F,CAAC,GAChG;AACA,UAAM,EAAE,QAAQ,IAAI,SAAS,GAAG,QAAQ,kBAAkB,MAAM,IAAI;AAEpE,UAAM,aAAa,CAACA,IAAG,SAAS,UAAU,QAAQ,CAAC;AAEnD,QAAI,WAAW,YAAY;AACzB,iBAAW,KAAKA,IAAG,SAAS,UAAU,IAAI,CAAC;AAAA,IAC7C,WAAW,QAAQ;AACjB,iBAAW,KAAKA,IAAG,SAAS,UAAU,KAAK,CAAC;AAAA,IAC9C,WAAW,CAAC,iBAAiB;AAC3B,iBAAW,KAAKA,IAAG,SAAS,UAAU,KAAK,CAAC;AAAA,IAC9C;AAEA,UAAM,QAAQC,KAAI,GAAG,UAAU;AAE/B,UAAM,OAAO,MAAM,KAAK,GACrB,OAAO;AAAA,MACN,IAAI,SAAS;AAAA,MACb,OAAO,SAAS;AAAA,MAChB,UAAU,SAAS;AAAA,MACnB,iBAAiB,SAAS;AAAA,MAC1B,WAAW,SAAS;AAAA,MACpB,WAAW,SAAS;AAAA,MACpB,MAAME;AAAA;AAAA,0BAEY,SAAS,eAAe;AAAA;AAAA;AAAA,kCAGhB,SAAS,EAAE;AAAA;AAAA,gBAE7B,GAAG,MAAM;AAAA,MACjB,UAAUA;AAAA;AAAA,0BAEQ,SAAS,eAAe;AAAA;AAAA;AAAA,kCAGhB,SAAS,EAAE;AAAA;AAAA,YAEjC,GAAG,UAAU;AAAA,MACjB,aAAaA;AAAA;AAAA,0BAEK,SAAS,eAAe;AAAA;AAAA;AAAA,kCAGhB,SAAS,EAAE;AAAA;AAAA,YAEjC,GAAG,aAAa;AAAA,MACpB,eAAeA;AAAA;AAAA,0BAEG,SAAS,eAAe;AAAA;AAAA;AAAA,kCAGhB,SAAS,EAAE;AAAA;AAAA,YAEjC,GAAG,eAAe;AAAA,MACtB,mBAAmBA;AAAA;AAAA,0BAED,SAAS,eAAe;AAAA;AAAA;AAAA,kCAGhB,SAAS,EAAE;AAAA;AAAA,YAEjC,GAAG,mBAAmB;AAAA,MAC1B,YAAYA;AAAA;AAAA;AAAA,mCAGe,SAAS,eAAe;AAAA;AAAA,qCAEtB,SAAS,EAAE;AAAA;AAAA;AAAA;AAAA,eAIjC,GAAG,YAAY;AAAA,MACtB,eAAeA;AAAA,mBACJ,KAAK,MAAM,SAAS,IAAI;AAAA,kBACzB,KAAK,SAAS,MAAM,SAAS,EAAE;AAAA,kBAC/B,KAAK,IAAI;AAAA,qBACN,KAAK,SAAS;AAAA;AAAA,WAExB,GAAG,eAAe;AAAA,MACrB,oBAAoBA;AAAA,mBACT,KAAK,WAAW,SAAS,IAAI;AAAA,kBAC9B,KAAK,SAAS,MAAM,SAAS,EAAE;AAAA,kBAC/B,KAAK,IAAI;AAAA,qBACN,KAAK,SAAS;AAAA;AAAA,WAExB,GAAG,oBAAoB;AAAA,MAC1B,uBAAuBA;AAAA;AAAA;AAAA;AAAA,4BAIH,SAAS,eAAe;AAAA;AAAA;AAAA,oCAGhB,SAAS,EAAE;AAAA;AAAA;AAAA,WAGpC,GAAG,uBAAuB;AAAA,MAC7B,cAAcA;AAAA;AAAA,kCAEY,SAAS,EAAE;AAAA,WAClC,GAAG,cAAc;AAAA,MACpB,UAAUA;AAAA;AAAA,kCAEgB,SAAS,EAAE;AAAA,WAClC,GAAG,UAAU;AAAA,IAClB,CAAC,EACA,KAAK,QAAQ,EACb,MAAM,KAAK,EACX,QAAQD,MAAK,SAAS,SAAS,CAAC,EAChC,MAAM,KAAK,EACX,OAAO,MAAM;AAGhB,QAAI,eAAe;AACnB,QAAI,UAAU,WAAW,YAAY;AACnC,YAAM,eAAe,WAAW,WAAW,WAAW,WAAW,yBAAyB,yBAAyB;AACnH,qBAAe,KAAK,OAAO,CAAC,MAAM,EAAE,kBAAkB,YAAY;AAAA,IACpE;AAEA,UAAM,QAAQ,aAAa,IAAI,CAAC,MAAM;AACpC,YAAM,aAAa,EAAE,WAAW,aAAuB,EAAE,iBAAmC;AAC5F,aAAO;AAAA,QACL,IAAI,EAAE;AAAA,QACN,OAAO,EAAE;AAAA,QACT,MAAM,EAAE,QAAQ;AAAA,QAChB,UAAU,EAAE;AAAA,QACZ,aAAa,EAAE,eAAe;AAAA,QAC9B,QAAQ;AAAA,QACR,mBAAmB,EAAE;AAAA,QACrB,uBAAuB,EAAE;AAAA,QACzB,eAAe,qBAAqB,YAAY,EAAE,mBAAmB,EAAE,qBAAqB;AAAA,QAC5F,WAAW,EAAE;AAAA,QACb,WAAW,EAAE;AAAA,QACb,YAAY,EAAE;AAAA,QACd,eAAe,EAAE;AAAA,QACjB,oBAAoB,EAAE;AAAA,QACtB,cAAc,EAAE;AAAA,QAChB,UAAU,EAAE;AAAA,QACZ,iBAAiB,EAAE;AAAA,MACrB;AAAA,IACF,CAAC;AAED,UAAM,CAAC,WAAW,IAAI,MAAM,KAAK,GAC9B,OAAO,EAAE,OAAOE,OAAM,EAAE,CAAC,EACzB,KAAK,QAAQ,EACb,MAAM,KAAK;AAEd,WAAO,EAAE,OAAO,OAAO,YAAY,MAAM;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,OAAO,UAAkB,IAAY,MAAyB;AAClE,UAAM,WAAW,MAAM,KAAK,SAAS,UAAU,EAAE;AACjD,QAAI,CAAC,SAAU,QAAO;AAEtB,UAAM,YAAY,SAAS;AAC3B,QAAI,CAAC,UAAW,QAAO;AAEvB,WAAO,MAAM,KAAK,GAAG,YAAY,OAAO,OAAO;AAC7C,UAAI,KAAK,SAAS;AAChB,cAAM,KAAK,KAAK;AAChB,cAAM,gBAAgB,SAAS;AAC/B,cAAM,cACJ,kBAAkB,YAAY,CAAC,KAAK,kBAChC,EAAE,QAAQ,wBAAiC,mBAAmB,KAAK,IACnE,kBAAkB,UAChB,EAAE,QAAQ,uBAAgC,IAC1C,CAAC;AAET,cAAM,GACH,OAAO,eAAe,EACtB,IAAI;AAAA,UACH,MAAM,GAAG,SAAS;AAAA,UAClB,UAAU,GAAG,SAAS;AAAA,UACtB,SAAS,KAAK,WAAW,SAAS;AAAA,UAClC,aAAa,GAAG,SAAS;AAAA,UACzB,GAAG;AAAA,QACL,CAAC,EACA,MAAMJ,IAAG,gBAAgB,IAAI,SAAS,CAAC;AAE1C,cAAM,GACH,OAAO,QAAQ,EACf,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC,EACvB,MAAMA,IAAG,SAAS,IAAI,EAAE,CAAC;AAE5B,cAAM,gBAAgB,KAAK,aAAa,GAAG;AAC3C,YAAI,kBAAkB,QAAW;AAC/B,gBAAM,GAAG,OAAO,gBAAgB,EAAE,MAAMA,IAAG,iBAAiB,WAAW,SAAS,CAAC;AACjF,gBAAM,OAAO,OAAO,QAAQ,aAAa,EAAE,IAAI,CAAC,CAAC,MAAM,GAAG,OAAO;AAAA,YAC/D;AAAA,YACA;AAAA,YACA,QAAQ,IAAI;AAAA,YACZ,aAAa,IAAI,eAAe;AAAA,YAChC,UAAU,IAAI;AAAA,YACd,WAAW,IAAI;AAAA,YACf,OAAO,IAAI,SAAS;AAAA,UACtB,EAAE;AACF,cAAI,KAAK,SAAS,GAAG;AACnB,kBAAM,GAAG,OAAO,gBAAgB,EAAE,OAAO,IAAI;AAAA,UAC/C;AAAA,QACF;AAEA,cAAM,GAAG,OAAO,YAAY,EAAE,MAAMA,IAAG,aAAa,WAAW,SAAS,CAAC;AACzE,cAAM,YAAY,IAAI,WAAW,GAAG,OAAO,IAAI;AAAA,MACjD,WAAW,KAAK,YAAY,QAAW;AACrC,cAAM,GACH,OAAO,eAAe,EACtB,IAAI,EAAE,SAAS,KAAK,QAAQ,CAAC,EAC7B,MAAMA,IAAG,gBAAgB,IAAI,SAAS,CAAC;AAAA,MAC5C;AAEA,UAAI,CAAC,KAAK,WAAW,KAAK,cAAc,QAAW;AACjD,cAAM,GAAG,OAAO,gBAAgB,EAAE,MAAMA,IAAG,iBAAiB,WAAW,SAAS,CAAC;AACjF,cAAM,OAAO,OAAO,QAAQ,KAAK,SAAS,EAAE,IAAI,CAAC,CAAC,MAAM,GAAG,OAAO;AAAA,UAChE;AAAA,UACA;AAAA,UACA,QAAQ,IAAI;AAAA,UACZ,aAAa,IAAI,eAAe;AAAA,UAChC,UAAU,IAAI;AAAA,UACd,WAAW,IAAI;AAAA,UACf,OAAO,IAAI,SAAS;AAAA,QACtB,EAAE;AACF,YAAI,KAAK,SAAS,GAAG;AACnB,gBAAM,GAAG,OAAO,gBAAgB,EAAE,OAAO,IAAI;AAAA,QAC/C;AAAA,MACF;AAEA,UAAI,KAAK,aAAa,QAAW;AAC/B,cAAM,GAAG,OAAO,eAAe,EAAE,MAAMA,IAAG,gBAAgB,WAAW,SAAS,CAAC;AAC/E,YAAI,KAAK,UAAU;AACjB,gBAAM,GAAG,OAAO,eAAe,EAAE,OAAO,EAAE,WAAW,GAAG,KAAK,SAAS,CAAC;AAAA,QACzE;AAAA,MACF;AAEA,UAAI,KAAK,YAAY,QAAW;AAC9B,cAAM,GAAG,OAAO,cAAc,EAAE,MAAMA,IAAG,eAAe,WAAW,SAAS,CAAC;AAC7E,cAAM,aAAa,OAAO,QAAQ,KAAK,OAAO,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,OAAO;AAAA,UACnE;AAAA,UACA;AAAA,UACA,gBAAgB;AAAA,QAClB,EAAE;AACF,YAAI,WAAW,SAAS,GAAG;AACzB,gBAAM,GAAG,OAAO,cAAc,EAAE,OAAO,UAAU;AAAA,QACnD;AAAA,MACF;AAEA,aAAO,MAAM,KAAK,SAAS,UAAU,EAAE;AAAA,IACzC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YACJ,UACA,IACA,MASA;AACA,UAAM,WAAW,MAAM,KAAK,SAAS,UAAU,EAAE;AACjD,QAAI,CAAC,SAAU,QAAO;AAEtB,UAAM,YAAY,SAAS;AAC3B,QAAI,CAAC,UAAW,QAAO;AACvB,QAAI,CAAC,WAAW,SAAS,aAA8B,EAAG,QAAO;AAEjE,UAAM,SAAS,MAAM,KAAK,SAAS,cAAc,UAAU,IAAI,WAAW;AAAA,MACxE,GAAG;AAAA,IACL,CAAC;AACD,QAAI,CAAC,OAAQ,QAAO;AAGpB,WAAO,MAAM,KAAK,SAAS,UAAU,EAAE;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cACJ,UACA,IACA,MASA;AACA,UAAM,WAAW,MAAM,KAAK,SAAS,UAAU,EAAE;AACjD,QAAI,CAAC,SAAU,QAAO;AAEtB,UAAM,YAAY,SAAS;AAC3B,QAAI,CAAC,UAAW,QAAO;AAEvB,UAAM,SAAS,MAAM,KAAK,SAAS,gBAAgB,UAAU,IAAI,WAAW,IAAI;AAChF,QAAI,CAAC,OAAQ,QAAO;AAEpB,WAAO,MAAM,KAAK,SAAS,UAAU,EAAE;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,UAAkB,IAAY,QAAuB;AACtE,QAAI,WAAW,YAAY;AACzB,YAAM,SAAS,MAAM,KAAK,GACvB,OAAO,QAAQ,EACf,IAAI,EAAE,UAAU,KAAK,CAAC,EACtB,MAAMC,KAAID,IAAG,SAAS,IAAI,EAAE,GAAGA,IAAG,SAAS,UAAU,QAAQ,CAAC,CAAC,EAC/D,UAAU,EAAE,IAAI,SAAS,GAAG,CAAC;AAChC,aAAO,OAAO,SAAS;AAAA,IACzB;AAEA,QAAI,WAAW,UAAU;AACvB,YAAMK,MAAK,MAAM,KAAK,GAAG,MAAM,SAAS,UAAU;AAAA,QAChD,OAAOJ,KAAID,IAAG,SAAS,IAAI,EAAE,GAAGA,IAAG,SAAS,UAAU,QAAQ,CAAC;AAAA,MACjE,CAAC;AACD,UAAI,CAACK,IAAI,QAAO;AAEhB,UAAIA,IAAG,UAAU;AACf,cAAM,KAAK,GACR,OAAO,QAAQ,EACf,IAAI,EAAE,UAAU,MAAM,CAAC,EACvB,MAAML,IAAG,SAAS,IAAI,EAAE,CAAC;AAC5B,eAAO;AAAA,MACT;AAEA,UAAIK,IAAG,iBAAiB;AACtB,cAAM,CAAC,GAAG,IAAI,MAAM,KAAK,GACtB,OAAO,EACP,KAAK,eAAe,EACpB,MAAML,IAAG,gBAAgB,IAAIK,IAAG,eAAe,CAAC;AACnD,YAAI,OAAO,IAAI,WAAW,wBAAwB;AAChD,gBAAM,KAAK,GACR,OAAO,eAAe,EACtB,IAAI,EAAE,QAAQ,UAAU,aAAa,oBAAI,KAAK,EAAE,CAAC,EACjD,MAAML,IAAG,gBAAgB,IAAIK,IAAG,eAAe,CAAC;AACnD,iBAAO;AAAA,QACT;AAAA,MACF;AAEA,YAAM,YAAY,MAAM,KAAK,GAAG,MAAM,gBAAgB,UAAU;AAAA,QAC9D,OAAOJ;AAAA,UACLD,IAAG,gBAAgB,WAAW,EAAE;AAAA,UAChCA,IAAG,gBAAgB,QAAQ,sBAAsB;AAAA,QACnD;AAAA,QACA,SAAS,CAACE,MAAK,gBAAgB,aAAa,CAAC;AAAA,MAC/C,CAAC;AACD,UAAI,WAAW;AACb,cAAM,KAAK,GACR,OAAO,eAAe,EACtB,IAAI,EAAE,QAAQ,UAAU,aAAa,oBAAI,KAAK,EAAE,CAAC,EACjD,MAAMF,IAAG,gBAAgB,IAAI,UAAU,EAAE,CAAC;AAC7C,cAAM,KAAK,GACR,OAAO,QAAQ,EACf,IAAI,EAAE,iBAAiB,UAAU,GAAG,CAAC,EACrC,MAAMA,IAAG,SAAS,IAAI,EAAE,CAAC;AAC5B,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAEA,UAAM,KAAK,MAAM,KAAK,GAAG,MAAM,SAAS,UAAU;AAAA,MAChD,OAAOC,KAAID,IAAG,SAAS,IAAI,EAAE,GAAGA,IAAG,SAAS,UAAU,QAAQ,CAAC;AAAA,IACjE,CAAC;AACD,QAAI,CAAC,GAAI,QAAO;AAEhB,UAAM,kBAAkB,GAAG;AAC3B,QAAI,CAAC,iBAAiB;AACpB,YAAM,YAAY,MAAM,KAAK,GAAG,MAAM,gBAAgB,UAAU;AAAA,QAC9D,OAAOA,IAAG,gBAAgB,WAAW,EAAE;AAAA,QACvC,SAAS,CAACE,MAAK,gBAAgB,aAAa,CAAC;AAAA,MAC/C,CAAC;AACD,UAAI,WAAW;AACb,cAAM,KAAK,GACR,OAAO,eAAe,EACtB,IAAI,EAAE,OAAO,CAAC,EACd,MAAMF,IAAG,gBAAgB,IAAI,UAAU,EAAE,CAAC;AAC7C,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAEA,UAAM,KAAK,GACR,OAAO,eAAe,EACtB,IAAI,EAAE,OAAO,CAAC,EACd,MAAMA,IAAG,gBAAgB,IAAI,eAAe,CAAC;AAChD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU,UAAkB,IAA2C;AAC3E,UAAM,KAAK,MAAM,KAAK,GAAG,MAAM,SAAS,UAAU;AAAA,MAChD,OAAOC,KAAID,IAAG,SAAS,IAAI,EAAE,GAAGA,IAAG,SAAS,UAAU,QAAQ,CAAC;AAAA,MAC/D,SAAS,EAAE,IAAI,MAAM,UAAU,MAAM,iBAAiB,KAAK;AAAA,IAC7D,CAAC;AACD,QAAI,CAAC,GAAI,QAAO;AAChB,QAAI,GAAG,SAAU,QAAO;AAExB,UAAM,QAAQ,GAAG;AACjB,QAAI,OAAO;AACT,YAAM,CAAC,GAAG,IAAI,MAAM,KAAK,GACtB,OAAO,EAAE,QAAQ,gBAAgB,OAAO,CAAC,EACzC,KAAK,eAAe,EACpB,MAAMA,IAAG,gBAAgB,IAAI,KAAK,CAAC;AACtC,UAAI,IAAK,QAAO,IAAI;AAAA,IACtB;AAEA,UAAM,YAAY,MAAM,KAAK,GAAG,MAAM,gBAAgB,UAAU;AAAA,MAC9D,OAAOA,IAAG,gBAAgB,WAAW,EAAE;AAAA,MACvC,SAAS,CAACE,MAAK,gBAAgB,aAAa,CAAC;AAAA,MAC7C,SAAS,EAAE,QAAQ,KAAK;AAAA,IAC1B,CAAC;AACD,WAAQ,WAAW,UAA4B;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,mBAAmB,UAAkB,WAAmB,OAAe;AAC3E,UAAM,KAAK,MAAM,KAAK,GAAG,MAAM,SAAS,UAAU;AAAA,MAChD,OAAOD,KAAID,IAAG,SAAS,IAAI,SAAS,GAAGA,IAAG,SAAS,UAAU,QAAQ,CAAC;AAAA,IACxE,CAAC;AACD,QAAI,CAAC,GAAI,QAAO;AAEhB,UAAM,YAAY,MAAM,KAAK,GAAG,MAAM,gBAAgB,UAAU;AAAA,MAC9D,OAAOA,IAAG,gBAAgB,WAAW,SAAS;AAAA,MAC9C,SAAS,CAACE,MAAK,gBAAgB,aAAa,CAAC;AAAA,IAC/C,CAAC;AACD,QAAI,CAAC,UAAW,QAAO;AAEvB,WAAO,MAAM,KAAK,SAAS,mBAAmB,UAAU,IAAI,KAAK;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,qBAAqB,UAAkB,WAAmB;AAC9D,UAAM,YAAY,MAAM,KAAK,GAAG,MAAM,gBAAgB,UAAU;AAAA,MAC9D,OAAOF,IAAG,gBAAgB,WAAW,SAAS;AAAA,MAC9C,SAAS,CAACE,MAAK,gBAAgB,aAAa,CAAC;AAAA,IAC/C,CAAC;AACD,QAAI,CAAC,UAAW,QAAO;AACvB,WAAO,MAAM,KAAK,SAAS,qBAAqB,UAAU,EAAE;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,UAAU,UAAkB,UAAkB,WAAoD;AACtG,UAAM,SAAS,MAAM,KAAK,SAAS,UAAU,QAAQ;AACrD,QAAI,CAAC,OAAQ,QAAO;AAEpB,WAAO,MAAM,KAAK,GAAG,YAAY,OAAO,OAAO;AAC7C,YAAM,CAAC,KAAK,IAAI,MAAM,GAAG,OAAO,QAAQ,EAAE,OAAO;AAAA,QAC/C;AAAA,QACA,OAAO,GAAG,OAAO,KAAK;AAAA,QACtB,WAAW,aAAa;AAAA,MAC1B,CAAC,EAAE,UAAU;AAGb,YAAM,SAAS,MAAM,KAAK,SAAS,qBAAqB,IAAI,MAAM,IAAI;AAAA,QACpE,MAAM,OAAO;AAAA,QACb,UAAU,OAAO;AAAA,QACjB,SAAS,OAAO;AAAA,QAChB,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC,WAAW,aAAa;AAAA,MAC1B,CAAC;AAGD,UAAI,OAAO,kBAAkB;AAC3B,cAAM,EAAE,iBAAAI,iBAAgB,IAAI,MAAM,OAAO,oCAA2B;AACpE,cAAMA,iBAAgB,IAAI,OAAO,kBAAkB,OAAO,EAAE;AAAA,MAC9D;AAEA,aAAO,EAAE,IAAI,MAAM,GAAG;AAAA,IACxB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WACJ,UACA,WACA,SACkB;AAClB,UAAM,YAAY,MAAM,KAAK,GAAG,MAAM,gBAAgB,UAAU;AAAA,MAC9D,OAAON,IAAG,gBAAgB,WAAW,SAAS;AAAA,MAC9C,SAAS,CAACE,MAAK,gBAAgB,aAAa,CAAC;AAAA,IAC/C,CAAC;AACD,QAAI,CAAC,UAAW,QAAO;AAEvB,WAAO,MAAM,KAAK,SAAS,WAAW,UAAU,WAAW,UAAU,IAAI,OAAO;AAAA,EAClF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,UAAkB,IAA8B;AAC3D,UAAM,SAAS,MAAM,KAAK,GACvB,OAAO,QAAQ,EACf,MAAMD,KAAID,IAAG,SAAS,IAAI,EAAE,GAAGA,IAAG,SAAS,UAAU,QAAQ,CAAC,CAAC,EAC/D,UAAU,EAAE,IAAI,SAAS,GAAG,CAAC;AAChC,WAAO,OAAO,SAAS;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,UAAkB,IAA8B;AAC5D,UAAM,SAAS,MAAM,KAAK,GACvB,OAAO,QAAQ,EACf,IAAI,EAAE,UAAU,KAAK,CAAC,EACtB,MAAMC,KAAID,IAAG,SAAS,IAAI,EAAE,GAAGA,IAAG,SAAS,UAAU,QAAQ,CAAC,CAAC,EAC/D,UAAU,EAAE,IAAI,SAAS,GAAG,CAAC;AAChC,WAAO,OAAO,SAAS;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,UAAkB,IAA8B;AAC3D,UAAM,SAAS,MAAM,KAAK,GACvB,OAAO,QAAQ,EACf,IAAI,EAAE,UAAU,MAAM,CAAC,EACvB,MAAMC,KAAID,IAAG,SAAS,IAAI,EAAE,GAAGA,IAAG,SAAS,UAAU,QAAQ,CAAC,CAAC,EAC/D,UAAU,EAAE,IAAI,SAAS,GAAG,CAAC;AAChC,WAAO,OAAO,SAAS;AAAA,EACzB;AACF;","names":["eq","and","desc","sql","count","eq","and","desc","sql","count","rb","copyVersionData"]}
@@ -0,0 +1,275 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/browser/snapshot-filter.ts
4
+ var KEEP_ROLES = /* @__PURE__ */ new Set([
5
+ "heading",
6
+ "navigation",
7
+ "main",
8
+ "banner",
9
+ "form",
10
+ "dialog",
11
+ "alertdialog",
12
+ "alert",
13
+ "region",
14
+ "search",
15
+ "tablist",
16
+ "tab",
17
+ "tabpanel",
18
+ "menu",
19
+ "menubar",
20
+ "menuitem",
21
+ "toolbar",
22
+ "radiogroup"
23
+ ]);
24
+ var NO_COLLAPSE_ROLES = /* @__PURE__ */ new Set([
25
+ "radio",
26
+ "checkbox",
27
+ "option",
28
+ "tab",
29
+ "menuitemradio",
30
+ "menuitemcheckbox",
31
+ "textbox"
32
+ ]);
33
+ var HIDDEN_PATTERNS = [
34
+ /\[hidden\]/,
35
+ /\[aria-hidden=true\]/,
36
+ /\[aria-hidden="true"\]/
37
+ ];
38
+ var SEMANTIC_NONE_ROLE_PATTERN = /^\s*(presentation|none)\b/;
39
+ var PAGINATION_TEXT_PATTERN = /\bpage\s+\d+\s+(?:of|\/)\s+\d+\b|\bshowing\s+\d+[\s\-–]+\d+\s+of\s+\d+\b|\d+\s*[\-–]\s*\d+\s+of\s+\d+\b|\d+\s*\/\s*\d+\s*ページ|\d+件中/i;
40
+ function filterSnapshot(snapshot, options) {
41
+ const lines = snapshot.split("\n");
42
+ const originalCount = lines.length;
43
+ const keepIndices = /* @__PURE__ */ new Set();
44
+ const refPattern = /\[ref=e\d+\]/;
45
+ const indentStack = [];
46
+ for (let i = 0; i < lines.length; i++) {
47
+ const line = lines[i];
48
+ const trimmed = line.trimStart();
49
+ const indent = line.length - trimmed.length;
50
+ while (indentStack.length > 0 && indentStack[indentStack.length - 1].indent >= indent) {
51
+ indentStack.pop();
52
+ }
53
+ indentStack.push({ indent, idx: i });
54
+ const hasRef = refPattern.test(line);
55
+ if (hasRef) {
56
+ keepIndices.add(i);
57
+ continue;
58
+ }
59
+ const roleMatch = trimmed.match(/^(\S+)/);
60
+ if (roleMatch && KEEP_ROLES.has(roleMatch[1])) {
61
+ if (!isHiddenLine(line)) {
62
+ keepIndices.add(i);
63
+ }
64
+ }
65
+ if (!keepIndices.has(i) && PAGINATION_TEXT_PATTERN.test(trimmed)) {
66
+ if (!isHiddenLine(line)) {
67
+ keepIndices.add(i);
68
+ }
69
+ }
70
+ }
71
+ const sortedKeepIndices = [...keepIndices].sort((a, b) => a - b);
72
+ const collapsedResult = collapseRedundantLists(lines, sortedKeepIndices);
73
+ const filledSelectors = options?.filledSelectors;
74
+ if (filledSelectors && filledSelectors.size >= 3) {
75
+ const filledIndices = [];
76
+ for (const idx of collapsedResult.keptIndices) {
77
+ const line = lines[idx];
78
+ if (!line) continue;
79
+ const refMatch = line.match(/\[ref=(e\d+)\]/);
80
+ if (refMatch) {
81
+ const ref = `@${refMatch[1]}`;
82
+ if (filledSelectors.has(ref)) {
83
+ filledIndices.push(idx);
84
+ }
85
+ }
86
+ }
87
+ if (filledIndices.length >= 3) {
88
+ const filledSet = new Set(filledIndices);
89
+ collapsedResult.keptIndices = collapsedResult.keptIndices.filter(
90
+ (idx) => !filledSet.has(idx)
91
+ );
92
+ const firstFilledIdx = filledIndices[0];
93
+ const firstLine = lines[firstFilledIdx];
94
+ const indent = firstLine ? Math.floor((firstLine.length - firstLine.trimStart().length) / 2) : 2;
95
+ collapsedResult.collapseMarkers.push({
96
+ afterLineIndex: firstFilledIdx > 0 ? firstFilledIdx - 1 : 0,
97
+ omittedCount: filledIndices.length,
98
+ indentLevel: indent
99
+ });
100
+ }
101
+ }
102
+ const parentIndices = /* @__PURE__ */ new Set();
103
+ for (const idx of collapsedResult.keptIndices) {
104
+ const line = lines[idx];
105
+ if (!line) continue;
106
+ const indent = line.length - line.trimStart().length;
107
+ if (indent > 0) {
108
+ for (let j = idx - 1; j >= 0; j--) {
109
+ const parentLine = lines[j];
110
+ if (!parentLine) continue;
111
+ const parentIndent = parentLine.length - parentLine.trimStart().length;
112
+ if (parentIndent < indent && parentLine.trimStart().length > 0) {
113
+ parentIndices.add(j);
114
+ break;
115
+ }
116
+ }
117
+ }
118
+ }
119
+ const finalIndices = new Set(collapsedResult.keptIndices);
120
+ for (const idx of parentIndices) {
121
+ finalIndices.add(idx);
122
+ }
123
+ const filteredLines = [];
124
+ const finalSorted = [...finalIndices].sort((a, b) => a - b);
125
+ for (const idx of finalSorted) {
126
+ const line = lines[idx];
127
+ if (line.length > 300) {
128
+ const refMatch = line.match(/\s*\[ref=e\d+\].*$/);
129
+ if (refMatch) {
130
+ const refSuffix = refMatch[0];
131
+ const maxContent = 300 - refSuffix.length - 3;
132
+ filteredLines.push(
133
+ maxContent > 0 ? line.slice(0, maxContent) + "..." + refSuffix : line.slice(0, 297) + "..."
134
+ );
135
+ } else {
136
+ filteredLines.push(line.slice(0, 297) + "...");
137
+ }
138
+ } else {
139
+ filteredLines.push(line);
140
+ }
141
+ }
142
+ for (const marker of collapsedResult.collapseMarkers) {
143
+ const insertAfterIdx = filteredLines.findIndex((_, i) => {
144
+ const originalIdx = finalSorted[i];
145
+ return originalIdx !== void 0 && originalIdx >= marker.afterLineIndex;
146
+ });
147
+ if (insertAfterIdx >= 0) {
148
+ const indent = " ".repeat(marker.indentLevel);
149
+ filteredLines.splice(insertAfterIdx + 1, 0, `${indent}[... ${marker.omittedCount}\u4EF6\u7701\u7565]`);
150
+ }
151
+ }
152
+ if (filteredLines.length > 300) {
153
+ const truncatedCount = filteredLines.length;
154
+ filteredLines.length = 300;
155
+ filteredLines.push(`[... ${truncatedCount - 300}\u884C\u7701\u7565]`);
156
+ }
157
+ const filteredCount = filteredLines.length;
158
+ const estimatedTokens = Math.ceil(filteredLines.join("\n").length / 4);
159
+ const meta = `[\u30D5\u30A3\u30EB\u30BF\u6E08\u307F: ${originalCount}\u884C \u2192 ${filteredCount}\u884C, \u63A8\u5B9A ~${estimatedTokens} tokens]`;
160
+ return `${meta}
161
+ ${filteredLines.join("\n")}`;
162
+ }
163
+ function isHiddenLine(line) {
164
+ return HIDDEN_PATTERNS.some((p) => p.test(line)) || SEMANTIC_NONE_ROLE_PATTERN.test(line.trimStart());
165
+ }
166
+ function collapseRedundantLists(lines, sortedIndices) {
167
+ const keptIndices = [];
168
+ const collapseMarkers = [];
169
+ const refPattern = /\[ref=e\d+\]/;
170
+ const roleCache = /* @__PURE__ */ new Map();
171
+ function getCachedRole(idx) {
172
+ let role = roleCache.get(idx);
173
+ if (role === void 0) {
174
+ role = extractRole(lines[idx]);
175
+ roleCache.set(idx, role);
176
+ }
177
+ return role;
178
+ }
179
+ let i = 0;
180
+ while (i < sortedIndices.length) {
181
+ const startIdx = sortedIndices[i];
182
+ const startLine = lines[startIdx];
183
+ if (!startLine) {
184
+ keptIndices.push(startIdx);
185
+ i++;
186
+ continue;
187
+ }
188
+ if (!refPattern.test(startLine)) {
189
+ keptIndices.push(startIdx);
190
+ i++;
191
+ continue;
192
+ }
193
+ const indent = startLine.length - startLine.trimStart().length;
194
+ const role = getCachedRole(startIdx);
195
+ if (!role) {
196
+ keptIndices.push(startIdx);
197
+ i++;
198
+ continue;
199
+ }
200
+ let runLength = 1;
201
+ let j = i + 1;
202
+ while (j < sortedIndices.length) {
203
+ const nextIdx = sortedIndices[j];
204
+ const nextLine = lines[nextIdx];
205
+ if (!nextLine || !refPattern.test(nextLine)) break;
206
+ const nextIndent = nextLine.length - nextLine.trimStart().length;
207
+ const nextRole = getCachedRole(nextIdx);
208
+ if (nextIndent !== indent || nextRole !== role) break;
209
+ runLength++;
210
+ j++;
211
+ }
212
+ const MAX_UNIQUE_NO_COLLAPSE = 15;
213
+ if (runLength >= 3 && !NO_COLLAPSE_ROLES.has(role)) {
214
+ let allUniqueNames = runLength <= MAX_UNIQUE_NO_COLLAPSE;
215
+ if (allUniqueNames) {
216
+ const names = /* @__PURE__ */ new Set();
217
+ let hasDuplicate = false;
218
+ for (let k = i; k < j; k++) {
219
+ const name = extractName(lines[sortedIndices[k]]);
220
+ if (!name) continue;
221
+ if (names.has(name)) {
222
+ hasDuplicate = true;
223
+ break;
224
+ }
225
+ names.add(name);
226
+ }
227
+ if (hasDuplicate || names.size === 0) {
228
+ allUniqueNames = false;
229
+ }
230
+ }
231
+ if (allUniqueNames) {
232
+ for (let k = i; k < j; k++) {
233
+ keptIndices.push(sortedIndices[k]);
234
+ }
235
+ i = j;
236
+ } else {
237
+ for (let k = i; k < i + 2; k++) {
238
+ keptIndices.push(sortedIndices[k]);
239
+ }
240
+ collapseMarkers.push({
241
+ afterLineIndex: sortedIndices[i + 1],
242
+ omittedCount: runLength - 2,
243
+ indentLevel: Math.floor(indent / 2)
244
+ });
245
+ i = j;
246
+ }
247
+ } else {
248
+ for (let k = i; k < j; k++) {
249
+ keptIndices.push(sortedIndices[k]);
250
+ }
251
+ i = j;
252
+ }
253
+ }
254
+ return { keptIndices, collapseMarkers };
255
+ }
256
+ function extractName(line) {
257
+ const trimmed = line.trimStart().replace(/^-\s+/, "");
258
+ const nameMatch = trimmed.match(/"([^"]*)"/);
259
+ return nameMatch ? nameMatch[1] : null;
260
+ }
261
+ function extractRole(line) {
262
+ const trimmed = line.trimStart();
263
+ const cleaned = trimmed.replace(/^-\s+/, "");
264
+ const roleBeforeRef = cleaned.match(/^(\S+)(?:\s+"[^"]*")?\s*\[ref=e\d+\]/);
265
+ if (roleBeforeRef) return roleBeforeRef[1];
266
+ const refFirst = cleaned.match(/\[ref=e\d+\]\s+(\S+)/);
267
+ if (refFirst) return refFirst[1];
268
+ const roleMatch = cleaned.match(/^(\S+)/);
269
+ return roleMatch ? roleMatch[1] : null;
270
+ }
271
+
272
+ export {
273
+ filterSnapshot
274
+ };
275
+ //# sourceMappingURL=chunk-XMFCXPYU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/browser/snapshot-filter.ts"],"sourcesContent":["/**\n * snapshot-filter — スナップショットフィルタリング\n *\n * 非インタラクティブ要素を除去してトークン使用量を削減する。\n * BrowserUse の DOM filtering pipeline、Stagehand の accessibility tree 最適化を参考。\n *\n * パイプライン:\n * Stage 1: ref + ロール判定で保持行を特定(既存)\n * Stage 2: 非表示要素([hidden], aria-hidden)を除去\n * Stage 3: 冗長リスト縮約(同一ロールの連続要素を圧縮)\n * Stage 4: 親インデント追加 + 行数制限 + トークン見積もり\n */\n\n/** 保持するロール(heading/landmark/インタラクティブ関連) */\nconst KEEP_ROLES = new Set([\n \"heading\",\n \"navigation\",\n \"main\",\n \"banner\",\n \"form\",\n \"dialog\",\n \"alertdialog\",\n \"alert\",\n \"region\",\n \"search\",\n \"tablist\",\n \"tab\",\n \"tabpanel\",\n \"menu\",\n \"menubar\",\n \"menuitem\",\n \"toolbar\",\n \"radiogroup\",\n]);\n\n/** 各オプションが意味的に固有であり、縮約してはならないロール */\nconst NO_COLLAPSE_ROLES = new Set([\n \"radio\",\n \"checkbox\",\n \"option\",\n \"tab\",\n \"menuitemradio\",\n \"menuitemcheckbox\",\n \"textbox\",\n]);\n\n/** 非表示を示す属性パターン */\nconst HIDDEN_PATTERNS = [\n /\\[hidden\\]/,\n /\\[aria-hidden=true\\]/,\n /\\[aria-hidden=\"true\"\\]/,\n];\n\n/** 意味を持たないロール(WAI-ARIA: presentation/none は装飾要素を示す) */\nconst SEMANTIC_NONE_ROLE_PATTERN = /^\\s*(presentation|none)\\b/;\n\n/**\n * ページネーションコンテキストのテキストパターン。\n * [ref] や KEEP_ROLES がなくても保持する。\n * AI がページネーション完了を判断するために必要。\n *\n * マッチ例:\n * - \"Page 1 of 12\", \"Page 1/12\"\n * - \"Showing 1-100 of 1120 users\", \"Showing 1–100 of 1120\"\n * - \"1-100 of 1120\"\n * - Japanese: \"1 / 12 ページ\", \"1120件中 1-100件\"\n */\nconst PAGINATION_TEXT_PATTERN =\n /\\bpage\\s+\\d+\\s+(?:of|\\/)\\s+\\d+\\b|\\bshowing\\s+\\d+[\\s\\-–]+\\d+\\s+of\\s+\\d+\\b|\\d+\\s*[\\-–]\\s*\\d+\\s+of\\s+\\d+\\b|\\d+\\s*\\/\\s*\\d+\\s*ページ|\\d+件中/i;\n\n/**\n * スナップショットから非インタラクティブ要素を除去\n *\n * 保持する行:\n * 1. [ref=eN] を含む行(インタラクティブ要素)\n * 2. heading/landmark ロール行\n * 3. 保持行の親インデント(ネスト構造の文脈保持)\n *\n * 除去する行: 静的テキスト、separator, generic, 装飾要素、非表示要素\n */\n/** スナップショットフィルタのオプション */\nexport interface SnapshotFilterOptions {\n /** 入力済みフィールドのセレクタ集合(@eN形式)。3件以上あればサマリーに圧縮 */\n filledSelectors?: Set<string>;\n}\n\nexport function filterSnapshot(snapshot: string, options?: SnapshotFilterOptions): string {\n const lines = snapshot.split(\"\\n\");\n const originalCount = lines.length;\n\n // Stage 1+2 統合: 保持行の特定と非表示除去を1パスで実行\n // 同時にインデント情報をキャッシュして Stage 4 の O(n²) 親探索を回避\n const keepIndices = new Set<number>();\n const refPattern = /\\[ref=e\\d+\\]/;\n\n // インデント → 最新行インデックスのスタック(親探索用)\n // スタック要素: [indent, lineIndex] を降順に保持\n const indentStack: Array<{ indent: number; idx: number }> = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const trimmed = line.trimStart();\n const indent = line.length - trimmed.length;\n\n // インデントスタック更新: 現在行より深い or 同等のエントリをポップ\n while (indentStack.length > 0 && indentStack[indentStack.length - 1].indent >= indent) {\n indentStack.pop();\n }\n indentStack.push({ indent, idx: i });\n\n const hasRef = refPattern.test(line);\n\n if (hasRef) {\n // ref 付き行は常に保持(非表示チェックしない — AI が判断する余地を残す)\n keepIndices.add(i);\n continue;\n }\n\n // heading/landmark ロールの行を保持(ただし非表示は除外)\n const roleMatch = trimmed.match(/^(\\S+)/);\n if (roleMatch && KEEP_ROLES.has(roleMatch[1])) {\n if (!isHiddenLine(line)) {\n keepIndices.add(i);\n }\n }\n\n // ページネーションコンテキスト: \"Page X of Y\" や \"Showing X-Y of Z\" を保持\n if (!keepIndices.has(i) && PAGINATION_TEXT_PATTERN.test(trimmed)) {\n if (!isHiddenLine(line)) {\n keepIndices.add(i);\n }\n }\n }\n\n // Stage 3: 冗長リスト縮約\n const sortedKeepIndices = [...keepIndices].sort((a, b) => a - b);\n const collapsedResult = collapseRedundantLists(lines, sortedKeepIndices);\n\n // Stage 3.5: 入力済みフォームフィールドの圧縮\n // 3件以上の入力済みフィールドをサマリー行に置換\n const filledSelectors = options?.filledSelectors;\n if (filledSelectors && filledSelectors.size >= 3) {\n const filledIndices: number[] = [];\n for (const idx of collapsedResult.keptIndices) {\n const line = lines[idx];\n if (!line) continue;\n const refMatch = line.match(/\\[ref=(e\\d+)\\]/);\n if (refMatch) {\n const ref = `@${refMatch[1]}`;\n if (filledSelectors.has(ref)) {\n filledIndices.push(idx);\n }\n }\n }\n\n if (filledIndices.length >= 3) {\n const filledSet = new Set(filledIndices);\n collapsedResult.keptIndices = collapsedResult.keptIndices.filter(\n idx => !filledSet.has(idx),\n );\n // 入力済みフィールドの最初の位置にサマリーマーカーを挿入\n const firstFilledIdx = filledIndices[0];\n const firstLine = lines[firstFilledIdx];\n const indent = firstLine ? Math.floor((firstLine.length - firstLine.trimStart().length) / 2) : 2;\n collapsedResult.collapseMarkers.push({\n afterLineIndex: firstFilledIdx > 0 ? firstFilledIdx - 1 : 0,\n omittedCount: filledIndices.length,\n indentLevel: indent,\n });\n }\n }\n\n // Stage 4: 親インデント追加(事前計算済みインデント情報を利用)\n // 各行の親を高速に引くため、行ごとのインデントをキャッシュして逆方向探索を最適化\n const parentIndices = new Set<number>();\n for (const idx of collapsedResult.keptIndices) {\n const line = lines[idx];\n if (!line) continue;\n const indent = line.length - line.trimStart().length;\n\n if (indent > 0) {\n // 直前の行から逆方向探索(多くの場合1-3行で見つかる)\n for (let j = idx - 1; j >= 0; j--) {\n const parentLine = lines[j];\n if (!parentLine) continue;\n const parentIndent = parentLine.length - parentLine.trimStart().length;\n if (parentIndent < indent && parentLine.trimStart().length > 0) {\n parentIndices.add(j);\n break;\n }\n }\n }\n }\n\n // 全保持行を統合\n const finalIndices = new Set<number>(collapsedResult.keptIndices);\n for (const idx of parentIndices) {\n finalIndices.add(idx);\n }\n\n // フィルタリング済み行を構築\n const filteredLines: string[] = [];\n const finalSorted = [...finalIndices].sort((a, b) => a - b);\n\n for (const idx of finalSorted) {\n const line = lines[idx];\n if (line.length > 300) {\n // ref suffix を保持して切り詰める\n const refMatch = line.match(/\\s*\\[ref=e\\d+\\].*$/);\n if (refMatch) {\n const refSuffix = refMatch[0];\n const maxContent = 300 - refSuffix.length - 3; // 3 = \"...\"\n filteredLines.push(\n maxContent > 0\n ? line.slice(0, maxContent) + \"...\" + refSuffix\n : line.slice(0, 297) + \"...\",\n );\n } else {\n filteredLines.push(line.slice(0, 297) + \"...\");\n }\n } else {\n filteredLines.push(line);\n }\n }\n\n // 縮約マーカーを挿入\n for (const marker of collapsedResult.collapseMarkers) {\n // マーカーの挿入位置を探す(最後に保持された行の後)\n const insertAfterIdx = filteredLines.findIndex((_, i) => {\n const originalIdx = finalSorted[i];\n return originalIdx !== undefined && originalIdx >= marker.afterLineIndex;\n });\n if (insertAfterIdx >= 0) {\n const indent = \" \".repeat(marker.indentLevel);\n filteredLines.splice(insertAfterIdx + 1, 0, `${indent}[... ${marker.omittedCount}件省略]`);\n }\n }\n\n // 出力行数リミット\n if (filteredLines.length > 300) {\n const truncatedCount = filteredLines.length;\n filteredLines.length = 300;\n filteredLines.push(`[... ${truncatedCount - 300}行省略]`);\n }\n\n const filteredCount = filteredLines.length;\n const estimatedTokens = Math.ceil(filteredLines.join(\"\\n\").length / 4);\n\n const meta = `[フィルタ済み: ${originalCount}行 → ${filteredCount}行, 推定 ~${estimatedTokens} tokens]`;\n\n return `${meta}\\n${filteredLines.join(\"\\n\")}`;\n}\n\n/** 行が非表示属性を含むか、または意味を持たないロールかを判定 */\nfunction isHiddenLine(line: string): boolean {\n return HIDDEN_PATTERNS.some((p) => p.test(line)) || SEMANTIC_NONE_ROLE_PATTERN.test(line.trimStart());\n}\n\ninterface CollapseMarker {\n afterLineIndex: number;\n omittedCount: number;\n indentLevel: number;\n}\n\ninterface CollapseResult {\n keptIndices: number[];\n collapseMarkers: CollapseMarker[];\n}\n\n/**\n * 同一インデント・同一ロールの [ref] 付き行が 3 個以上連続する場合、\n * 最初の 2 個 + マーカーに圧縮する。\n */\nfunction collapseRedundantLists(\n lines: string[],\n sortedIndices: number[],\n): CollapseResult {\n const keptIndices: number[] = [];\n const collapseMarkers: CollapseMarker[] = [];\n const refPattern = /\\[ref=e\\d+\\]/;\n\n // ロール抽出結果をキャッシュして同一行の再計算を回避\n const roleCache = new Map<number, string | null>();\n function getCachedRole(idx: number): string | null {\n let role = roleCache.get(idx);\n if (role === undefined) {\n role = extractRole(lines[idx]);\n roleCache.set(idx, role);\n }\n return role;\n }\n\n let i = 0;\n while (i < sortedIndices.length) {\n const startIdx = sortedIndices[i];\n const startLine = lines[startIdx];\n if (!startLine) {\n keptIndices.push(startIdx);\n i++;\n continue;\n }\n\n // ref 付きでなければそのまま保持\n if (!refPattern.test(startLine)) {\n keptIndices.push(startIdx);\n i++;\n continue;\n }\n\n const indent = startLine.length - startLine.trimStart().length;\n const role = getCachedRole(startIdx);\n\n if (!role) {\n keptIndices.push(startIdx);\n i++;\n continue;\n }\n\n // 同一 indent + role の連続する ref 付き行を数える\n let runLength = 1;\n let j = i + 1;\n while (j < sortedIndices.length) {\n const nextIdx = sortedIndices[j];\n const nextLine = lines[nextIdx];\n if (!nextLine || !refPattern.test(nextLine)) break;\n\n const nextIndent = nextLine.length - nextLine.trimStart().length;\n const nextRole = getCachedRole(nextIdx);\n\n if (nextIndent !== indent || nextRole !== role) break;\n\n runLength++;\n j++;\n }\n\n // 各要素の名前が全て異なる場合は折りたたまない(ナビバー等)\n const MAX_UNIQUE_NO_COLLAPSE = 15;\n\n if (runLength >= 3 && !NO_COLLAPSE_ROLES.has(role)) {\n // 名前一意性チェック: 名前付き要素が全て異なる名前を持つ場合は折りたたまない\n // 名前なし要素はスキップ(名前がないことと繰り返しは別の問題)\n let allUniqueNames = runLength <= MAX_UNIQUE_NO_COLLAPSE;\n if (allUniqueNames) {\n const names = new Set<string>();\n let hasDuplicate = false;\n for (let k = i; k < j; k++) {\n const name = extractName(lines[sortedIndices[k]]);\n if (!name) continue; // 名前なし要素はスキップ\n if (names.has(name)) { hasDuplicate = true; break; }\n names.add(name);\n }\n // 名前付き要素に重複がある場合は折りたたむ\n // 名前付き要素が1つもない場合も折りたたむ(一意性を判定できない)\n if (hasDuplicate || names.size === 0) {\n allUniqueNames = false;\n }\n }\n\n if (allUniqueNames) {\n // 全て保持(ナビバーのように各要素が意味的に固有)\n for (let k = i; k < j; k++) {\n keptIndices.push(sortedIndices[k]);\n }\n i = j;\n } else {\n // 最初の 2 個を保持、残りを省略(従来通り)\n for (let k = i; k < i + 2; k++) {\n keptIndices.push(sortedIndices[k]);\n }\n collapseMarkers.push({\n afterLineIndex: sortedIndices[i + 1],\n omittedCount: runLength - 2,\n indentLevel: Math.floor(indent / 2),\n });\n i = j;\n }\n } else {\n for (let k = i; k < j; k++) {\n keptIndices.push(sortedIndices[k]);\n }\n i = j;\n }\n }\n\n return { keptIndices, collapseMarkers };\n}\n\n/** 行から要素名を抽出(\"name\" 部分) */\nfunction extractName(line: string): string | null {\n const trimmed = line.trimStart().replace(/^-\\s+/, \"\");\n const nameMatch = trimmed.match(/\"([^\"]*)\"/);\n return nameMatch ? nameMatch[1] : null;\n}\n\n/** 行からロール名を抽出(Format A/B 両対応) */\nfunction extractRole(line: string): string | null {\n const trimmed = line.trimStart();\n // 先頭の \"- \" (Playwright リストbullet) を除去\n const cleaned = trimmed.replace(/^-\\s+/, \"\");\n\n // Format A: role \"name\" [ref=eN] ... or role [ref=eN]\n const roleBeforeRef = cleaned.match(/^(\\S+)(?:\\s+\"[^\"]*\")?\\s*\\[ref=e\\d+\\]/);\n if (roleBeforeRef) return roleBeforeRef[1];\n\n // Format B (legacy): [ref=eN] role \"name\" ...\n const refFirst = cleaned.match(/\\[ref=e\\d+\\]\\s+(\\S+)/);\n if (refFirst) return refFirst[1];\n\n // ref なし行: 最初の単語がロール\n const roleMatch = cleaned.match(/^(\\S+)/);\n return roleMatch ? roleMatch[1] : null;\n}\n"],"mappings":"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","names":[]}