@refrainai/cli 0.4.1 → 0.4.3

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 (83) hide show
  1. package/dist/{ai-model-FM6GWCID.js → ai-model-DP5PKGM6.js} +2 -2
  2. package/dist/{chunk-IGFCYKHC.js → chunk-5CKPPEYP.js} +262 -305
  3. package/dist/chunk-5CKPPEYP.js.map +1 -0
  4. package/dist/{chunk-7UCVPKD4.js → chunk-6FGCPMBU.js} +34 -74
  5. package/dist/chunk-6FGCPMBU.js.map +1 -0
  6. package/dist/{chunk-2BVDAJZT.js → chunk-A5X2VF5G.js} +9 -6
  7. package/dist/chunk-A5X2VF5G.js.map +1 -0
  8. package/dist/{chunk-H47NWH7N.js → chunk-AOCGSFRM.js} +611 -73
  9. package/dist/chunk-AOCGSFRM.js.map +1 -0
  10. package/dist/{chunk-CLYJHKPY.js → chunk-CMWLFQXD.js} +43 -42
  11. package/dist/chunk-CMWLFQXD.js.map +1 -0
  12. package/dist/chunk-GC7I5SGK.js +1146 -0
  13. package/dist/chunk-GC7I5SGK.js.map +1 -0
  14. package/dist/{chunk-WEYR56ZN.js → chunk-HHRHHFSK.js} +4 -4
  15. package/dist/chunk-IGJNT457.js +30 -0
  16. package/dist/chunk-IGJNT457.js.map +1 -0
  17. package/dist/{chunk-UGPXCQY3.js → chunk-KFNW4XR2.js} +13 -4
  18. package/dist/chunk-KFNW4XR2.js.map +1 -0
  19. package/dist/{chunk-RT664YIO.js → chunk-LZDZGI4M.js} +3 -1
  20. package/dist/chunk-LZDZGI4M.js.map +1 -0
  21. package/dist/{chunk-RYIJPYM3.js → chunk-MYITSQYV.js} +25 -8
  22. package/dist/chunk-MYITSQYV.js.map +1 -0
  23. package/dist/chunk-NRKZJVPE.js +74 -0
  24. package/dist/chunk-NRKZJVPE.js.map +1 -0
  25. package/dist/chunk-RBZK7T76.js +349 -0
  26. package/dist/chunk-RBZK7T76.js.map +1 -0
  27. package/dist/{chunk-HQDXLWAY.js → chunk-SDV3X5UN.js} +2 -2
  28. package/dist/{chunk-Z33FCOTZ.js → chunk-VVXNFUPL.js} +4 -2
  29. package/dist/chunk-VVXNFUPL.js.map +1 -0
  30. package/dist/chunk-YTVEYQGA.js +64 -0
  31. package/dist/chunk-YTVEYQGA.js.map +1 -0
  32. package/dist/{chunk-DJVUITRB.js → chunk-ZEBQWBEU.js} +898 -1135
  33. package/dist/chunk-ZEBQWBEU.js.map +1 -0
  34. package/dist/cli.js +5 -5
  35. package/dist/{compose-MTSIJY5D.js → compose-AVX5RU67.js} +9 -7
  36. package/dist/{compose-MTSIJY5D.js.map → compose-AVX5RU67.js.map} +1 -1
  37. package/dist/extraction-prompt-VDCKIFLB.js +17 -0
  38. package/dist/extraction-prompt-VDCKIFLB.js.map +1 -0
  39. package/dist/{fix-runbook-ZSBOTLC2.js → fix-runbook-6L5ZMA5G.js} +12 -10
  40. package/dist/{fix-runbook-ZSBOTLC2.js.map → fix-runbook-6L5ZMA5G.js.map} +1 -1
  41. package/dist/prompts-AGUYYIOM.js +13 -0
  42. package/dist/runbook-builder-2ZLE2AEO.js +11 -0
  43. package/dist/{runbook-data-helpers-KRR2SH76.js → runbook-data-helpers-5UAO65TZ.js} +3 -3
  44. package/dist/{runbook-executor-K7T6RJWJ.js → runbook-executor-OJXJTN6A.js} +41 -444
  45. package/dist/runbook-executor-OJXJTN6A.js.map +1 -0
  46. package/dist/{runbook-generator-MPXJBQ5N.js → runbook-generator-UIHWBEYC.js} +61 -136
  47. package/dist/runbook-generator-UIHWBEYC.js.map +1 -0
  48. package/dist/{runbook-schema-3T6TP3JJ.js → runbook-schema-X7DW725O.js} +2 -2
  49. package/dist/runbook-store-S24PXIHD.js +11 -0
  50. package/dist/{schema-5G6UQSPT.js → schema-XFSD5EWN.js} +2 -2
  51. package/dist/{server-AG3LXQBI.js → server-MULT5ZWG.js} +1176 -128
  52. package/dist/server-MULT5ZWG.js.map +1 -0
  53. package/dist/{tenant-ai-config-QPFEJUVJ.js → tenant-ai-config-4NHKRW7O.js} +4 -4
  54. package/dist/tenant-ai-config-4NHKRW7O.js.map +1 -0
  55. package/dist/yaml-patcher-GOCLYKZZ.js +18 -0
  56. package/dist/yaml-patcher-GOCLYKZZ.js.map +1 -0
  57. package/package.json +3 -2
  58. package/dist/chunk-2BVDAJZT.js.map +0 -1
  59. package/dist/chunk-7UCVPKD4.js.map +0 -1
  60. package/dist/chunk-CLYJHKPY.js.map +0 -1
  61. package/dist/chunk-DJVUITRB.js.map +0 -1
  62. package/dist/chunk-H47NWH7N.js.map +0 -1
  63. package/dist/chunk-IGFCYKHC.js.map +0 -1
  64. package/dist/chunk-RT664YIO.js.map +0 -1
  65. package/dist/chunk-RYIJPYM3.js.map +0 -1
  66. package/dist/chunk-UGPXCQY3.js.map +0 -1
  67. package/dist/chunk-VPK2MQAZ.js +0 -589
  68. package/dist/chunk-VPK2MQAZ.js.map +0 -1
  69. package/dist/chunk-Z33FCOTZ.js.map +0 -1
  70. package/dist/runbook-executor-K7T6RJWJ.js.map +0 -1
  71. package/dist/runbook-generator-MPXJBQ5N.js.map +0 -1
  72. package/dist/runbook-store-G5GUOWRR.js +0 -11
  73. package/dist/server-AG3LXQBI.js.map +0 -1
  74. package/dist/yaml-patcher-VGUS2JGH.js +0 -15
  75. /package/dist/{ai-model-FM6GWCID.js.map → ai-model-DP5PKGM6.js.map} +0 -0
  76. /package/dist/{chunk-WEYR56ZN.js.map → chunk-HHRHHFSK.js.map} +0 -0
  77. /package/dist/{chunk-HQDXLWAY.js.map → chunk-SDV3X5UN.js.map} +0 -0
  78. /package/dist/{runbook-data-helpers-KRR2SH76.js.map → prompts-AGUYYIOM.js.map} +0 -0
  79. /package/dist/{runbook-schema-3T6TP3JJ.js.map → runbook-builder-2ZLE2AEO.js.map} +0 -0
  80. /package/dist/{runbook-store-G5GUOWRR.js.map → runbook-data-helpers-5UAO65TZ.js.map} +0 -0
  81. /package/dist/{schema-5G6UQSPT.js.map → runbook-schema-X7DW725O.js.map} +0 -0
  82. /package/dist/{tenant-ai-config-QPFEJUVJ.js.map → runbook-store-S24PXIHD.js.map} +0 -0
  83. /package/dist/{yaml-patcher-VGUS2JGH.js.map → schema-XFSD5EWN.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/server/store/runbook-data-helpers.ts","../../../src/server/store/version-lifecycle.ts"],"sourcesContent":["/**\n * Runbook データ操作の純粋ヘルパー関数\n *\n * RunbookStore / VersionStore の private メソッドを抽出したもの。\n * DB トランザクション内で使用する。\n */\n\nimport { eq } from \"drizzle-orm\";\nimport {\n runbookSettings,\n runbookVariables,\n runbookSecrets,\n runbookSteps,\n jobs,\n} from \"../db/schema.js\";\nimport type { getDb } from \"../db/client.js\";\nimport type { ParsedStep } from \"../../runbook-executor/types.js\";\nimport { resolveDisplayStatus } from \"./version-lifecycle.js\";\n\ntype Db = ReturnType<typeof getDb>;\ntype Tx = Parameters<Parameters<Db[\"transaction\"]>[0]>[0];\n\n/**\n * バージョンデータ(settings, variables, secrets, steps)をコピーする。\n */\nexport async function copyVersionData(\n tx: Tx,\n sourceVersionId: string,\n targetVersionId: string,\n options?: { skipSteps?: boolean },\n) {\n // Settings\n const srcSettings = await tx.query.runbookSettings.findFirst({\n where: eq(runbookSettings.versionId, sourceVersionId),\n });\n if (srcSettings) {\n await tx.insert(runbookSettings).values({\n versionId: targetVersionId,\n defaultTimeout: srcSettings.defaultTimeout,\n pauseBetweenSteps: srcSettings.pauseBetweenSteps,\n stopOnError: srcSettings.stopOnError,\n stepDelay: srcSettings.stepDelay,\n enableSelectorCache: srcSettings.enableSelectorCache,\n enableAgentFallback: srcSettings.enableAgentFallback,\n enableVisionFallback: srcSettings.enableVisionFallback,\n modelId: srcSettings.modelId,\n modelProvider: srcSettings.modelProvider,\n });\n }\n\n // Variables\n const srcVars = await tx.query.runbookVariables.findMany({\n where: eq(runbookVariables.versionId, sourceVersionId),\n });\n if (srcVars.length > 0) {\n await tx.insert(runbookVariables).values(\n srcVars.map((v) => ({\n versionId: targetVersionId,\n name: v.name,\n source: v.source,\n description: v.description,\n required: v.required,\n sensitive: v.sensitive,\n value: v.value,\n })),\n );\n }\n\n // Secrets\n const srcSecrets = await tx.query.runbookSecrets.findMany({\n where: eq(runbookSecrets.versionId, sourceVersionId),\n });\n if (srcSecrets.length > 0) {\n await tx.insert(runbookSecrets).values(\n srcSecrets.map((s) => ({\n versionId: targetVersionId,\n key: s.key,\n encryptedValue: s.encryptedValue,\n })),\n );\n }\n\n // Steps(skipSteps 時はスキップ — 新バージョンでは AI が再生成する)\n if (options?.skipSteps) return;\n\n // Steps(再帰構造をコピー)\n const srcSteps = await tx.query.runbookSteps.findMany({\n where: eq(runbookSteps.versionId, sourceVersionId),\n orderBy: [runbookSteps.ordinal],\n });\n if (srcSteps.length > 0) {\n // ID マッピングを構築\n const idMap = new Map<string, string>();\n for (const s of srcSteps) {\n const [newStep] = await tx.insert(runbookSteps).values({\n versionId: targetVersionId,\n parentStepId: s.parentStepId ? idMap.get(s.parentStepId) ?? null : null,\n ordinal: s.ordinal,\n description: s.description,\n actionType: s.actionType,\n url: s.url,\n riskLevel: s.riskLevel,\n requiresConfirmation: s.requiresConfirmation,\n value: s.value,\n optionText: s.optionText,\n script: s.script,\n extractPrompt: s.extractPrompt,\n keys: s.keys,\n downloadPath: s.downloadPath,\n exportCollection: s.exportCollection,\n exportFormat: s.exportFormat,\n exportPath: s.exportPath,\n selector: s.selector,\n condition: s.condition,\n captures: s.captures,\n memoryOperations: s.memoryOperations,\n loopCondition: s.loopCondition,\n loopForEach: s.loopForEach,\n loopItemVariable: s.loopItemVariable,\n loopIndexVariable: s.loopIndexVariable,\n loopMaxIterations: s.loopMaxIterations,\n loopCounterVariable: s.loopCounterVariable,\n branchValue: s.branchValue,\n branchCaseMatch: s.branchCaseMatch,\n branchIsDefault: s.branchIsDefault,\n }).returning();\n idMap.set(s.id, newStep.id);\n }\n }\n}\n\n/**\n * ステップツリーを再帰的に DB に挿入する。\n */\nexport async function insertSteps(\n tx: Tx,\n versionId: string,\n steps: ParsedStep[],\n parentStepId: string | null,\n branchCaseMatch?: string,\n branchIsDefault?: boolean,\n) {\n for (const step of steps) {\n const [inserted] = await tx\n .insert(runbookSteps)\n .values({\n versionId,\n parentStepId,\n ordinal: step.ordinal,\n description: step.description,\n actionType: step.action.type,\n url: step.url || null,\n riskLevel: step.riskLevel,\n requiresConfirmation: step.requiresConfirmation,\n value: step.action.value ?? null,\n optionText: step.action.optionText ?? null,\n script: step.action.script ?? null,\n extractPrompt: step.action.extractPrompt ?? null,\n keys: step.action.keys ?? null,\n downloadPath: step.action.downloadPath ?? null,\n exportCollection: step.action.exportCollection ?? null,\n exportFormat: step.action.exportFormat ?? null,\n exportPath: step.action.exportPath ?? null,\n selector: step.action.selector ?? null,\n condition: step.condition ?? null,\n captures: step.captures ?? null,\n memoryOperations: step.memoryOperations ?? null,\n loopCondition: step.loop?.condition ?? null,\n loopForEach: step.loop?.forEach ?? null,\n loopItemVariable: step.loop?.itemVariable ?? null,\n loopIndexVariable: step.loop?.indexVariable ?? null,\n loopMaxIterations: step.loop?.maxIterations ?? null,\n loopCounterVariable: step.loop?.counterVariable ?? null,\n branchValue: step.branches?.value ?? null,\n branchCaseMatch: branchCaseMatch ?? null,\n branchIsDefault: branchIsDefault ?? false,\n })\n .returning();\n\n // サブステップ (loop)\n if (step.steps && step.steps.length > 0) {\n await insertSteps(tx, versionId, step.steps, inserted.id);\n }\n\n // ブランチ (cases + default)\n if (step.branches) {\n for (const branchCase of step.branches.cases) {\n await insertSteps(\n tx,\n versionId,\n branchCase.steps,\n inserted.id,\n branchCase.match,\n );\n }\n if (step.branches.default) {\n await insertSteps(\n tx,\n versionId,\n step.branches.default.steps,\n inserted.id,\n undefined,\n true,\n );\n }\n }\n }\n}\n\n/**\n * バージョン詳細(settings, variables, secrets, steps)を読み込む。\n */\nexport async function loadVersionDetail(db: Db, versionId: string) {\n const [settingsRow, variables, secretRows, steps] = await Promise.all([\n db.query.runbookSettings.findFirst({\n where: eq(runbookSettings.versionId, versionId),\n }),\n db.query.runbookVariables.findMany({\n where: eq(runbookVariables.versionId, versionId),\n }),\n db.query.runbookSecrets.findMany({\n where: eq(runbookSecrets.versionId, versionId),\n }),\n db.query.runbookSteps.findMany({\n where: eq(runbookSteps.versionId, versionId),\n orderBy: [runbookSteps.ordinal],\n }),\n ]);\n\n return {\n settings: settingsRow ?? null,\n variables,\n secrets: secretRows,\n steps,\n };\n}\n\n/**\n * DB のバージョン + 子テーブルからフラット構造を構築する(旧 API 互換)。\n */\nexport async function buildFlatRunbook(\n db: Db,\n rb: { id: string; title: string; disabled: boolean; activeVersionId: string | null; createdAt: Date; updatedAt: Date; tenantId: string; createdBy: string | null },\n ver: { id: string; status: string; goal: string; startUrl: string | null; context: string | null; generatedAt: string | null; verificationJobId: string | null; versionNumber: number },\n) {\n const detail = await loadVersionDetail(db, ver.id);\n\n // 検証ジョブのステータスを取得\n let verificationJobStatus: string | null = null;\n if (ver.verificationJobId) {\n const [job] = await db.select({ status: jobs.status }).from(jobs).where(eq(jobs.id, ver.verificationJobId));\n verificationJobStatus = job?.status ?? null;\n }\n\n // ステータスの計算: disabled フラグが true なら \"disabled\"、それ以外はバージョンステータス\n const status = rb.disabled\n ? \"disabled\" as const\n : ver.status === \"active\"\n ? \"active\" as const\n : ver.status === \"pending_verification\"\n ? \"pending_verification\" as const\n : ver.status === \"pending_approval\"\n ? \"pending_verification\" as const // 旧 API 互換\n : \"draft\" as const;\n\n return {\n ...rb,\n // フラット構造互換フィールド(バージョンからコピー)\n goal: ver.goal,\n startUrl: ver.startUrl,\n context: ver.context,\n generatedAt: ver.generatedAt,\n status,\n verificationJobId: ver.verificationJobId,\n verificationJobStatus,\n displayStatus: resolveDisplayStatus(\n rb.disabled ? \"disabled\" : ver.status,\n ver.verificationJobId,\n verificationJobStatus,\n ),\n // 子データ\n ...detail,\n // バージョン情報\n activeVersionId: rb.activeVersionId,\n currentVersionId: ver.id,\n versionNumber: ver.versionNumber,\n versionStatus: ver.status,\n };\n}\n","/**\n * バージョン状態遷移マシン\n *\n * 全てのバージョンステータス遷移ルールを一元管理する。\n * store/handler はここを参照して遷移の妥当性を検証する。\n */\n\nexport type VersionStatus = \"draft\" | \"pending_verification\" | \"pending_approval\" | \"active\" | \"archived\";\n\n/** 許可された状態遷移マップ */\nconst TRANSITIONS: Record<VersionStatus, VersionStatus[]> = {\n draft: [\"pending_verification\"],\n pending_verification: [\"pending_approval\", \"active\"],\n pending_approval: [\"pending_verification\", \"active\"],\n active: [\"archived\"],\n archived: [\"active\"],\n};\n\n/** 遷移が許可されているか */\nexport function canTransition(from: VersionStatus, to: VersionStatus): boolean {\n return TRANSITIONS[from]?.includes(to) ?? false;\n}\n\n/** 遷移を検証し、不正な場合は例外を投げる */\nexport function assertTransition(from: VersionStatus, to: VersionStatus): void {\n if (!canTransition(from, to)) {\n throw new Error(`Invalid transition: ${from} → ${to}`);\n }\n}\n\n/** 編集可能なステータスか(draft | pending_verification) */\nexport function isEditable(status: VersionStatus): boolean {\n return status === \"draft\" || status === \"pending_verification\";\n}\n\n/** 削除可能なステータスか(draft | pending_verification) */\nexport function isDeletable(status: VersionStatus): boolean {\n return status === \"draft\" || status === \"pending_verification\";\n}\n\n/** 検証可能なステータスか(pending_verification) */\nexport function isVerifiable(status: VersionStatus): boolean {\n return status === \"pending_verification\";\n}\n\n// ── 表示ステータス ──\n\nexport type DisplayStatus =\n | \"draft\"\n | \"pendingVerification\"\n | \"verifying\"\n | \"readyToActivate\"\n | \"pendingApproval\"\n | \"active\"\n | \"archived\"\n | \"disabled\";\n\n/**\n * DB ステータス + 検証ジョブ状態から表示用ステータスを解決する。\n * サーバーで計算して返し、フロントエンドはそのまま使う。\n */\nexport function resolveDisplayStatus(\n status: string,\n verificationJobId: string | null,\n verificationJobStatus: string | null,\n): DisplayStatus {\n if (status === \"disabled\") return \"disabled\";\n if (status === \"pending_verification\") {\n if (verificationJobId && verificationJobStatus === \"completed\") return \"readyToActivate\";\n if (\n verificationJobId &&\n verificationJobStatus &&\n ![\"completed\", \"failed\", \"cancelled\"].includes(verificationJobStatus)\n ) return \"verifying\";\n return \"pendingVerification\";\n }\n if (status === \"pending_approval\") return \"pendingApproval\";\n if (status === \"active\") return \"active\";\n if (status === \"archived\") return \"archived\";\n return \"draft\";\n}\n\n/**\n * 公開可能なステータスか\n * requireApproval=true の場合: pending_approval のみ\n * requireApproval=false の場合: pending_verification | pending_approval\n */\nexport function isPublishable(status: VersionStatus, requireApproval: boolean): boolean {\n if (requireApproval) {\n return status === \"pending_approval\";\n }\n return status === \"pending_verification\" || status === \"pending_approval\";\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/browser/snapshot-parser.ts
4
+ function parseSnapshotLine(line) {
5
+ const refMatch = line.match(/\[ref=(e\d+)\]/);
6
+ if (!refMatch) return null;
7
+ const ref = refMatch[1];
8
+ const refIndex = line.indexOf(refMatch[0]);
9
+ const beforeRef = line.slice(0, refIndex).trim();
10
+ const afterRef = line.slice(refIndex + refMatch[0].length).trim();
11
+ const cleanBefore = beforeRef.replace(/^-\s+/, "");
12
+ let role;
13
+ let name;
14
+ const roleNameMatch = cleanBefore.match(/^(\S+)\s+"([^"]*)"$/);
15
+ const roleOnlyMatch = cleanBefore.match(/^(\S+)$/);
16
+ if (roleNameMatch) {
17
+ role = roleNameMatch[1];
18
+ name = roleNameMatch[2];
19
+ } else if (roleOnlyMatch && !roleOnlyMatch[1].startsWith("[")) {
20
+ role = roleOnlyMatch[1];
21
+ name = "";
22
+ } else {
23
+ return null;
24
+ }
25
+ const attrSource = afterRef.replace(/:$/, "").trim();
26
+ const attributes = {};
27
+ const attrRegex = /\[(\w+)(?:=([^\]]*))?\]/g;
28
+ let attrMatch;
29
+ while ((attrMatch = attrRegex.exec(attrSource)) !== null) {
30
+ const key = attrMatch[1];
31
+ if (key === "ref") continue;
32
+ const value = attrMatch[2] ?? "true";
33
+ attributes[key] = value;
34
+ }
35
+ return { ref, role, name, attributes };
36
+ }
37
+ function findElementInSnapshot(snapshot, ref) {
38
+ const lines = snapshot.split("\n");
39
+ for (const line of lines) {
40
+ if (!line.includes(`[ref=${ref}]`)) continue;
41
+ const parsed = parseSnapshotLine(line);
42
+ if (parsed && parsed.ref === ref) return parsed;
43
+ }
44
+ return null;
45
+ }
46
+ function parseAllElements(snapshot) {
47
+ const lines = snapshot.split("\n");
48
+ const elements = [];
49
+ for (const line of lines) {
50
+ const parsed = parseSnapshotLine(line);
51
+ if (parsed) elements.push(parsed);
52
+ }
53
+ return elements;
54
+ }
55
+ function countElements(snapshot) {
56
+ return parseAllElements(snapshot).length;
57
+ }
58
+
59
+ export {
60
+ findElementInSnapshot,
61
+ parseAllElements,
62
+ countElements
63
+ };
64
+ //# sourceMappingURL=chunk-YTVEYQGA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/browser/snapshot-parser.ts"],"sourcesContent":["/**\n * snapshot-parser — アクセシビリティスナップショット行パース\n *\n * Playwright のアクセシビリティスナップショット出力形式:\n * role \"name\" [ref=eN] [attrs]\n *\n * から構造化データを抽出する純粋関数群\n */\n\nexport interface ParsedSnapshotElement {\n /** 参照ID(例: \"e3\") */\n ref: string;\n /** ロール(例: \"textbox\", \"button\", \"link\") */\n role: string;\n /** 名前(例: \"Email\", \"ログイン\") */\n name: string;\n /** 追加属性 */\n attributes: Record<string, string>;\n}\n\n/**\n * スナップショットの1行をパースして構造化データに変換\n *\n * 入力例:\n * textbox \"Email\" [ref=e3] [required] [focused]\n * - button \"ログイン\" [ref=e5]\n * heading \"Title\" [ref=e1] [level=2]\n * textbox \"サブドメイン\" [ref=e3]:\n * img [ref=e10]\n *\n * @returns パースされた要素、またはマッチしない場合 null\n */\nexport function parseSnapshotLine(\n line: string,\n): ParsedSnapshotElement | null {\n // [ref=eN] を抽出\n const refMatch = line.match(/\\[ref=(e\\d+)\\]/);\n if (!refMatch) return null;\n\n const ref = refMatch[1];\n const refIndex = line.indexOf(refMatch[0]);\n\n // ref より前のテキスト(role \"name\" が先頭にある)\n const beforeRef = line.slice(0, refIndex).trim();\n // ref より後のテキスト(属性のみ)\n const afterRef = line.slice(refIndex + refMatch[0].length).trim();\n\n // 先頭の \"- \" (Playwright リストbullet) を除去\n const cleanBefore = beforeRef.replace(/^-\\s+/, \"\");\n\n let role: string;\n let name: string;\n\n // role \"name\" パターン\n const roleNameMatch = cleanBefore.match(/^(\\S+)\\s+\"([^\"]*)\"$/);\n const roleOnlyMatch = cleanBefore.match(/^(\\S+)$/);\n\n if (roleNameMatch) {\n role = roleNameMatch[1];\n name = roleNameMatch[2];\n } else if (roleOnlyMatch && !roleOnlyMatch[1].startsWith(\"[\")) {\n role = roleOnlyMatch[1];\n name = \"\";\n } else {\n return null;\n }\n\n // 末尾 \":\" (子要素インジケータ) を除去して属性を抽出\n const attrSource = afterRef.replace(/:$/, \"\").trim();\n\n // 属性を抽出([key=value] または [key] 形式、[ref=...] はスキップ)\n const attributes: Record<string, string> = {};\n const attrRegex = /\\[(\\w+)(?:=([^\\]]*))?\\]/g;\n let attrMatch: RegExpExecArray | null;\n while ((attrMatch = attrRegex.exec(attrSource)) !== null) {\n const key = attrMatch[1];\n if (key === \"ref\") continue;\n const value = attrMatch[2] ?? \"true\";\n attributes[key] = value;\n }\n\n return { ref, role, name, attributes };\n}\n\n/**\n * スナップショット全体から指定refの要素を検索\n */\nexport function findElementInSnapshot(\n snapshot: string,\n ref: string,\n): ParsedSnapshotElement | null {\n const lines = snapshot.split(\"\\n\");\n for (const line of lines) {\n if (!line.includes(`[ref=${ref}]`)) continue;\n const parsed = parseSnapshotLine(line);\n if (parsed && parsed.ref === ref) return parsed;\n }\n return null;\n}\n\n/**\n * スナップショットからインタラクティブ要素一覧を抽出\n */\nexport function parseAllElements(\n snapshot: string,\n): ParsedSnapshotElement[] {\n const lines = snapshot.split(\"\\n\");\n const elements: ParsedSnapshotElement[] = [];\n for (const line of lines) {\n const parsed = parseSnapshotLine(line);\n if (parsed) elements.push(parsed);\n }\n return elements;\n}\n\n/**\n * スナップショット内の [ref=eN] 要素の総数を返す。\n */\nexport function countElements(snapshot: string): number {\n return parseAllElements(snapshot).length;\n}\n"],"mappings":";;;AAgCO,SAAS,kBACd,MAC8B;AAE9B,QAAM,WAAW,KAAK,MAAM,gBAAgB;AAC5C,MAAI,CAAC,SAAU,QAAO;AAEtB,QAAM,MAAM,SAAS,CAAC;AACtB,QAAM,WAAW,KAAK,QAAQ,SAAS,CAAC,CAAC;AAGzC,QAAM,YAAY,KAAK,MAAM,GAAG,QAAQ,EAAE,KAAK;AAE/C,QAAM,WAAW,KAAK,MAAM,WAAW,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK;AAGhE,QAAM,cAAc,UAAU,QAAQ,SAAS,EAAE;AAEjD,MAAI;AACJ,MAAI;AAGJ,QAAM,gBAAgB,YAAY,MAAM,qBAAqB;AAC7D,QAAM,gBAAgB,YAAY,MAAM,SAAS;AAEjD,MAAI,eAAe;AACjB,WAAO,cAAc,CAAC;AACtB,WAAO,cAAc,CAAC;AAAA,EACxB,WAAW,iBAAiB,CAAC,cAAc,CAAC,EAAE,WAAW,GAAG,GAAG;AAC7D,WAAO,cAAc,CAAC;AACtB,WAAO;AAAA,EACT,OAAO;AACL,WAAO;AAAA,EACT;AAGA,QAAM,aAAa,SAAS,QAAQ,MAAM,EAAE,EAAE,KAAK;AAGnD,QAAM,aAAqC,CAAC;AAC5C,QAAM,YAAY;AAClB,MAAI;AACJ,UAAQ,YAAY,UAAU,KAAK,UAAU,OAAO,MAAM;AACxD,UAAM,MAAM,UAAU,CAAC;AACvB,QAAI,QAAQ,MAAO;AACnB,UAAM,QAAQ,UAAU,CAAC,KAAK;AAC9B,eAAW,GAAG,IAAI;AAAA,EACpB;AAEA,SAAO,EAAE,KAAK,MAAM,MAAM,WAAW;AACvC;AAKO,SAAS,sBACd,UACA,KAC8B;AAC9B,QAAM,QAAQ,SAAS,MAAM,IAAI;AACjC,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,KAAK,SAAS,QAAQ,GAAG,GAAG,EAAG;AACpC,UAAM,SAAS,kBAAkB,IAAI;AACrC,QAAI,UAAU,OAAO,QAAQ,IAAK,QAAO;AAAA,EAC3C;AACA,SAAO;AACT;AAKO,SAAS,iBACd,UACyB;AACzB,QAAM,QAAQ,SAAS,MAAM,IAAI;AACjC,QAAM,WAAoC,CAAC;AAC3C,aAAW,QAAQ,OAAO;AACxB,UAAM,SAAS,kBAAkB,IAAI;AACrC,QAAI,OAAQ,UAAS,KAAK,MAAM;AAAA,EAClC;AACA,SAAO;AACT;AAKO,SAAS,cAAc,UAA0B;AACtD,SAAO,iBAAiB,QAAQ,EAAE;AACpC;","names":[]}