@flanksource/clicky-ui 0.3.11 → 0.3.13

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 (54) hide show
  1. package/dist/data/ai/SessionViewer.input.cjs +2 -1
  2. package/dist/data/ai/SessionViewer.input.cjs.map +1 -1
  3. package/dist/data/ai/SessionViewer.input.d.ts.map +1 -1
  4. package/dist/data/ai/SessionViewer.input.js +2 -1
  5. package/dist/data/ai/SessionViewer.input.js.map +1 -1
  6. package/dist/data/diagnostics/error-diagnostics.cjs +38 -6
  7. package/dist/data/diagnostics/error-diagnostics.cjs.map +1 -1
  8. package/dist/data/diagnostics/error-diagnostics.js +38 -6
  9. package/dist/data/diagnostics/error-diagnostics.js.map +1 -1
  10. package/dist/data/diagnostics/jvm-stacktrace.cjs +35 -3
  11. package/dist/data/diagnostics/jvm-stacktrace.cjs.map +1 -1
  12. package/dist/data/diagnostics/jvm-stacktrace.d.ts.map +1 -1
  13. package/dist/data/diagnostics/jvm-stacktrace.js +35 -3
  14. package/dist/data/diagnostics/jvm-stacktrace.js.map +1 -1
  15. package/dist/data/diagnostics/stacktrace-parse.cjs +19 -5
  16. package/dist/data/diagnostics/stacktrace-parse.cjs.map +1 -1
  17. package/dist/data/diagnostics/stacktrace-parse.d.ts.map +1 -1
  18. package/dist/data/diagnostics/stacktrace-parse.js +19 -5
  19. package/dist/data/diagnostics/stacktrace-parse.js.map +1 -1
  20. package/dist/data/diagnostics/stacktrace.cjs +15 -2
  21. package/dist/data/diagnostics/stacktrace.cjs.map +1 -1
  22. package/dist/data/diagnostics/stacktrace.js +15 -2
  23. package/dist/data/diagnostics/stacktrace.js.map +1 -1
  24. package/dist/data/test-runner/routePath.cjs +3 -1
  25. package/dist/data/test-runner/routePath.cjs.map +1 -1
  26. package/dist/data/test-runner/routePath.d.ts.map +1 -1
  27. package/dist/data/test-runner/routePath.js +3 -1
  28. package/dist/data/test-runner/routePath.js.map +1 -1
  29. package/dist/data/version-info.cjs +3 -3
  30. package/dist/data/version-info.cjs.map +1 -1
  31. package/dist/data/version-info.js +3 -3
  32. package/dist/data/version-info.js.map +1 -1
  33. package/dist/lib/string.cjs +15 -0
  34. package/dist/lib/string.cjs.map +1 -0
  35. package/dist/lib/string.d.ts +3 -0
  36. package/dist/lib/string.d.ts.map +1 -0
  37. package/dist/lib/string.js +15 -0
  38. package/dist/lib/string.js.map +1 -0
  39. package/dist/rpc/OperationActionDialog.cjs +4 -10
  40. package/dist/rpc/OperationActionDialog.cjs.map +1 -1
  41. package/dist/rpc/OperationActionDialog.d.ts.map +1 -1
  42. package/dist/rpc/OperationActionDialog.js +2 -8
  43. package/dist/rpc/OperationActionDialog.js.map +1 -1
  44. package/dist/rpc/OperationCommandPage.cjs +3 -2
  45. package/dist/rpc/OperationCommandPage.cjs.map +1 -1
  46. package/dist/rpc/OperationCommandPage.d.ts.map +1 -1
  47. package/dist/rpc/OperationCommandPage.js +3 -2
  48. package/dist/rpc/OperationCommandPage.js.map +1 -1
  49. package/dist/rpc/apiClient.cjs +2 -1
  50. package/dist/rpc/apiClient.cjs.map +1 -1
  51. package/dist/rpc/apiClient.d.ts.map +1 -1
  52. package/dist/rpc/apiClient.js +2 -1
  53. package/dist/rpc/apiClient.js.map +1 -1
  54. package/package.json +1 -1
@@ -2,10 +2,11 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const codeDiff = require("../code-diff.cjs");
4
4
  const codeHighlight = require("../code-highlight.cjs");
5
+ const string = require("../../lib/string.cjs");
5
6
  const SessionViewer_model = require("./SessionViewer.model.cjs");
6
7
  function relativizePath(path, cwd) {
7
8
  if (!cwd) return path;
8
- const base = cwd.replace(/\/+$/, "");
9
+ const base = string.stripTrailingSlashes(cwd);
9
10
  return path.startsWith(`${base}/`) ? path.slice(base.length + 1) : path;
10
11
  }
11
12
  function shellCommand(tool, input) {
@@ -1 +1 @@
1
- {"version":3,"file":"SessionViewer.input.cjs","sources":["../../../src/data/ai/SessionViewer.input.ts"],"sourcesContent":["// Presentation helpers for a tool call's input: the one-line summary, the\n// JetBrains-style inline params, the inline shell command, and the line diff\n// for file-writing tools. Pure functions — the viewer renders their output.\n\nimport { computeLineDiff } from \"../code-diff\";\nimport { languageFromPath } from \"../code-highlight\";\nimport { splitMcpTool, truncate } from \"./SessionViewer.model\";\n\n/** Strip the event's working directory from an absolute file path. */\nexport function relativizePath(path: string, cwd?: string): string {\n if (!cwd) return path;\n const base = cwd.replace(/\\/+$/, \"\");\n return path.startsWith(`${base}/`) ? path.slice(base.length + 1) : path;\n}\n\n/** The raw shell command of a shell-execution tool call, if present. Shell rows\n * render this inline as a bash code block instead of the generic label +\n * tool-input JSON. */\nexport function shellCommand(\n tool: string,\n input?: Record<string, unknown>,\n): string | undefined {\n if (tool !== \"Bash\") return undefined;\n const command = input?.[\"command\"];\n return typeof command === \"string\" && command ? command : undefined;\n}\n\nexport interface ToolParam {\n name: string;\n value: string;\n}\n\nexport interface SessionQuestionOption {\n value: string;\n label: string;\n description?: string;\n}\n\nexport interface SessionQuestion {\n id: string;\n text: string;\n context?: string;\n multiSelect?: boolean;\n options: SessionQuestionOption[];\n}\n\n// Keys already rendered elsewhere in the row — the file-path heading, the\n// inline shell command, or the diff — so they don't repeat as inline params.\nconst CONSUMED_INPUT_KEYS: Record<string, readonly string[]> = {\n Bash: [\"command\"],\n Read: [\"file_path\", \"notebook_path\", \"path\"],\n Write: [\"file_path\", \"notebook_path\", \"path\", \"content\"],\n Edit: [\"file_path\", \"notebook_path\", \"path\", \"old_string\", \"new_string\"],\n MultiEdit: [\"file_path\", \"notebook_path\", \"path\", \"edits\"],\n NotebookEdit: [\"file_path\", \"notebook_path\", \"path\"],\n AskUserQuestion: [\"questions\", \"question\", \"prompt\", \"text\", \"header\", \"context\", \"description\", \"options\"],\n};\n\n/** Flatten a tool's input into JetBrains-style `name: value` inline params:\n * single-line values, cwd-relativized and truncated so the row never wraps. */\nexport function toolInputParams(\n tool: string,\n input?: Record<string, unknown>,\n cwd?: string,\n): ToolParam[] {\n const consumed = CONSUMED_INPUT_KEYS[tool] ?? [];\n return Object.entries(input ?? {})\n .filter(\n ([name, value]) =>\n !consumed.includes(name) &&\n value !== undefined &&\n value !== null &&\n value !== \"\",\n )\n .map(([name, value]) => ({ name, value: paramValue(value, cwd) }));\n}\n\nfunction paramValue(value: unknown, cwd?: string): string {\n const text =\n typeof value === \"string\"\n ? relativizePath(value, cwd)\n : JSON.stringify(value);\n return truncate(text.replace(/\\s+/g, \" \").trim(), 60);\n}\n\n/** One before/after edit, rendered as a language-aware diff. */\nexport interface DiffSegment {\n original: string;\n modified: string;\n}\n\nexport interface ToolDiff {\n added: number;\n removed: number;\n /** Edits as original→modified pairs (Write has one; MultiEdit has several). */\n segments: DiffSegment[];\n /** Highlighter hint from the file extension, when known. */\n language?: string;\n}\n\n// Added/removed line counts from a real LCS diff — context lines don't count,\n// so a no-op edit reports 0/0 (and yields no diff).\nfunction diffCounts(segments: DiffSegment[]): {\n added: number;\n removed: number;\n} {\n let added = 0;\n let removed = 0;\n for (const { original, modified } of segments) {\n for (const hunk of computeLineDiff(original, modified)) {\n for (const line of hunk.lines) {\n if (line.type === \"add\") added += 1;\n else if (line.type === \"remove\") removed += 1;\n }\n }\n }\n return { added, removed };\n}\n\n/** The content change of a file-writing tool call as before/after segments —\n * Write is one all-additions segment; Edit/MultiEdit pair old and new text. */\nexport function toolDiff(\n tool: string,\n input?: Record<string, unknown>,\n): ToolDiff | undefined {\n if (!input) return undefined;\n const str = (key: string): string =>\n typeof input[key] === \"string\" ? (input[key] as string) : \"\";\n\n const segments = toolDiffSegments(tool, input, str);\n if (!segments || segments.length === 0) return undefined;\n const counts = diffCounts(segments);\n if (counts.added === 0 && counts.removed === 0) return undefined;\n\n const language = languageFromPath(\n str(\"file_path\") || str(\"notebook_path\") || str(\"path\"),\n );\n return { ...counts, segments, ...(language ? { language } : {}) };\n}\n\nfunction toolDiffSegments(\n tool: string,\n input: Record<string, unknown>,\n str: (key: string) => string,\n): DiffSegment[] | undefined {\n if (tool === \"Write\") {\n const content = str(\"content\");\n return content ? [{ original: \"\", modified: content }] : undefined;\n }\n if (tool === \"Edit\" || tool === \"NotebookEdit\") {\n const original = str(\"old_string\");\n const modified = str(\"new_string\") || str(\"new_source\");\n return original || modified ? [{ original, modified }] : undefined;\n }\n if (tool === \"MultiEdit\") {\n const edits = input[\"edits\"];\n if (!Array.isArray(edits)) return undefined;\n return edits\n .filter(\n (edit): edit is Record<string, unknown> =>\n typeof edit === \"object\" && edit !== null,\n )\n .map((edit) => ({\n original:\n typeof edit[\"old_string\"] === \"string\"\n ? (edit[\"old_string\"] as string)\n : \"\",\n modified:\n typeof edit[\"new_string\"] === \"string\"\n ? (edit[\"new_string\"] as string)\n : \"\",\n }))\n .filter((segment) => segment.original !== \"\" || segment.modified !== \"\");\n }\n return undefined;\n}\n\n// summarizeToolInput condenses a tool's input into a one-line preview, ported\n// from captain's history.FormatToolUseSummary so the viewer reads like the CLI.\nexport function summarizeToolInput(\n tool: string,\n input?: Record<string, unknown>,\n cwd?: string,\n): string {\n if (!input) return \"\";\n const str = (key: string): string =>\n typeof input[key] === \"string\" ? (input[key] as string) : \"\";\n const first = (...keys: string[]): string => {\n for (const key of keys) {\n const value = str(key);\n if (value) return value;\n }\n return \"\";\n };\n\n const mcp = splitMcpTool(tool);\n if (mcp) {\n const arg = first(\"url\", \"sql\", \"query\", \"element\", \"method\");\n return arg ? truncate(arg, 80) : \"\";\n }\n\n switch (tool) {\n case \"Bash\":\n case \"browser_type\":\n return str(\"command\") || str(\"text\");\n case \"Read\":\n case \"Write\":\n case \"Edit\":\n case \"MultiEdit\":\n case \"NotebookEdit\":\n return relativizePath(first(\"file_path\", \"notebook_path\", \"path\"), cwd);\n case \"Grep\":\n return [str(\"pattern\"), str(\"path\")].filter(Boolean).join(\" \");\n case \"Glob\":\n return str(\"pattern\");\n case \"Task\":\n case \"Agent\":\n return first(\"description\", \"prompt\");\n case \"Skill\":\n return first(\"skill\", \"command\", \"name\");\n case \"TaskCreate\":\n return first(\"subject\", \"description\");\n case \"TaskUpdate\": {\n const id = first(\"taskId\", \"task_id\", \"id\");\n const status = str(\"status\");\n return status ? `${id} ${status}`.trim() : id;\n }\n case \"TaskGet\":\n case \"TaskOutput\":\n case \"TaskStop\":\n return first(\"task_id\", \"taskId\", \"id\");\n case \"ToolSearch\":\n case \"WebSearch\":\n return str(\"query\");\n case \"WebFetch\":\n case \"browser_navigate\":\n return str(\"url\");\n case \"AskUserQuestion\": {\n const questions = questionsFromToolInput(input);\n const rawQuestions = input[\"questions\"];\n if (questions.length > 1) return `${questions.length} questions`;\n if (questions[0]?.text) return truncate(questions[0].text, 80);\n if (Array.isArray(rawQuestions) && rawQuestions.length > 0) return `${rawQuestions.length} questions`;\n return \"\";\n }\n case \"ExitPlanMode\":\n return str(\"planFilePath\");\n default:\n return \"\";\n }\n}\n\nexport function questionsFromToolInput(input?: Record<string, unknown>): SessionQuestion[] {\n if (!input) return [];\n const rawQuestions = input.questions;\n if (Array.isArray(rawQuestions)) {\n return rawQuestions\n .map((question, index) => questionFromValue(question, index))\n .filter((question): question is SessionQuestion => question !== null);\n }\n\n const text = stringField(input, \"question\") || stringField(input, \"prompt\") || stringField(input, \"text\");\n if (!text) return [];\n return [{\n id: stringField(input, \"id\") || \"1\",\n text,\n ...optionalContext(input),\n multiSelect: booleanField(input, \"multiSelect\") || booleanField(input, \"multi_select\"),\n options: optionList(input.options),\n }];\n}\n\nfunction questionFromValue(value: unknown, index: number): SessionQuestion | null {\n if (typeof value === \"string\") {\n const text = value.trim();\n return text ? { id: String(index + 1), text, options: [] } : null;\n }\n if (!isRecord(value)) return null;\n const text =\n stringField(value, \"question\") ||\n stringField(value, \"text\") ||\n stringField(value, \"prompt\") ||\n stringField(value, \"label\");\n if (!text) return null;\n return {\n id: stringField(value, \"id\") || String(index + 1),\n text,\n ...optionalContext(value),\n multiSelect: booleanField(value, \"multiSelect\") || booleanField(value, \"multi_select\"),\n options: optionList(value.options),\n };\n}\n\nfunction optionList(value: unknown): SessionQuestionOption[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap((option, index) => {\n if (typeof option === \"string\") {\n const label = option.trim();\n return label ? [{ value: label, label }] : [];\n }\n if (!isRecord(option)) return [];\n const label =\n stringField(option, \"label\") ||\n stringField(option, \"value\") ||\n stringField(option, \"id\") ||\n stringField(option, \"description\");\n if (!label) return [];\n const value = stringField(option, \"value\") || stringField(option, \"id\") || label;\n const description = stringField(option, \"description\");\n return [{\n value: value || String(index + 1),\n label,\n ...(description && description !== label ? { description } : {}),\n }];\n });\n}\n\nfunction optionalContext(input: Record<string, unknown>): Pick<SessionQuestion, \"context\"> {\n const context = stringField(input, \"header\") || stringField(input, \"context\") || stringField(input, \"description\");\n return context ? { context } : {};\n}\n\nfunction stringField(input: Record<string, unknown>, key: string): string {\n const value = input[key];\n return typeof value === \"string\" ? value.trim() : \"\";\n}\n\nfunction booleanField(input: Record<string, unknown>, key: string): boolean {\n return input[key] === true;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n"],"names":["truncate","computeLineDiff","languageFromPath","splitMcpTool","text","label","value"],"mappings":"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"}
1
+ {"version":3,"file":"SessionViewer.input.cjs","sources":["../../../src/data/ai/SessionViewer.input.ts"],"sourcesContent":["// Presentation helpers for a tool call's input: the one-line summary, the\n// JetBrains-style inline params, the inline shell command, and the line diff\n// for file-writing tools. Pure functions — the viewer renders their output.\n\nimport { computeLineDiff } from \"../code-diff\";\nimport { languageFromPath } from \"../code-highlight\";\nimport { stripTrailingSlashes } from \"../../lib/string\";\nimport { splitMcpTool, truncate } from \"./SessionViewer.model\";\n\n/** Strip the event's working directory from an absolute file path. */\nexport function relativizePath(path: string, cwd?: string): string {\n if (!cwd) return path;\n const base = stripTrailingSlashes(cwd);\n return path.startsWith(`${base}/`) ? path.slice(base.length + 1) : path;\n}\n\n/** The raw shell command of a shell-execution tool call, if present. Shell rows\n * render this inline as a bash code block instead of the generic label +\n * tool-input JSON. */\nexport function shellCommand(\n tool: string,\n input?: Record<string, unknown>,\n): string | undefined {\n if (tool !== \"Bash\") return undefined;\n const command = input?.[\"command\"];\n return typeof command === \"string\" && command ? command : undefined;\n}\n\nexport interface ToolParam {\n name: string;\n value: string;\n}\n\nexport interface SessionQuestionOption {\n value: string;\n label: string;\n description?: string;\n}\n\nexport interface SessionQuestion {\n id: string;\n text: string;\n context?: string;\n multiSelect?: boolean;\n options: SessionQuestionOption[];\n}\n\n// Keys already rendered elsewhere in the row — the file-path heading, the\n// inline shell command, or the diff — so they don't repeat as inline params.\nconst CONSUMED_INPUT_KEYS: Record<string, readonly string[]> = {\n Bash: [\"command\"],\n Read: [\"file_path\", \"notebook_path\", \"path\"],\n Write: [\"file_path\", \"notebook_path\", \"path\", \"content\"],\n Edit: [\"file_path\", \"notebook_path\", \"path\", \"old_string\", \"new_string\"],\n MultiEdit: [\"file_path\", \"notebook_path\", \"path\", \"edits\"],\n NotebookEdit: [\"file_path\", \"notebook_path\", \"path\"],\n AskUserQuestion: [\"questions\", \"question\", \"prompt\", \"text\", \"header\", \"context\", \"description\", \"options\"],\n};\n\n/** Flatten a tool's input into JetBrains-style `name: value` inline params:\n * single-line values, cwd-relativized and truncated so the row never wraps. */\nexport function toolInputParams(\n tool: string,\n input?: Record<string, unknown>,\n cwd?: string,\n): ToolParam[] {\n const consumed = CONSUMED_INPUT_KEYS[tool] ?? [];\n return Object.entries(input ?? {})\n .filter(\n ([name, value]) =>\n !consumed.includes(name) &&\n value !== undefined &&\n value !== null &&\n value !== \"\",\n )\n .map(([name, value]) => ({ name, value: paramValue(value, cwd) }));\n}\n\nfunction paramValue(value: unknown, cwd?: string): string {\n const text =\n typeof value === \"string\"\n ? relativizePath(value, cwd)\n : JSON.stringify(value);\n return truncate(text.replace(/\\s+/g, \" \").trim(), 60);\n}\n\n/** One before/after edit, rendered as a language-aware diff. */\nexport interface DiffSegment {\n original: string;\n modified: string;\n}\n\nexport interface ToolDiff {\n added: number;\n removed: number;\n /** Edits as original→modified pairs (Write has one; MultiEdit has several). */\n segments: DiffSegment[];\n /** Highlighter hint from the file extension, when known. */\n language?: string;\n}\n\n// Added/removed line counts from a real LCS diff — context lines don't count,\n// so a no-op edit reports 0/0 (and yields no diff).\nfunction diffCounts(segments: DiffSegment[]): {\n added: number;\n removed: number;\n} {\n let added = 0;\n let removed = 0;\n for (const { original, modified } of segments) {\n for (const hunk of computeLineDiff(original, modified)) {\n for (const line of hunk.lines) {\n if (line.type === \"add\") added += 1;\n else if (line.type === \"remove\") removed += 1;\n }\n }\n }\n return { added, removed };\n}\n\n/** The content change of a file-writing tool call as before/after segments —\n * Write is one all-additions segment; Edit/MultiEdit pair old and new text. */\nexport function toolDiff(\n tool: string,\n input?: Record<string, unknown>,\n): ToolDiff | undefined {\n if (!input) return undefined;\n const str = (key: string): string =>\n typeof input[key] === \"string\" ? (input[key] as string) : \"\";\n\n const segments = toolDiffSegments(tool, input, str);\n if (!segments || segments.length === 0) return undefined;\n const counts = diffCounts(segments);\n if (counts.added === 0 && counts.removed === 0) return undefined;\n\n const language = languageFromPath(\n str(\"file_path\") || str(\"notebook_path\") || str(\"path\"),\n );\n return { ...counts, segments, ...(language ? { language } : {}) };\n}\n\nfunction toolDiffSegments(\n tool: string,\n input: Record<string, unknown>,\n str: (key: string) => string,\n): DiffSegment[] | undefined {\n if (tool === \"Write\") {\n const content = str(\"content\");\n return content ? [{ original: \"\", modified: content }] : undefined;\n }\n if (tool === \"Edit\" || tool === \"NotebookEdit\") {\n const original = str(\"old_string\");\n const modified = str(\"new_string\") || str(\"new_source\");\n return original || modified ? [{ original, modified }] : undefined;\n }\n if (tool === \"MultiEdit\") {\n const edits = input[\"edits\"];\n if (!Array.isArray(edits)) return undefined;\n return edits\n .filter(\n (edit): edit is Record<string, unknown> =>\n typeof edit === \"object\" && edit !== null,\n )\n .map((edit) => ({\n original:\n typeof edit[\"old_string\"] === \"string\"\n ? (edit[\"old_string\"] as string)\n : \"\",\n modified:\n typeof edit[\"new_string\"] === \"string\"\n ? (edit[\"new_string\"] as string)\n : \"\",\n }))\n .filter((segment) => segment.original !== \"\" || segment.modified !== \"\");\n }\n return undefined;\n}\n\n// summarizeToolInput condenses a tool's input into a one-line preview, ported\n// from captain's history.FormatToolUseSummary so the viewer reads like the CLI.\nexport function summarizeToolInput(\n tool: string,\n input?: Record<string, unknown>,\n cwd?: string,\n): string {\n if (!input) return \"\";\n const str = (key: string): string =>\n typeof input[key] === \"string\" ? (input[key] as string) : \"\";\n const first = (...keys: string[]): string => {\n for (const key of keys) {\n const value = str(key);\n if (value) return value;\n }\n return \"\";\n };\n\n const mcp = splitMcpTool(tool);\n if (mcp) {\n const arg = first(\"url\", \"sql\", \"query\", \"element\", \"method\");\n return arg ? truncate(arg, 80) : \"\";\n }\n\n switch (tool) {\n case \"Bash\":\n case \"browser_type\":\n return str(\"command\") || str(\"text\");\n case \"Read\":\n case \"Write\":\n case \"Edit\":\n case \"MultiEdit\":\n case \"NotebookEdit\":\n return relativizePath(first(\"file_path\", \"notebook_path\", \"path\"), cwd);\n case \"Grep\":\n return [str(\"pattern\"), str(\"path\")].filter(Boolean).join(\" \");\n case \"Glob\":\n return str(\"pattern\");\n case \"Task\":\n case \"Agent\":\n return first(\"description\", \"prompt\");\n case \"Skill\":\n return first(\"skill\", \"command\", \"name\");\n case \"TaskCreate\":\n return first(\"subject\", \"description\");\n case \"TaskUpdate\": {\n const id = first(\"taskId\", \"task_id\", \"id\");\n const status = str(\"status\");\n return status ? `${id} ${status}`.trim() : id;\n }\n case \"TaskGet\":\n case \"TaskOutput\":\n case \"TaskStop\":\n return first(\"task_id\", \"taskId\", \"id\");\n case \"ToolSearch\":\n case \"WebSearch\":\n return str(\"query\");\n case \"WebFetch\":\n case \"browser_navigate\":\n return str(\"url\");\n case \"AskUserQuestion\": {\n const questions = questionsFromToolInput(input);\n const rawQuestions = input[\"questions\"];\n if (questions.length > 1) return `${questions.length} questions`;\n if (questions[0]?.text) return truncate(questions[0].text, 80);\n if (Array.isArray(rawQuestions) && rawQuestions.length > 0) return `${rawQuestions.length} questions`;\n return \"\";\n }\n case \"ExitPlanMode\":\n return str(\"planFilePath\");\n default:\n return \"\";\n }\n}\n\nexport function questionsFromToolInput(input?: Record<string, unknown>): SessionQuestion[] {\n if (!input) return [];\n const rawQuestions = input.questions;\n if (Array.isArray(rawQuestions)) {\n return rawQuestions\n .map((question, index) => questionFromValue(question, index))\n .filter((question): question is SessionQuestion => question !== null);\n }\n\n const text = stringField(input, \"question\") || stringField(input, \"prompt\") || stringField(input, \"text\");\n if (!text) return [];\n return [{\n id: stringField(input, \"id\") || \"1\",\n text,\n ...optionalContext(input),\n multiSelect: booleanField(input, \"multiSelect\") || booleanField(input, \"multi_select\"),\n options: optionList(input.options),\n }];\n}\n\nfunction questionFromValue(value: unknown, index: number): SessionQuestion | null {\n if (typeof value === \"string\") {\n const text = value.trim();\n return text ? { id: String(index + 1), text, options: [] } : null;\n }\n if (!isRecord(value)) return null;\n const text =\n stringField(value, \"question\") ||\n stringField(value, \"text\") ||\n stringField(value, \"prompt\") ||\n stringField(value, \"label\");\n if (!text) return null;\n return {\n id: stringField(value, \"id\") || String(index + 1),\n text,\n ...optionalContext(value),\n multiSelect: booleanField(value, \"multiSelect\") || booleanField(value, \"multi_select\"),\n options: optionList(value.options),\n };\n}\n\nfunction optionList(value: unknown): SessionQuestionOption[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap((option, index) => {\n if (typeof option === \"string\") {\n const label = option.trim();\n return label ? [{ value: label, label }] : [];\n }\n if (!isRecord(option)) return [];\n const label =\n stringField(option, \"label\") ||\n stringField(option, \"value\") ||\n stringField(option, \"id\") ||\n stringField(option, \"description\");\n if (!label) return [];\n const value = stringField(option, \"value\") || stringField(option, \"id\") || label;\n const description = stringField(option, \"description\");\n return [{\n value: value || String(index + 1),\n label,\n ...(description && description !== label ? { description } : {}),\n }];\n });\n}\n\nfunction optionalContext(input: Record<string, unknown>): Pick<SessionQuestion, \"context\"> {\n const context = stringField(input, \"header\") || stringField(input, \"context\") || stringField(input, \"description\");\n return context ? { context } : {};\n}\n\nfunction stringField(input: Record<string, unknown>, key: string): string {\n const value = input[key];\n return typeof value === \"string\" ? value.trim() : \"\";\n}\n\nfunction booleanField(input: Record<string, unknown>, key: string): boolean {\n return input[key] === true;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n"],"names":["stripTrailingSlashes","truncate","computeLineDiff","languageFromPath","splitMcpTool","text","label","value"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"SessionViewer.input.d.ts","sourceRoot":"","sources":["../../../src/data/ai/SessionViewer.input.ts"],"names":[],"mappings":"AAQA,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAIjE;AAED;;uBAEuB;AACvB,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,MAAM,GAAG,SAAS,CAIpB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,qBAAqB,EAAE,CAAC;CAClC;AAcD;gFACgF;AAChF,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,GAAG,CAAC,EAAE,MAAM,GACX,SAAS,EAAE,CAWb;AAUD,gEAAgE;AAChE,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAqBD;gFACgF;AAChF,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,QAAQ,GAAG,SAAS,CActB;AAyCD,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,GAAG,CAAC,EAAE,MAAM,GACX,MAAM,CAmER;AAED,wBAAgB,sBAAsB,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,EAAE,CAkBzF"}
1
+ {"version":3,"file":"SessionViewer.input.d.ts","sourceRoot":"","sources":["../../../src/data/ai/SessionViewer.input.ts"],"names":[],"mappings":"AASA,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAIjE;AAED;;uBAEuB;AACvB,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,MAAM,GAAG,SAAS,CAIpB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,qBAAqB,EAAE,CAAC;CAClC;AAcD;gFACgF;AAChF,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,GAAG,CAAC,EAAE,MAAM,GACX,SAAS,EAAE,CAWb;AAUD,gEAAgE;AAChE,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAqBD;gFACgF;AAChF,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,QAAQ,GAAG,SAAS,CActB;AAyCD,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,GAAG,CAAC,EAAE,MAAM,GACX,MAAM,CAmER;AAED,wBAAgB,sBAAsB,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,EAAE,CAkBzF"}
@@ -1,9 +1,10 @@
1
1
  import { computeLineDiff } from "../code-diff.js";
2
2
  import { languageFromPath } from "../code-highlight.js";
3
+ import { stripTrailingSlashes } from "../../lib/string.js";
3
4
  import { splitMcpTool, truncate } from "./SessionViewer.model.js";
4
5
  function relativizePath(path, cwd) {
5
6
  if (!cwd) return path;
6
- const base = cwd.replace(/\/+$/, "");
7
+ const base = stripTrailingSlashes(cwd);
7
8
  return path.startsWith(`${base}/`) ? path.slice(base.length + 1) : path;
8
9
  }
9
10
  function shellCommand(tool, input) {
@@ -1 +1 @@
1
- {"version":3,"file":"SessionViewer.input.js","sources":["../../../src/data/ai/SessionViewer.input.ts"],"sourcesContent":["// Presentation helpers for a tool call's input: the one-line summary, the\n// JetBrains-style inline params, the inline shell command, and the line diff\n// for file-writing tools. Pure functions — the viewer renders their output.\n\nimport { computeLineDiff } from \"../code-diff\";\nimport { languageFromPath } from \"../code-highlight\";\nimport { splitMcpTool, truncate } from \"./SessionViewer.model\";\n\n/** Strip the event's working directory from an absolute file path. */\nexport function relativizePath(path: string, cwd?: string): string {\n if (!cwd) return path;\n const base = cwd.replace(/\\/+$/, \"\");\n return path.startsWith(`${base}/`) ? path.slice(base.length + 1) : path;\n}\n\n/** The raw shell command of a shell-execution tool call, if present. Shell rows\n * render this inline as a bash code block instead of the generic label +\n * tool-input JSON. */\nexport function shellCommand(\n tool: string,\n input?: Record<string, unknown>,\n): string | undefined {\n if (tool !== \"Bash\") return undefined;\n const command = input?.[\"command\"];\n return typeof command === \"string\" && command ? command : undefined;\n}\n\nexport interface ToolParam {\n name: string;\n value: string;\n}\n\nexport interface SessionQuestionOption {\n value: string;\n label: string;\n description?: string;\n}\n\nexport interface SessionQuestion {\n id: string;\n text: string;\n context?: string;\n multiSelect?: boolean;\n options: SessionQuestionOption[];\n}\n\n// Keys already rendered elsewhere in the row — the file-path heading, the\n// inline shell command, or the diff — so they don't repeat as inline params.\nconst CONSUMED_INPUT_KEYS: Record<string, readonly string[]> = {\n Bash: [\"command\"],\n Read: [\"file_path\", \"notebook_path\", \"path\"],\n Write: [\"file_path\", \"notebook_path\", \"path\", \"content\"],\n Edit: [\"file_path\", \"notebook_path\", \"path\", \"old_string\", \"new_string\"],\n MultiEdit: [\"file_path\", \"notebook_path\", \"path\", \"edits\"],\n NotebookEdit: [\"file_path\", \"notebook_path\", \"path\"],\n AskUserQuestion: [\"questions\", \"question\", \"prompt\", \"text\", \"header\", \"context\", \"description\", \"options\"],\n};\n\n/** Flatten a tool's input into JetBrains-style `name: value` inline params:\n * single-line values, cwd-relativized and truncated so the row never wraps. */\nexport function toolInputParams(\n tool: string,\n input?: Record<string, unknown>,\n cwd?: string,\n): ToolParam[] {\n const consumed = CONSUMED_INPUT_KEYS[tool] ?? [];\n return Object.entries(input ?? {})\n .filter(\n ([name, value]) =>\n !consumed.includes(name) &&\n value !== undefined &&\n value !== null &&\n value !== \"\",\n )\n .map(([name, value]) => ({ name, value: paramValue(value, cwd) }));\n}\n\nfunction paramValue(value: unknown, cwd?: string): string {\n const text =\n typeof value === \"string\"\n ? relativizePath(value, cwd)\n : JSON.stringify(value);\n return truncate(text.replace(/\\s+/g, \" \").trim(), 60);\n}\n\n/** One before/after edit, rendered as a language-aware diff. */\nexport interface DiffSegment {\n original: string;\n modified: string;\n}\n\nexport interface ToolDiff {\n added: number;\n removed: number;\n /** Edits as original→modified pairs (Write has one; MultiEdit has several). */\n segments: DiffSegment[];\n /** Highlighter hint from the file extension, when known. */\n language?: string;\n}\n\n// Added/removed line counts from a real LCS diff — context lines don't count,\n// so a no-op edit reports 0/0 (and yields no diff).\nfunction diffCounts(segments: DiffSegment[]): {\n added: number;\n removed: number;\n} {\n let added = 0;\n let removed = 0;\n for (const { original, modified } of segments) {\n for (const hunk of computeLineDiff(original, modified)) {\n for (const line of hunk.lines) {\n if (line.type === \"add\") added += 1;\n else if (line.type === \"remove\") removed += 1;\n }\n }\n }\n return { added, removed };\n}\n\n/** The content change of a file-writing tool call as before/after segments —\n * Write is one all-additions segment; Edit/MultiEdit pair old and new text. */\nexport function toolDiff(\n tool: string,\n input?: Record<string, unknown>,\n): ToolDiff | undefined {\n if (!input) return undefined;\n const str = (key: string): string =>\n typeof input[key] === \"string\" ? (input[key] as string) : \"\";\n\n const segments = toolDiffSegments(tool, input, str);\n if (!segments || segments.length === 0) return undefined;\n const counts = diffCounts(segments);\n if (counts.added === 0 && counts.removed === 0) return undefined;\n\n const language = languageFromPath(\n str(\"file_path\") || str(\"notebook_path\") || str(\"path\"),\n );\n return { ...counts, segments, ...(language ? { language } : {}) };\n}\n\nfunction toolDiffSegments(\n tool: string,\n input: Record<string, unknown>,\n str: (key: string) => string,\n): DiffSegment[] | undefined {\n if (tool === \"Write\") {\n const content = str(\"content\");\n return content ? [{ original: \"\", modified: content }] : undefined;\n }\n if (tool === \"Edit\" || tool === \"NotebookEdit\") {\n const original = str(\"old_string\");\n const modified = str(\"new_string\") || str(\"new_source\");\n return original || modified ? [{ original, modified }] : undefined;\n }\n if (tool === \"MultiEdit\") {\n const edits = input[\"edits\"];\n if (!Array.isArray(edits)) return undefined;\n return edits\n .filter(\n (edit): edit is Record<string, unknown> =>\n typeof edit === \"object\" && edit !== null,\n )\n .map((edit) => ({\n original:\n typeof edit[\"old_string\"] === \"string\"\n ? (edit[\"old_string\"] as string)\n : \"\",\n modified:\n typeof edit[\"new_string\"] === \"string\"\n ? (edit[\"new_string\"] as string)\n : \"\",\n }))\n .filter((segment) => segment.original !== \"\" || segment.modified !== \"\");\n }\n return undefined;\n}\n\n// summarizeToolInput condenses a tool's input into a one-line preview, ported\n// from captain's history.FormatToolUseSummary so the viewer reads like the CLI.\nexport function summarizeToolInput(\n tool: string,\n input?: Record<string, unknown>,\n cwd?: string,\n): string {\n if (!input) return \"\";\n const str = (key: string): string =>\n typeof input[key] === \"string\" ? (input[key] as string) : \"\";\n const first = (...keys: string[]): string => {\n for (const key of keys) {\n const value = str(key);\n if (value) return value;\n }\n return \"\";\n };\n\n const mcp = splitMcpTool(tool);\n if (mcp) {\n const arg = first(\"url\", \"sql\", \"query\", \"element\", \"method\");\n return arg ? truncate(arg, 80) : \"\";\n }\n\n switch (tool) {\n case \"Bash\":\n case \"browser_type\":\n return str(\"command\") || str(\"text\");\n case \"Read\":\n case \"Write\":\n case \"Edit\":\n case \"MultiEdit\":\n case \"NotebookEdit\":\n return relativizePath(first(\"file_path\", \"notebook_path\", \"path\"), cwd);\n case \"Grep\":\n return [str(\"pattern\"), str(\"path\")].filter(Boolean).join(\" \");\n case \"Glob\":\n return str(\"pattern\");\n case \"Task\":\n case \"Agent\":\n return first(\"description\", \"prompt\");\n case \"Skill\":\n return first(\"skill\", \"command\", \"name\");\n case \"TaskCreate\":\n return first(\"subject\", \"description\");\n case \"TaskUpdate\": {\n const id = first(\"taskId\", \"task_id\", \"id\");\n const status = str(\"status\");\n return status ? `${id} ${status}`.trim() : id;\n }\n case \"TaskGet\":\n case \"TaskOutput\":\n case \"TaskStop\":\n return first(\"task_id\", \"taskId\", \"id\");\n case \"ToolSearch\":\n case \"WebSearch\":\n return str(\"query\");\n case \"WebFetch\":\n case \"browser_navigate\":\n return str(\"url\");\n case \"AskUserQuestion\": {\n const questions = questionsFromToolInput(input);\n const rawQuestions = input[\"questions\"];\n if (questions.length > 1) return `${questions.length} questions`;\n if (questions[0]?.text) return truncate(questions[0].text, 80);\n if (Array.isArray(rawQuestions) && rawQuestions.length > 0) return `${rawQuestions.length} questions`;\n return \"\";\n }\n case \"ExitPlanMode\":\n return str(\"planFilePath\");\n default:\n return \"\";\n }\n}\n\nexport function questionsFromToolInput(input?: Record<string, unknown>): SessionQuestion[] {\n if (!input) return [];\n const rawQuestions = input.questions;\n if (Array.isArray(rawQuestions)) {\n return rawQuestions\n .map((question, index) => questionFromValue(question, index))\n .filter((question): question is SessionQuestion => question !== null);\n }\n\n const text = stringField(input, \"question\") || stringField(input, \"prompt\") || stringField(input, \"text\");\n if (!text) return [];\n return [{\n id: stringField(input, \"id\") || \"1\",\n text,\n ...optionalContext(input),\n multiSelect: booleanField(input, \"multiSelect\") || booleanField(input, \"multi_select\"),\n options: optionList(input.options),\n }];\n}\n\nfunction questionFromValue(value: unknown, index: number): SessionQuestion | null {\n if (typeof value === \"string\") {\n const text = value.trim();\n return text ? { id: String(index + 1), text, options: [] } : null;\n }\n if (!isRecord(value)) return null;\n const text =\n stringField(value, \"question\") ||\n stringField(value, \"text\") ||\n stringField(value, \"prompt\") ||\n stringField(value, \"label\");\n if (!text) return null;\n return {\n id: stringField(value, \"id\") || String(index + 1),\n text,\n ...optionalContext(value),\n multiSelect: booleanField(value, \"multiSelect\") || booleanField(value, \"multi_select\"),\n options: optionList(value.options),\n };\n}\n\nfunction optionList(value: unknown): SessionQuestionOption[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap((option, index) => {\n if (typeof option === \"string\") {\n const label = option.trim();\n return label ? [{ value: label, label }] : [];\n }\n if (!isRecord(option)) return [];\n const label =\n stringField(option, \"label\") ||\n stringField(option, \"value\") ||\n stringField(option, \"id\") ||\n stringField(option, \"description\");\n if (!label) return [];\n const value = stringField(option, \"value\") || stringField(option, \"id\") || label;\n const description = stringField(option, \"description\");\n return [{\n value: value || String(index + 1),\n label,\n ...(description && description !== label ? { description } : {}),\n }];\n });\n}\n\nfunction optionalContext(input: Record<string, unknown>): Pick<SessionQuestion, \"context\"> {\n const context = stringField(input, \"header\") || stringField(input, \"context\") || stringField(input, \"description\");\n return context ? { context } : {};\n}\n\nfunction stringField(input: Record<string, unknown>, key: string): string {\n const value = input[key];\n return typeof value === \"string\" ? value.trim() : \"\";\n}\n\nfunction booleanField(input: Record<string, unknown>, key: string): boolean {\n return input[key] === true;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n"],"names":["text","label","value"],"mappings":";;;AASO,SAAS,eAAe,MAAc,KAAsB;AACjE,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,OAAO,IAAI,QAAQ,QAAQ,EAAE;AACnC,SAAO,KAAK,WAAW,GAAG,IAAI,GAAG,IAAI,KAAK,MAAM,KAAK,SAAS,CAAC,IAAI;AACrE;AAKO,SAAS,aACd,MACA,OACoB;AACpB,MAAI,SAAS,OAAQ,QAAO;AAC5B,QAAM,UAAU,+BAAQ;AACxB,SAAO,OAAO,YAAY,YAAY,UAAU,UAAU;AAC5D;AAuBA,MAAM,sBAAyD;AAAA,EAC7D,MAAM,CAAC,SAAS;AAAA,EAChB,MAAM,CAAC,aAAa,iBAAiB,MAAM;AAAA,EAC3C,OAAO,CAAC,aAAa,iBAAiB,QAAQ,SAAS;AAAA,EACvD,MAAM,CAAC,aAAa,iBAAiB,QAAQ,cAAc,YAAY;AAAA,EACvE,WAAW,CAAC,aAAa,iBAAiB,QAAQ,OAAO;AAAA,EACzD,cAAc,CAAC,aAAa,iBAAiB,MAAM;AAAA,EACnD,iBAAiB,CAAC,aAAa,YAAY,UAAU,QAAQ,UAAU,WAAW,eAAe,SAAS;AAC5G;AAIO,SAAS,gBACd,MACA,OACA,KACa;AACb,QAAM,WAAW,oBAAoB,IAAI,KAAK,CAAA;AAC9C,SAAO,OAAO,QAAQ,SAAS,CAAA,CAAE,EAC9B;AAAA,IACC,CAAC,CAAC,MAAM,KAAK,MACX,CAAC,SAAS,SAAS,IAAI,KACvB,UAAU,UACV,UAAU,QACV,UAAU;AAAA,EAAA,EAEb,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO,EAAE,MAAM,OAAO,WAAW,OAAO,GAAG,IAAI;AACrE;AAEA,SAAS,WAAW,OAAgB,KAAsB;AACxD,QAAM,OACJ,OAAO,UAAU,WACb,eAAe,OAAO,GAAG,IACzB,KAAK,UAAU,KAAK;AAC1B,SAAO,SAAS,KAAK,QAAQ,QAAQ,GAAG,EAAE,KAAA,GAAQ,EAAE;AACtD;AAmBA,SAAS,WAAW,UAGlB;AACA,MAAI,QAAQ;AACZ,MAAI,UAAU;AACd,aAAW,EAAE,UAAU,SAAA,KAAc,UAAU;AAC7C,eAAW,QAAQ,gBAAgB,UAAU,QAAQ,GAAG;AACtD,iBAAW,QAAQ,KAAK,OAAO;AAC7B,YAAI,KAAK,SAAS,MAAO,UAAS;AAAA,iBACzB,KAAK,SAAS,SAAU,YAAW;AAAA,MAC9C;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,OAAO,QAAA;AAClB;AAIO,SAAS,SACd,MACA,OACsB;AACtB,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,MAAM,CAAC,QACX,OAAO,MAAM,GAAG,MAAM,WAAY,MAAM,GAAG,IAAe;AAE5D,QAAM,WAAW,iBAAiB,MAAM,OAAO,GAAG;AAClD,MAAI,CAAC,YAAY,SAAS,WAAW,EAAG,QAAO;AAC/C,QAAM,SAAS,WAAW,QAAQ;AAClC,MAAI,OAAO,UAAU,KAAK,OAAO,YAAY,EAAG,QAAO;AAEvD,QAAM,WAAW;AAAA,IACf,IAAI,WAAW,KAAK,IAAI,eAAe,KAAK,IAAI,MAAM;AAAA,EAAA;AAExD,SAAO,EAAE,GAAG,QAAQ,UAAU,GAAI,WAAW,EAAE,SAAA,IAAa,GAAC;AAC/D;AAEA,SAAS,iBACP,MACA,OACA,KAC2B;AAC3B,MAAI,SAAS,SAAS;AACpB,UAAM,UAAU,IAAI,SAAS;AAC7B,WAAO,UAAU,CAAC,EAAE,UAAU,IAAI,UAAU,QAAA,CAAS,IAAI;AAAA,EAC3D;AACA,MAAI,SAAS,UAAU,SAAS,gBAAgB;AAC9C,UAAM,WAAW,IAAI,YAAY;AACjC,UAAM,WAAW,IAAI,YAAY,KAAK,IAAI,YAAY;AACtD,WAAO,YAAY,WAAW,CAAC,EAAE,UAAU,SAAA,CAAU,IAAI;AAAA,EAC3D;AACA,MAAI,SAAS,aAAa;AACxB,UAAM,QAAQ,MAAM,OAAO;AAC3B,QAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO;AAClC,WAAO,MACJ;AAAA,MACC,CAAC,SACC,OAAO,SAAS,YAAY,SAAS;AAAA,IAAA,EAExC,IAAI,CAAC,UAAU;AAAA,MACd,UACE,OAAO,KAAK,YAAY,MAAM,WACzB,KAAK,YAAY,IAClB;AAAA,MACN,UACE,OAAO,KAAK,YAAY,MAAM,WACzB,KAAK,YAAY,IAClB;AAAA,IAAA,EACN,EACD,OAAO,CAAC,YAAY,QAAQ,aAAa,MAAM,QAAQ,aAAa,EAAE;AAAA,EAC3E;AACA,SAAO;AACT;AAIO,SAAS,mBACd,MACA,OACA,KACQ;;AACR,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,MAAM,CAAC,QACX,OAAO,MAAM,GAAG,MAAM,WAAY,MAAM,GAAG,IAAe;AAC5D,QAAM,QAAQ,IAAI,SAA2B;AAC3C,eAAW,OAAO,MAAM;AACtB,YAAM,QAAQ,IAAI,GAAG;AACrB,UAAI,MAAO,QAAO;AAAA,IACpB;AACA,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,aAAa,IAAI;AAC7B,MAAI,KAAK;AACP,UAAM,MAAM,MAAM,OAAO,OAAO,SAAS,WAAW,QAAQ;AAC5D,WAAO,MAAM,SAAS,KAAK,EAAE,IAAI;AAAA,EACnC;AAEA,UAAQ,MAAA;AAAA,IACN,KAAK;AAAA,IACL,KAAK;AACH,aAAO,IAAI,SAAS,KAAK,IAAI,MAAM;AAAA,IACrC,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,eAAe,MAAM,aAAa,iBAAiB,MAAM,GAAG,GAAG;AAAA,IACxE,KAAK;AACH,aAAO,CAAC,IAAI,SAAS,GAAG,IAAI,MAAM,CAAC,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,IAC/D,KAAK;AACH,aAAO,IAAI,SAAS;AAAA,IACtB,KAAK;AAAA,IACL,KAAK;AACH,aAAO,MAAM,eAAe,QAAQ;AAAA,IACtC,KAAK;AACH,aAAO,MAAM,SAAS,WAAW,MAAM;AAAA,IACzC,KAAK;AACH,aAAO,MAAM,WAAW,aAAa;AAAA,IACvC,KAAK,cAAc;AACjB,YAAM,KAAK,MAAM,UAAU,WAAW,IAAI;AAC1C,YAAM,SAAS,IAAI,QAAQ;AAC3B,aAAO,SAAS,GAAG,EAAE,IAAI,MAAM,GAAG,SAAS;AAAA,IAC7C;AAAA,IACA,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,MAAM,WAAW,UAAU,IAAI;AAAA,IACxC,KAAK;AAAA,IACL,KAAK;AACH,aAAO,IAAI,OAAO;AAAA,IACpB,KAAK;AAAA,IACL,KAAK;AACH,aAAO,IAAI,KAAK;AAAA,IAClB,KAAK,mBAAmB;AACtB,YAAM,YAAY,uBAAuB,KAAK;AAC9C,YAAM,eAAe,MAAM,WAAW;AACtC,UAAI,UAAU,SAAS,EAAG,QAAO,GAAG,UAAU,MAAM;AACpD,WAAI,eAAU,CAAC,MAAX,mBAAc,KAAM,QAAO,SAAS,UAAU,CAAC,EAAE,MAAM,EAAE;AAC7D,UAAI,MAAM,QAAQ,YAAY,KAAK,aAAa,SAAS,EAAG,QAAO,GAAG,aAAa,MAAM;AACzF,aAAO;AAAA,IACT;AAAA,IACA,KAAK;AACH,aAAO,IAAI,cAAc;AAAA,IAC3B;AACE,aAAO;AAAA,EAAA;AAEb;AAEO,SAAS,uBAAuB,OAAoD;AACzF,MAAI,CAAC,MAAO,QAAO,CAAA;AACnB,QAAM,eAAe,MAAM;AAC3B,MAAI,MAAM,QAAQ,YAAY,GAAG;AAC/B,WAAO,aACJ,IAAI,CAAC,UAAU,UAAU,kBAAkB,UAAU,KAAK,CAAC,EAC3D,OAAO,CAAC,aAA0C,aAAa,IAAI;AAAA,EACxE;AAEA,QAAM,OAAO,YAAY,OAAO,UAAU,KAAK,YAAY,OAAO,QAAQ,KAAK,YAAY,OAAO,MAAM;AACxG,MAAI,CAAC,KAAM,QAAO,CAAA;AAClB,SAAO,CAAC;AAAA,IACN,IAAI,YAAY,OAAO,IAAI,KAAK;AAAA,IAChC;AAAA,IACA,GAAG,gBAAgB,KAAK;AAAA,IACxB,aAAa,aAAa,OAAO,aAAa,KAAK,aAAa,OAAO,cAAc;AAAA,IACrF,SAAS,WAAW,MAAM,OAAO;AAAA,EAAA,CAClC;AACH;AAEA,SAAS,kBAAkB,OAAgB,OAAuC;AAChF,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAMA,QAAO,MAAM,KAAA;AACnB,WAAOA,QAAO,EAAE,IAAI,OAAO,QAAQ,CAAC,GAAG,MAAAA,OAAM,SAAS,CAAA,EAAC,IAAM;AAAA,EAC/D;AACA,MAAI,CAAC,SAAS,KAAK,EAAG,QAAO;AAC7B,QAAM,OACJ,YAAY,OAAO,UAAU,KAC7B,YAAY,OAAO,MAAM,KACzB,YAAY,OAAO,QAAQ,KAC3B,YAAY,OAAO,OAAO;AAC5B,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO;AAAA,IACL,IAAI,YAAY,OAAO,IAAI,KAAK,OAAO,QAAQ,CAAC;AAAA,IAChD;AAAA,IACA,GAAG,gBAAgB,KAAK;AAAA,IACxB,aAAa,aAAa,OAAO,aAAa,KAAK,aAAa,OAAO,cAAc;AAAA,IACrF,SAAS,WAAW,MAAM,OAAO;AAAA,EAAA;AAErC;AAEA,SAAS,WAAW,OAAyC;AAC3D,MAAI,CAAC,MAAM,QAAQ,KAAK,UAAU,CAAA;AAClC,SAAO,MAAM,QAAQ,CAAC,QAAQ,UAAU;AACtC,QAAI,OAAO,WAAW,UAAU;AAC9B,YAAMC,SAAQ,OAAO,KAAA;AACrB,aAAOA,SAAQ,CAAC,EAAE,OAAOA,QAAO,OAAAA,OAAAA,CAAO,IAAI,CAAA;AAAA,IAC7C;AACA,QAAI,CAAC,SAAS,MAAM,UAAU,CAAA;AAC9B,UAAM,QACJ,YAAY,QAAQ,OAAO,KAC3B,YAAY,QAAQ,OAAO,KAC3B,YAAY,QAAQ,IAAI,KACxB,YAAY,QAAQ,aAAa;AACnC,QAAI,CAAC,MAAO,QAAO,CAAA;AACnB,UAAMC,SAAQ,YAAY,QAAQ,OAAO,KAAK,YAAY,QAAQ,IAAI,KAAK;AAC3E,UAAM,cAAc,YAAY,QAAQ,aAAa;AACrD,WAAO,CAAC;AAAA,MACN,OAAOA,UAAS,OAAO,QAAQ,CAAC;AAAA,MAChC;AAAA,MACA,GAAI,eAAe,gBAAgB,QAAQ,EAAE,YAAA,IAAgB,CAAA;AAAA,IAAC,CAC/D;AAAA,EACH,CAAC;AACH;AAEA,SAAS,gBAAgB,OAAkE;AACzF,QAAM,UAAU,YAAY,OAAO,QAAQ,KAAK,YAAY,OAAO,SAAS,KAAK,YAAY,OAAO,aAAa;AACjH,SAAO,UAAU,EAAE,QAAA,IAAY,CAAA;AACjC;AAEA,SAAS,YAAY,OAAgC,KAAqB;AACxE,QAAM,QAAQ,MAAM,GAAG;AACvB,SAAO,OAAO,UAAU,WAAW,MAAM,SAAS;AACpD;AAEA,SAAS,aAAa,OAAgC,KAAsB;AAC1E,SAAO,MAAM,GAAG,MAAM;AACxB;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,CAAC,CAAC,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AACrE;"}
1
+ {"version":3,"file":"SessionViewer.input.js","sources":["../../../src/data/ai/SessionViewer.input.ts"],"sourcesContent":["// Presentation helpers for a tool call's input: the one-line summary, the\n// JetBrains-style inline params, the inline shell command, and the line diff\n// for file-writing tools. Pure functions — the viewer renders their output.\n\nimport { computeLineDiff } from \"../code-diff\";\nimport { languageFromPath } from \"../code-highlight\";\nimport { stripTrailingSlashes } from \"../../lib/string\";\nimport { splitMcpTool, truncate } from \"./SessionViewer.model\";\n\n/** Strip the event's working directory from an absolute file path. */\nexport function relativizePath(path: string, cwd?: string): string {\n if (!cwd) return path;\n const base = stripTrailingSlashes(cwd);\n return path.startsWith(`${base}/`) ? path.slice(base.length + 1) : path;\n}\n\n/** The raw shell command of a shell-execution tool call, if present. Shell rows\n * render this inline as a bash code block instead of the generic label +\n * tool-input JSON. */\nexport function shellCommand(\n tool: string,\n input?: Record<string, unknown>,\n): string | undefined {\n if (tool !== \"Bash\") return undefined;\n const command = input?.[\"command\"];\n return typeof command === \"string\" && command ? command : undefined;\n}\n\nexport interface ToolParam {\n name: string;\n value: string;\n}\n\nexport interface SessionQuestionOption {\n value: string;\n label: string;\n description?: string;\n}\n\nexport interface SessionQuestion {\n id: string;\n text: string;\n context?: string;\n multiSelect?: boolean;\n options: SessionQuestionOption[];\n}\n\n// Keys already rendered elsewhere in the row — the file-path heading, the\n// inline shell command, or the diff — so they don't repeat as inline params.\nconst CONSUMED_INPUT_KEYS: Record<string, readonly string[]> = {\n Bash: [\"command\"],\n Read: [\"file_path\", \"notebook_path\", \"path\"],\n Write: [\"file_path\", \"notebook_path\", \"path\", \"content\"],\n Edit: [\"file_path\", \"notebook_path\", \"path\", \"old_string\", \"new_string\"],\n MultiEdit: [\"file_path\", \"notebook_path\", \"path\", \"edits\"],\n NotebookEdit: [\"file_path\", \"notebook_path\", \"path\"],\n AskUserQuestion: [\"questions\", \"question\", \"prompt\", \"text\", \"header\", \"context\", \"description\", \"options\"],\n};\n\n/** Flatten a tool's input into JetBrains-style `name: value` inline params:\n * single-line values, cwd-relativized and truncated so the row never wraps. */\nexport function toolInputParams(\n tool: string,\n input?: Record<string, unknown>,\n cwd?: string,\n): ToolParam[] {\n const consumed = CONSUMED_INPUT_KEYS[tool] ?? [];\n return Object.entries(input ?? {})\n .filter(\n ([name, value]) =>\n !consumed.includes(name) &&\n value !== undefined &&\n value !== null &&\n value !== \"\",\n )\n .map(([name, value]) => ({ name, value: paramValue(value, cwd) }));\n}\n\nfunction paramValue(value: unknown, cwd?: string): string {\n const text =\n typeof value === \"string\"\n ? relativizePath(value, cwd)\n : JSON.stringify(value);\n return truncate(text.replace(/\\s+/g, \" \").trim(), 60);\n}\n\n/** One before/after edit, rendered as a language-aware diff. */\nexport interface DiffSegment {\n original: string;\n modified: string;\n}\n\nexport interface ToolDiff {\n added: number;\n removed: number;\n /** Edits as original→modified pairs (Write has one; MultiEdit has several). */\n segments: DiffSegment[];\n /** Highlighter hint from the file extension, when known. */\n language?: string;\n}\n\n// Added/removed line counts from a real LCS diff — context lines don't count,\n// so a no-op edit reports 0/0 (and yields no diff).\nfunction diffCounts(segments: DiffSegment[]): {\n added: number;\n removed: number;\n} {\n let added = 0;\n let removed = 0;\n for (const { original, modified } of segments) {\n for (const hunk of computeLineDiff(original, modified)) {\n for (const line of hunk.lines) {\n if (line.type === \"add\") added += 1;\n else if (line.type === \"remove\") removed += 1;\n }\n }\n }\n return { added, removed };\n}\n\n/** The content change of a file-writing tool call as before/after segments —\n * Write is one all-additions segment; Edit/MultiEdit pair old and new text. */\nexport function toolDiff(\n tool: string,\n input?: Record<string, unknown>,\n): ToolDiff | undefined {\n if (!input) return undefined;\n const str = (key: string): string =>\n typeof input[key] === \"string\" ? (input[key] as string) : \"\";\n\n const segments = toolDiffSegments(tool, input, str);\n if (!segments || segments.length === 0) return undefined;\n const counts = diffCounts(segments);\n if (counts.added === 0 && counts.removed === 0) return undefined;\n\n const language = languageFromPath(\n str(\"file_path\") || str(\"notebook_path\") || str(\"path\"),\n );\n return { ...counts, segments, ...(language ? { language } : {}) };\n}\n\nfunction toolDiffSegments(\n tool: string,\n input: Record<string, unknown>,\n str: (key: string) => string,\n): DiffSegment[] | undefined {\n if (tool === \"Write\") {\n const content = str(\"content\");\n return content ? [{ original: \"\", modified: content }] : undefined;\n }\n if (tool === \"Edit\" || tool === \"NotebookEdit\") {\n const original = str(\"old_string\");\n const modified = str(\"new_string\") || str(\"new_source\");\n return original || modified ? [{ original, modified }] : undefined;\n }\n if (tool === \"MultiEdit\") {\n const edits = input[\"edits\"];\n if (!Array.isArray(edits)) return undefined;\n return edits\n .filter(\n (edit): edit is Record<string, unknown> =>\n typeof edit === \"object\" && edit !== null,\n )\n .map((edit) => ({\n original:\n typeof edit[\"old_string\"] === \"string\"\n ? (edit[\"old_string\"] as string)\n : \"\",\n modified:\n typeof edit[\"new_string\"] === \"string\"\n ? (edit[\"new_string\"] as string)\n : \"\",\n }))\n .filter((segment) => segment.original !== \"\" || segment.modified !== \"\");\n }\n return undefined;\n}\n\n// summarizeToolInput condenses a tool's input into a one-line preview, ported\n// from captain's history.FormatToolUseSummary so the viewer reads like the CLI.\nexport function summarizeToolInput(\n tool: string,\n input?: Record<string, unknown>,\n cwd?: string,\n): string {\n if (!input) return \"\";\n const str = (key: string): string =>\n typeof input[key] === \"string\" ? (input[key] as string) : \"\";\n const first = (...keys: string[]): string => {\n for (const key of keys) {\n const value = str(key);\n if (value) return value;\n }\n return \"\";\n };\n\n const mcp = splitMcpTool(tool);\n if (mcp) {\n const arg = first(\"url\", \"sql\", \"query\", \"element\", \"method\");\n return arg ? truncate(arg, 80) : \"\";\n }\n\n switch (tool) {\n case \"Bash\":\n case \"browser_type\":\n return str(\"command\") || str(\"text\");\n case \"Read\":\n case \"Write\":\n case \"Edit\":\n case \"MultiEdit\":\n case \"NotebookEdit\":\n return relativizePath(first(\"file_path\", \"notebook_path\", \"path\"), cwd);\n case \"Grep\":\n return [str(\"pattern\"), str(\"path\")].filter(Boolean).join(\" \");\n case \"Glob\":\n return str(\"pattern\");\n case \"Task\":\n case \"Agent\":\n return first(\"description\", \"prompt\");\n case \"Skill\":\n return first(\"skill\", \"command\", \"name\");\n case \"TaskCreate\":\n return first(\"subject\", \"description\");\n case \"TaskUpdate\": {\n const id = first(\"taskId\", \"task_id\", \"id\");\n const status = str(\"status\");\n return status ? `${id} ${status}`.trim() : id;\n }\n case \"TaskGet\":\n case \"TaskOutput\":\n case \"TaskStop\":\n return first(\"task_id\", \"taskId\", \"id\");\n case \"ToolSearch\":\n case \"WebSearch\":\n return str(\"query\");\n case \"WebFetch\":\n case \"browser_navigate\":\n return str(\"url\");\n case \"AskUserQuestion\": {\n const questions = questionsFromToolInput(input);\n const rawQuestions = input[\"questions\"];\n if (questions.length > 1) return `${questions.length} questions`;\n if (questions[0]?.text) return truncate(questions[0].text, 80);\n if (Array.isArray(rawQuestions) && rawQuestions.length > 0) return `${rawQuestions.length} questions`;\n return \"\";\n }\n case \"ExitPlanMode\":\n return str(\"planFilePath\");\n default:\n return \"\";\n }\n}\n\nexport function questionsFromToolInput(input?: Record<string, unknown>): SessionQuestion[] {\n if (!input) return [];\n const rawQuestions = input.questions;\n if (Array.isArray(rawQuestions)) {\n return rawQuestions\n .map((question, index) => questionFromValue(question, index))\n .filter((question): question is SessionQuestion => question !== null);\n }\n\n const text = stringField(input, \"question\") || stringField(input, \"prompt\") || stringField(input, \"text\");\n if (!text) return [];\n return [{\n id: stringField(input, \"id\") || \"1\",\n text,\n ...optionalContext(input),\n multiSelect: booleanField(input, \"multiSelect\") || booleanField(input, \"multi_select\"),\n options: optionList(input.options),\n }];\n}\n\nfunction questionFromValue(value: unknown, index: number): SessionQuestion | null {\n if (typeof value === \"string\") {\n const text = value.trim();\n return text ? { id: String(index + 1), text, options: [] } : null;\n }\n if (!isRecord(value)) return null;\n const text =\n stringField(value, \"question\") ||\n stringField(value, \"text\") ||\n stringField(value, \"prompt\") ||\n stringField(value, \"label\");\n if (!text) return null;\n return {\n id: stringField(value, \"id\") || String(index + 1),\n text,\n ...optionalContext(value),\n multiSelect: booleanField(value, \"multiSelect\") || booleanField(value, \"multi_select\"),\n options: optionList(value.options),\n };\n}\n\nfunction optionList(value: unknown): SessionQuestionOption[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap((option, index) => {\n if (typeof option === \"string\") {\n const label = option.trim();\n return label ? [{ value: label, label }] : [];\n }\n if (!isRecord(option)) return [];\n const label =\n stringField(option, \"label\") ||\n stringField(option, \"value\") ||\n stringField(option, \"id\") ||\n stringField(option, \"description\");\n if (!label) return [];\n const value = stringField(option, \"value\") || stringField(option, \"id\") || label;\n const description = stringField(option, \"description\");\n return [{\n value: value || String(index + 1),\n label,\n ...(description && description !== label ? { description } : {}),\n }];\n });\n}\n\nfunction optionalContext(input: Record<string, unknown>): Pick<SessionQuestion, \"context\"> {\n const context = stringField(input, \"header\") || stringField(input, \"context\") || stringField(input, \"description\");\n return context ? { context } : {};\n}\n\nfunction stringField(input: Record<string, unknown>, key: string): string {\n const value = input[key];\n return typeof value === \"string\" ? value.trim() : \"\";\n}\n\nfunction booleanField(input: Record<string, unknown>, key: string): boolean {\n return input[key] === true;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n"],"names":["text","label","value"],"mappings":"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"}
@@ -66,16 +66,48 @@ function isApplicationStackFrame(file) {
66
66
  return file.includes("github.com/flanksource/incident-commander/") || file.includes("/incident-commander/");
67
67
  }
68
68
  function parseStackTraceFrame(line) {
69
- var _a;
70
- const match = line.match(/^--- at (.+):(\d+)(?:\s+(.+))?$/);
71
- if (!match) return null;
69
+ const prefix = "--- at ";
70
+ if (!line.startsWith(prefix)) return null;
71
+ const value = line.slice(prefix.length);
72
+ let fileEnd = -1;
73
+ let lineStart = -1;
74
+ let lineEnd = -1;
75
+ let functionStart = -1;
76
+ for (let index = 0; index < value.length; index++) {
77
+ if (value[index] !== ":" || !isDecimalDigit(value[index + 1])) continue;
78
+ let end = index + 1;
79
+ while (isDecimalDigit(value[end])) end++;
80
+ if (end === value.length) {
81
+ fileEnd = index;
82
+ lineStart = index + 1;
83
+ lineEnd = end;
84
+ functionStart = -1;
85
+ continue;
86
+ }
87
+ if (!isWhitespace(value[end])) continue;
88
+ let start = end;
89
+ while (isWhitespace(value[start])) start++;
90
+ if (start === value.length && start - end < 2) continue;
91
+ fileEnd = index;
92
+ lineStart = index + 1;
93
+ lineEnd = end;
94
+ functionStart = start;
95
+ }
96
+ if (fileEnd <= 0 || lineStart < 0 || lineEnd < 0) return null;
97
+ const functionName = functionStart >= 0 ? value.slice(functionStart).trim() : "";
72
98
  return {
73
99
  raw: line,
74
- file: match[1] ?? "",
75
- line: Number(match[2] ?? 0),
76
- ...((_a = match[3]) == null ? void 0 : _a.trim()) ? { functionName: match[3].trim() } : {}
100
+ file: value.slice(0, fileEnd),
101
+ line: Number(value.slice(lineStart, lineEnd)),
102
+ ...functionName ? { functionName } : {}
77
103
  };
78
104
  }
105
+ function isDecimalDigit(value) {
106
+ return value !== void 0 && value >= "0" && value <= "9";
107
+ }
108
+ function isWhitespace(value) {
109
+ return value !== void 0 && value.trim() === "";
110
+ }
79
111
  function objectRecord(value) {
80
112
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
81
113
  return value;
@@ -1 +1 @@
1
- {"version":3,"file":"error-diagnostics.cjs","sources":["../../../src/data/diagnostics/error-diagnostics.ts"],"sourcesContent":["// Normalize ad-hoc error payloads (oops JSON, plain strings, nested objects)\n// into the shape ErrorDetails consumes. Mirrors what `samber/oops` emits\n// from `OopsError.MarshalJSON()` on the Go side.\n\nexport type ErrorDiagnostics = {\n message: string;\n trace?: string;\n time?: string;\n stacktrace?: string;\n context: Array<[string, string]>;\n raw?: unknown;\n};\n\nexport type ParsedErrorStackTrace = {\n headline?: string;\n frames: ErrorStackFrame[];\n unparsed: string[];\n raw: string;\n};\n\nexport type ErrorStackFrame = {\n raw: string;\n file: string;\n line: number;\n functionName?: string;\n};\n\nexport function normalizeErrorDiagnostics(\n value: unknown,\n fallback?: string | null,\n): ErrorDiagnostics | null {\n if (!value) return null;\n if (typeof value === \"string\") {\n return value.trim() ? { message: value, context: [] } : null;\n }\n const record = objectRecord(value);\n if (!record) return null;\n const nested = objectRecord(record.error) ?? objectRecord(record.diagnostics);\n if (nested && nested !== record) {\n return normalizeErrorDiagnostics(nested, fallback);\n }\n const message =\n firstString(record, [\"error\", \"message\", \"msg\", \"reason\", \"detail\", \"details\"]) ?? fallback;\n const trace = firstString(record, [\"trace\", \"trace_id\", \"traceId\", \"traceID\"]);\n const stacktrace = firstString(record, [\"stacktrace\", \"stack_trace\", \"stackTrace\", \"stack\"]);\n const time = firstString(record, [\"time\", \"timestamp\", \"created_at\"]);\n const context = contextEntries(record.context);\n if (!message && !trace && !stacktrace && context.length === 0) return null;\n return {\n message: message ?? \"Action failed\",\n context,\n raw: value,\n ...(trace !== undefined ? { trace } : {}),\n ...(time !== undefined ? { time } : {}),\n ...(stacktrace !== undefined ? { stacktrace } : {}),\n };\n}\n\nexport function parseDiagnosticsStackTrace(stacktrace: string): ParsedErrorStackTrace {\n const lines = stacktrace\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(Boolean);\n const frames: ErrorStackFrame[] = [];\n const unparsed: string[] = [];\n let headline: string | undefined;\n\n for (const line of lines) {\n const frame = parseStackTraceFrame(line);\n if (frame) {\n frames.push(frame);\n continue;\n }\n if (!headline && !line.startsWith(\"--- at \")) {\n headline = line;\n continue;\n }\n unparsed.push(line);\n }\n\n return {\n frames,\n unparsed,\n raw: stacktrace,\n ...(headline !== undefined ? { headline } : {}),\n };\n}\n\nexport function parseInlineJsonContextValue(value: string): unknown | null {\n const trimmed = value.trim();\n if (!trimmed || !/^[{[]/.test(trimmed)) return null;\n try {\n return JSON.parse(trimmed);\n } catch {\n return null;\n }\n}\n\nexport function compactStackPath(file: string) {\n return file\n .replace(/^github\\.com\\/flanksource\\/incident-commander\\//, \"\")\n .replace(/^github\\.com\\/flanksource\\//, \"flanksource/\")\n .replace(/^.*\\/go\\/pkg\\/mod\\//, \"pkg/mod/\")\n .replace(/^.*\\/incident-commander\\//, \"\");\n}\n\nexport function isApplicationStackFrame(file: string) {\n return (\n file.includes(\"github.com/flanksource/incident-commander/\") ||\n file.includes(\"/incident-commander/\")\n );\n}\n\nfunction parseStackTraceFrame(line: string): ErrorStackFrame | null {\n const match = line.match(/^--- at (.+):(\\d+)(?:\\s+(.+))?$/);\n if (!match) return null;\n return {\n raw: line,\n file: match[1] ?? \"\",\n line: Number(match[2] ?? 0),\n ...(match[3]?.trim() ? { functionName: match[3]!.trim() } : {}),\n };\n}\n\nfunction objectRecord(value: unknown): Record<string, unknown> | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n return value as Record<string, unknown>;\n}\n\nfunction firstString(record: Record<string, unknown>, keys: string[]): string | undefined {\n for (const key of keys) {\n const value = record[key];\n if (typeof value === \"string\" && value.trim()) return value;\n }\n return undefined;\n}\n\nfunction contextEntries(value: unknown): Array<[string, string]> {\n const record = objectRecord(value);\n if (!record) return [];\n return Object.entries(record)\n .filter(\n ([, entryValue]) => entryValue !== undefined && entryValue !== null && entryValue !== \"\",\n )\n .map(([key, entryValue]) => [key, stringifyValue(entryValue)]);\n}\n\nfunction stringifyValue(value: unknown): string {\n if (value === null || value === undefined || value === \"\") return \"-\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n return JSON.stringify(value);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"error-diagnostics.cjs","sources":["../../../src/data/diagnostics/error-diagnostics.ts"],"sourcesContent":["// Normalize ad-hoc error payloads (oops JSON, plain strings, nested objects)\n// into the shape ErrorDetails consumes. Mirrors what `samber/oops` emits\n// from `OopsError.MarshalJSON()` on the Go side.\n\nexport type ErrorDiagnostics = {\n message: string;\n trace?: string;\n time?: string;\n stacktrace?: string;\n context: Array<[string, string]>;\n raw?: unknown;\n};\n\nexport type ParsedErrorStackTrace = {\n headline?: string;\n frames: ErrorStackFrame[];\n unparsed: string[];\n raw: string;\n};\n\nexport type ErrorStackFrame = {\n raw: string;\n file: string;\n line: number;\n functionName?: string;\n};\n\nexport function normalizeErrorDiagnostics(\n value: unknown,\n fallback?: string | null,\n): ErrorDiagnostics | null {\n if (!value) return null;\n if (typeof value === \"string\") {\n return value.trim() ? { message: value, context: [] } : null;\n }\n const record = objectRecord(value);\n if (!record) return null;\n const nested = objectRecord(record.error) ?? objectRecord(record.diagnostics);\n if (nested && nested !== record) {\n return normalizeErrorDiagnostics(nested, fallback);\n }\n const message =\n firstString(record, [\"error\", \"message\", \"msg\", \"reason\", \"detail\", \"details\"]) ?? fallback;\n const trace = firstString(record, [\"trace\", \"trace_id\", \"traceId\", \"traceID\"]);\n const stacktrace = firstString(record, [\"stacktrace\", \"stack_trace\", \"stackTrace\", \"stack\"]);\n const time = firstString(record, [\"time\", \"timestamp\", \"created_at\"]);\n const context = contextEntries(record.context);\n if (!message && !trace && !stacktrace && context.length === 0) return null;\n return {\n message: message ?? \"Action failed\",\n context,\n raw: value,\n ...(trace !== undefined ? { trace } : {}),\n ...(time !== undefined ? { time } : {}),\n ...(stacktrace !== undefined ? { stacktrace } : {}),\n };\n}\n\nexport function parseDiagnosticsStackTrace(stacktrace: string): ParsedErrorStackTrace {\n const lines = stacktrace\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(Boolean);\n const frames: ErrorStackFrame[] = [];\n const unparsed: string[] = [];\n let headline: string | undefined;\n\n for (const line of lines) {\n const frame = parseStackTraceFrame(line);\n if (frame) {\n frames.push(frame);\n continue;\n }\n if (!headline && !line.startsWith(\"--- at \")) {\n headline = line;\n continue;\n }\n unparsed.push(line);\n }\n\n return {\n frames,\n unparsed,\n raw: stacktrace,\n ...(headline !== undefined ? { headline } : {}),\n };\n}\n\nexport function parseInlineJsonContextValue(value: string): unknown | null {\n const trimmed = value.trim();\n if (!trimmed || !/^[{[]/.test(trimmed)) return null;\n try {\n return JSON.parse(trimmed);\n } catch {\n return null;\n }\n}\n\nexport function compactStackPath(file: string) {\n return file\n .replace(/^github\\.com\\/flanksource\\/incident-commander\\//, \"\")\n .replace(/^github\\.com\\/flanksource\\//, \"flanksource/\")\n .replace(/^.*\\/go\\/pkg\\/mod\\//, \"pkg/mod/\")\n .replace(/^.*\\/incident-commander\\//, \"\");\n}\n\nexport function isApplicationStackFrame(file: string) {\n return (\n file.includes(\"github.com/flanksource/incident-commander/\") ||\n file.includes(\"/incident-commander/\")\n );\n}\n\nfunction parseStackTraceFrame(line: string): ErrorStackFrame | null {\n const prefix = \"--- at \";\n if (!line.startsWith(prefix)) return null;\n\n const value = line.slice(prefix.length);\n let fileEnd = -1;\n let lineStart = -1;\n let lineEnd = -1;\n let functionStart = -1;\n\n for (let index = 0; index < value.length; index++) {\n if (value[index] !== \":\" || !isDecimalDigit(value[index + 1])) continue;\n\n let end = index + 1;\n while (isDecimalDigit(value[end])) end++;\n if (end === value.length) {\n fileEnd = index;\n lineStart = index + 1;\n lineEnd = end;\n functionStart = -1;\n continue;\n }\n if (!isWhitespace(value[end])) continue;\n\n let start = end;\n while (isWhitespace(value[start])) start++;\n if (start === value.length && start - end < 2) continue;\n fileEnd = index;\n lineStart = index + 1;\n lineEnd = end;\n functionStart = start;\n }\n\n if (fileEnd <= 0 || lineStart < 0 || lineEnd < 0) return null;\n const functionName = functionStart >= 0 ? value.slice(functionStart).trim() : \"\";\n return {\n raw: line,\n file: value.slice(0, fileEnd),\n line: Number(value.slice(lineStart, lineEnd)),\n ...(functionName ? { functionName } : {}),\n };\n}\n\nfunction isDecimalDigit(value: string | undefined): boolean {\n return value !== undefined && value >= \"0\" && value <= \"9\";\n}\n\nfunction isWhitespace(value: string | undefined): boolean {\n return value !== undefined && value.trim() === \"\";\n}\n\nfunction objectRecord(value: unknown): Record<string, unknown> | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n return value as Record<string, unknown>;\n}\n\nfunction firstString(record: Record<string, unknown>, keys: string[]): string | undefined {\n for (const key of keys) {\n const value = record[key];\n if (typeof value === \"string\" && value.trim()) return value;\n }\n return undefined;\n}\n\nfunction contextEntries(value: unknown): Array<[string, string]> {\n const record = objectRecord(value);\n if (!record) return [];\n return Object.entries(record)\n .filter(\n ([, entryValue]) => entryValue !== undefined && entryValue !== null && entryValue !== \"\",\n )\n .map(([key, entryValue]) => [key, stringifyValue(entryValue)]);\n}\n\nfunction stringifyValue(value: unknown): string {\n if (value === null || value === undefined || value === \"\") return \"-\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n return JSON.stringify(value);\n}\n"],"names":[],"mappings":"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"}
@@ -64,16 +64,48 @@ function isApplicationStackFrame(file) {
64
64
  return file.includes("github.com/flanksource/incident-commander/") || file.includes("/incident-commander/");
65
65
  }
66
66
  function parseStackTraceFrame(line) {
67
- var _a;
68
- const match = line.match(/^--- at (.+):(\d+)(?:\s+(.+))?$/);
69
- if (!match) return null;
67
+ const prefix = "--- at ";
68
+ if (!line.startsWith(prefix)) return null;
69
+ const value = line.slice(prefix.length);
70
+ let fileEnd = -1;
71
+ let lineStart = -1;
72
+ let lineEnd = -1;
73
+ let functionStart = -1;
74
+ for (let index = 0; index < value.length; index++) {
75
+ if (value[index] !== ":" || !isDecimalDigit(value[index + 1])) continue;
76
+ let end = index + 1;
77
+ while (isDecimalDigit(value[end])) end++;
78
+ if (end === value.length) {
79
+ fileEnd = index;
80
+ lineStart = index + 1;
81
+ lineEnd = end;
82
+ functionStart = -1;
83
+ continue;
84
+ }
85
+ if (!isWhitespace(value[end])) continue;
86
+ let start = end;
87
+ while (isWhitespace(value[start])) start++;
88
+ if (start === value.length && start - end < 2) continue;
89
+ fileEnd = index;
90
+ lineStart = index + 1;
91
+ lineEnd = end;
92
+ functionStart = start;
93
+ }
94
+ if (fileEnd <= 0 || lineStart < 0 || lineEnd < 0) return null;
95
+ const functionName = functionStart >= 0 ? value.slice(functionStart).trim() : "";
70
96
  return {
71
97
  raw: line,
72
- file: match[1] ?? "",
73
- line: Number(match[2] ?? 0),
74
- ...((_a = match[3]) == null ? void 0 : _a.trim()) ? { functionName: match[3].trim() } : {}
98
+ file: value.slice(0, fileEnd),
99
+ line: Number(value.slice(lineStart, lineEnd)),
100
+ ...functionName ? { functionName } : {}
75
101
  };
76
102
  }
103
+ function isDecimalDigit(value) {
104
+ return value !== void 0 && value >= "0" && value <= "9";
105
+ }
106
+ function isWhitespace(value) {
107
+ return value !== void 0 && value.trim() === "";
108
+ }
77
109
  function objectRecord(value) {
78
110
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
79
111
  return value;
@@ -1 +1 @@
1
- {"version":3,"file":"error-diagnostics.js","sources":["../../../src/data/diagnostics/error-diagnostics.ts"],"sourcesContent":["// Normalize ad-hoc error payloads (oops JSON, plain strings, nested objects)\n// into the shape ErrorDetails consumes. Mirrors what `samber/oops` emits\n// from `OopsError.MarshalJSON()` on the Go side.\n\nexport type ErrorDiagnostics = {\n message: string;\n trace?: string;\n time?: string;\n stacktrace?: string;\n context: Array<[string, string]>;\n raw?: unknown;\n};\n\nexport type ParsedErrorStackTrace = {\n headline?: string;\n frames: ErrorStackFrame[];\n unparsed: string[];\n raw: string;\n};\n\nexport type ErrorStackFrame = {\n raw: string;\n file: string;\n line: number;\n functionName?: string;\n};\n\nexport function normalizeErrorDiagnostics(\n value: unknown,\n fallback?: string | null,\n): ErrorDiagnostics | null {\n if (!value) return null;\n if (typeof value === \"string\") {\n return value.trim() ? { message: value, context: [] } : null;\n }\n const record = objectRecord(value);\n if (!record) return null;\n const nested = objectRecord(record.error) ?? objectRecord(record.diagnostics);\n if (nested && nested !== record) {\n return normalizeErrorDiagnostics(nested, fallback);\n }\n const message =\n firstString(record, [\"error\", \"message\", \"msg\", \"reason\", \"detail\", \"details\"]) ?? fallback;\n const trace = firstString(record, [\"trace\", \"trace_id\", \"traceId\", \"traceID\"]);\n const stacktrace = firstString(record, [\"stacktrace\", \"stack_trace\", \"stackTrace\", \"stack\"]);\n const time = firstString(record, [\"time\", \"timestamp\", \"created_at\"]);\n const context = contextEntries(record.context);\n if (!message && !trace && !stacktrace && context.length === 0) return null;\n return {\n message: message ?? \"Action failed\",\n context,\n raw: value,\n ...(trace !== undefined ? { trace } : {}),\n ...(time !== undefined ? { time } : {}),\n ...(stacktrace !== undefined ? { stacktrace } : {}),\n };\n}\n\nexport function parseDiagnosticsStackTrace(stacktrace: string): ParsedErrorStackTrace {\n const lines = stacktrace\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(Boolean);\n const frames: ErrorStackFrame[] = [];\n const unparsed: string[] = [];\n let headline: string | undefined;\n\n for (const line of lines) {\n const frame = parseStackTraceFrame(line);\n if (frame) {\n frames.push(frame);\n continue;\n }\n if (!headline && !line.startsWith(\"--- at \")) {\n headline = line;\n continue;\n }\n unparsed.push(line);\n }\n\n return {\n frames,\n unparsed,\n raw: stacktrace,\n ...(headline !== undefined ? { headline } : {}),\n };\n}\n\nexport function parseInlineJsonContextValue(value: string): unknown | null {\n const trimmed = value.trim();\n if (!trimmed || !/^[{[]/.test(trimmed)) return null;\n try {\n return JSON.parse(trimmed);\n } catch {\n return null;\n }\n}\n\nexport function compactStackPath(file: string) {\n return file\n .replace(/^github\\.com\\/flanksource\\/incident-commander\\//, \"\")\n .replace(/^github\\.com\\/flanksource\\//, \"flanksource/\")\n .replace(/^.*\\/go\\/pkg\\/mod\\//, \"pkg/mod/\")\n .replace(/^.*\\/incident-commander\\//, \"\");\n}\n\nexport function isApplicationStackFrame(file: string) {\n return (\n file.includes(\"github.com/flanksource/incident-commander/\") ||\n file.includes(\"/incident-commander/\")\n );\n}\n\nfunction parseStackTraceFrame(line: string): ErrorStackFrame | null {\n const match = line.match(/^--- at (.+):(\\d+)(?:\\s+(.+))?$/);\n if (!match) return null;\n return {\n raw: line,\n file: match[1] ?? \"\",\n line: Number(match[2] ?? 0),\n ...(match[3]?.trim() ? { functionName: match[3]!.trim() } : {}),\n };\n}\n\nfunction objectRecord(value: unknown): Record<string, unknown> | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n return value as Record<string, unknown>;\n}\n\nfunction firstString(record: Record<string, unknown>, keys: string[]): string | undefined {\n for (const key of keys) {\n const value = record[key];\n if (typeof value === \"string\" && value.trim()) return value;\n }\n return undefined;\n}\n\nfunction contextEntries(value: unknown): Array<[string, string]> {\n const record = objectRecord(value);\n if (!record) return [];\n return Object.entries(record)\n .filter(\n ([, entryValue]) => entryValue !== undefined && entryValue !== null && entryValue !== \"\",\n )\n .map(([key, entryValue]) => [key, stringifyValue(entryValue)]);\n}\n\nfunction stringifyValue(value: unknown): string {\n if (value === null || value === undefined || value === \"\") return \"-\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n return JSON.stringify(value);\n}\n"],"names":[],"mappings":"AA2BO,SAAS,0BACd,OACA,UACyB;AACzB,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,MAAM,SAAS,EAAE,SAAS,OAAO,SAAS,CAAA,EAAC,IAAM;AAAA,EAC1D;AACA,QAAM,SAAS,aAAa,KAAK;AACjC,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,SAAS,aAAa,OAAO,KAAK,KAAK,aAAa,OAAO,WAAW;AAC5E,MAAI,UAAU,WAAW,QAAQ;AAC/B,WAAO,0BAA0B,QAAQ,QAAQ;AAAA,EACnD;AACA,QAAM,UACJ,YAAY,QAAQ,CAAC,SAAS,WAAW,OAAO,UAAU,UAAU,SAAS,CAAC,KAAK;AACrF,QAAM,QAAQ,YAAY,QAAQ,CAAC,SAAS,YAAY,WAAW,SAAS,CAAC;AAC7E,QAAM,aAAa,YAAY,QAAQ,CAAC,cAAc,eAAe,cAAc,OAAO,CAAC;AAC3F,QAAM,OAAO,YAAY,QAAQ,CAAC,QAAQ,aAAa,YAAY,CAAC;AACpE,QAAM,UAAU,eAAe,OAAO,OAAO;AAC7C,MAAI,CAAC,WAAW,CAAC,SAAS,CAAC,cAAc,QAAQ,WAAW,EAAG,QAAO;AACtE,SAAO;AAAA,IACL,SAAS,WAAW;AAAA,IACpB;AAAA,IACA,KAAK;AAAA,IACL,GAAI,UAAU,SAAY,EAAE,MAAA,IAAU,CAAA;AAAA,IACtC,GAAI,SAAS,SAAY,EAAE,KAAA,IAAS,CAAA;AAAA,IACpC,GAAI,eAAe,SAAY,EAAE,eAAe,CAAA;AAAA,EAAC;AAErD;AAEO,SAAS,2BAA2B,YAA2C;AACpF,QAAM,QAAQ,WACX,MAAM,OAAO,EACb,IAAI,CAAC,SAAS,KAAK,KAAA,CAAM,EACzB,OAAO,OAAO;AACjB,QAAM,SAA4B,CAAA;AAClC,QAAM,WAAqB,CAAA;AAC3B,MAAI;AAEJ,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,qBAAqB,IAAI;AACvC,QAAI,OAAO;AACT,aAAO,KAAK,KAAK;AACjB;AAAA,IACF;AACA,QAAI,CAAC,YAAY,CAAC,KAAK,WAAW,SAAS,GAAG;AAC5C,iBAAW;AACX;AAAA,IACF;AACA,aAAS,KAAK,IAAI;AAAA,EACpB;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,KAAK;AAAA,IACL,GAAI,aAAa,SAAY,EAAE,aAAa,CAAA;AAAA,EAAC;AAEjD;AAEO,SAAS,4BAA4B,OAA+B;AACzE,QAAM,UAAU,MAAM,KAAA;AACtB,MAAI,CAAC,WAAW,CAAC,QAAQ,KAAK,OAAO,EAAG,QAAO;AAC/C,MAAI;AACF,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,iBAAiB,MAAc;AAC7C,SAAO,KACJ,QAAQ,mDAAmD,EAAE,EAC7D,QAAQ,+BAA+B,cAAc,EACrD,QAAQ,uBAAuB,UAAU,EACzC,QAAQ,6BAA6B,EAAE;AAC5C;AAEO,SAAS,wBAAwB,MAAc;AACpD,SACE,KAAK,SAAS,4CAA4C,KAC1D,KAAK,SAAS,sBAAsB;AAExC;AAEA,SAAS,qBAAqB,MAAsC;AAtF7D;AAuFL,QAAM,QAAQ,KAAK,MAAM,iCAAiC;AAC1D,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO;AAAA,IACL,KAAK;AAAA,IACL,MAAM,MAAM,CAAC,KAAK;AAAA,IAClB,MAAM,OAAO,MAAM,CAAC,KAAK,CAAC;AAAA,IAC1B,KAAI,WAAM,CAAC,MAAP,mBAAU,UAAS,EAAE,cAAc,MAAM,CAAC,EAAG,KAAA,MAAW,CAAA;AAAA,EAAC;AAEjE;AAEA,SAAS,aAAa,OAAgD;AACpE,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,EAAG,QAAO;AACxE,SAAO;AACT;AAEA,SAAS,YAAY,QAAiC,MAAoC;AACxF,aAAW,OAAO,MAAM;AACtB,UAAM,QAAQ,OAAO,GAAG;AACxB,QAAI,OAAO,UAAU,YAAY,MAAM,KAAA,EAAQ,QAAO;AAAA,EACxD;AACA,SAAO;AACT;AAEA,SAAS,eAAe,OAAyC;AAC/D,QAAM,SAAS,aAAa,KAAK;AACjC,MAAI,CAAC,OAAQ,QAAO,CAAA;AACpB,SAAO,OAAO,QAAQ,MAAM,EACzB;AAAA,IACC,CAAC,CAAA,EAAG,UAAU,MAAM,eAAe,UAAa,eAAe,QAAQ,eAAe;AAAA,EAAA,EAEvF,IAAI,CAAC,CAAC,KAAK,UAAU,MAAM,CAAC,KAAK,eAAe,UAAU,CAAC,CAAC;AACjE;AAEA,SAAS,eAAe,OAAwB;AAC9C,MAAI,UAAU,QAAQ,UAAU,UAAa,UAAU,GAAI,QAAO;AAClE,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAW,QAAO,OAAO,KAAK;AAChF,SAAO,KAAK,UAAU,KAAK;AAC7B;"}
1
+ {"version":3,"file":"error-diagnostics.js","sources":["../../../src/data/diagnostics/error-diagnostics.ts"],"sourcesContent":["// Normalize ad-hoc error payloads (oops JSON, plain strings, nested objects)\n// into the shape ErrorDetails consumes. Mirrors what `samber/oops` emits\n// from `OopsError.MarshalJSON()` on the Go side.\n\nexport type ErrorDiagnostics = {\n message: string;\n trace?: string;\n time?: string;\n stacktrace?: string;\n context: Array<[string, string]>;\n raw?: unknown;\n};\n\nexport type ParsedErrorStackTrace = {\n headline?: string;\n frames: ErrorStackFrame[];\n unparsed: string[];\n raw: string;\n};\n\nexport type ErrorStackFrame = {\n raw: string;\n file: string;\n line: number;\n functionName?: string;\n};\n\nexport function normalizeErrorDiagnostics(\n value: unknown,\n fallback?: string | null,\n): ErrorDiagnostics | null {\n if (!value) return null;\n if (typeof value === \"string\") {\n return value.trim() ? { message: value, context: [] } : null;\n }\n const record = objectRecord(value);\n if (!record) return null;\n const nested = objectRecord(record.error) ?? objectRecord(record.diagnostics);\n if (nested && nested !== record) {\n return normalizeErrorDiagnostics(nested, fallback);\n }\n const message =\n firstString(record, [\"error\", \"message\", \"msg\", \"reason\", \"detail\", \"details\"]) ?? fallback;\n const trace = firstString(record, [\"trace\", \"trace_id\", \"traceId\", \"traceID\"]);\n const stacktrace = firstString(record, [\"stacktrace\", \"stack_trace\", \"stackTrace\", \"stack\"]);\n const time = firstString(record, [\"time\", \"timestamp\", \"created_at\"]);\n const context = contextEntries(record.context);\n if (!message && !trace && !stacktrace && context.length === 0) return null;\n return {\n message: message ?? \"Action failed\",\n context,\n raw: value,\n ...(trace !== undefined ? { trace } : {}),\n ...(time !== undefined ? { time } : {}),\n ...(stacktrace !== undefined ? { stacktrace } : {}),\n };\n}\n\nexport function parseDiagnosticsStackTrace(stacktrace: string): ParsedErrorStackTrace {\n const lines = stacktrace\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(Boolean);\n const frames: ErrorStackFrame[] = [];\n const unparsed: string[] = [];\n let headline: string | undefined;\n\n for (const line of lines) {\n const frame = parseStackTraceFrame(line);\n if (frame) {\n frames.push(frame);\n continue;\n }\n if (!headline && !line.startsWith(\"--- at \")) {\n headline = line;\n continue;\n }\n unparsed.push(line);\n }\n\n return {\n frames,\n unparsed,\n raw: stacktrace,\n ...(headline !== undefined ? { headline } : {}),\n };\n}\n\nexport function parseInlineJsonContextValue(value: string): unknown | null {\n const trimmed = value.trim();\n if (!trimmed || !/^[{[]/.test(trimmed)) return null;\n try {\n return JSON.parse(trimmed);\n } catch {\n return null;\n }\n}\n\nexport function compactStackPath(file: string) {\n return file\n .replace(/^github\\.com\\/flanksource\\/incident-commander\\//, \"\")\n .replace(/^github\\.com\\/flanksource\\//, \"flanksource/\")\n .replace(/^.*\\/go\\/pkg\\/mod\\//, \"pkg/mod/\")\n .replace(/^.*\\/incident-commander\\//, \"\");\n}\n\nexport function isApplicationStackFrame(file: string) {\n return (\n file.includes(\"github.com/flanksource/incident-commander/\") ||\n file.includes(\"/incident-commander/\")\n );\n}\n\nfunction parseStackTraceFrame(line: string): ErrorStackFrame | null {\n const prefix = \"--- at \";\n if (!line.startsWith(prefix)) return null;\n\n const value = line.slice(prefix.length);\n let fileEnd = -1;\n let lineStart = -1;\n let lineEnd = -1;\n let functionStart = -1;\n\n for (let index = 0; index < value.length; index++) {\n if (value[index] !== \":\" || !isDecimalDigit(value[index + 1])) continue;\n\n let end = index + 1;\n while (isDecimalDigit(value[end])) end++;\n if (end === value.length) {\n fileEnd = index;\n lineStart = index + 1;\n lineEnd = end;\n functionStart = -1;\n continue;\n }\n if (!isWhitespace(value[end])) continue;\n\n let start = end;\n while (isWhitespace(value[start])) start++;\n if (start === value.length && start - end < 2) continue;\n fileEnd = index;\n lineStart = index + 1;\n lineEnd = end;\n functionStart = start;\n }\n\n if (fileEnd <= 0 || lineStart < 0 || lineEnd < 0) return null;\n const functionName = functionStart >= 0 ? value.slice(functionStart).trim() : \"\";\n return {\n raw: line,\n file: value.slice(0, fileEnd),\n line: Number(value.slice(lineStart, lineEnd)),\n ...(functionName ? { functionName } : {}),\n };\n}\n\nfunction isDecimalDigit(value: string | undefined): boolean {\n return value !== undefined && value >= \"0\" && value <= \"9\";\n}\n\nfunction isWhitespace(value: string | undefined): boolean {\n return value !== undefined && value.trim() === \"\";\n}\n\nfunction objectRecord(value: unknown): Record<string, unknown> | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n return value as Record<string, unknown>;\n}\n\nfunction firstString(record: Record<string, unknown>, keys: string[]): string | undefined {\n for (const key of keys) {\n const value = record[key];\n if (typeof value === \"string\" && value.trim()) return value;\n }\n return undefined;\n}\n\nfunction contextEntries(value: unknown): Array<[string, string]> {\n const record = objectRecord(value);\n if (!record) return [];\n return Object.entries(record)\n .filter(\n ([, entryValue]) => entryValue !== undefined && entryValue !== null && entryValue !== \"\",\n )\n .map(([key, entryValue]) => [key, stringifyValue(entryValue)]);\n}\n\nfunction stringifyValue(value: unknown): string {\n if (value === null || value === undefined || value === \"\") return \"-\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n return JSON.stringify(value);\n}\n"],"names":[],"mappings":"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"}
@@ -125,9 +125,41 @@ function parseThreadBlock(block) {
125
125
  };
126
126
  }
127
127
  function extractHeaderStateTrail(rest) {
128
- var _a, _b;
129
- const tail = rest.match(/nid=0x[0-9a-f]+\s+(?<desc>[^[]+?)(?:\s+\[0x[0-9a-f]+\])?\s*$/i);
130
- return (_b = (_a = tail == null ? void 0 : tail.groups) == null ? void 0 : _a.desc) == null ? void 0 : _b.trim();
128
+ const lower = rest.toLowerCase();
129
+ const marker = "nid=0x";
130
+ const markerStart = lower.indexOf(marker);
131
+ if (markerStart === -1) return void 0;
132
+ let stateStart = markerStart + marker.length;
133
+ const hexStart = stateStart;
134
+ while (isHexDigit(rest[stateStart])) stateStart++;
135
+ if (stateStart === hexStart || !isWhitespace(rest[stateStart])) return void 0;
136
+ while (isWhitespace(rest[stateStart])) stateStart++;
137
+ let stateEnd = rest.length;
138
+ while (stateEnd > stateStart && isWhitespace(rest[stateEnd - 1])) stateEnd--;
139
+ if (rest[stateEnd - 1] === "]") {
140
+ const addressStart = lower.lastIndexOf("[0x", stateEnd - 1);
141
+ if (addressStart > stateStart && isHexSequence(rest, addressStart + 3, stateEnd - 1) && isWhitespace(rest[addressStart - 1])) {
142
+ stateEnd = addressStart;
143
+ while (stateEnd > stateStart && isWhitespace(rest[stateEnd - 1])) stateEnd--;
144
+ }
145
+ }
146
+ const state = rest.slice(stateStart, stateEnd);
147
+ return state || void 0;
148
+ }
149
+ function isHexDigit(value) {
150
+ if (value === void 0) return false;
151
+ const code = value.toLowerCase().charCodeAt(0);
152
+ return code >= 48 && code <= 57 || code >= 97 && code <= 102;
153
+ }
154
+ function isHexSequence(value, start, end) {
155
+ if (start >= end) return false;
156
+ for (let index = start; index < end; index++) {
157
+ if (!isHexDigit(value[index])) return false;
158
+ }
159
+ return true;
160
+ }
161
+ function isWhitespace(value) {
162
+ return value !== void 0 && value.trim() === "";
131
163
  }
132
164
  function deriveSyntheticId(name, rest) {
133
165
  const tid = /\btid=(0x[0-9a-f]+)/i.exec(rest);
@@ -1 +1 @@
1
- {"version":3,"file":"jvm-stacktrace.cjs","sources":["../../../src/data/diagnostics/jvm-stacktrace.ts"],"sourcesContent":["export interface ParsedThreadFrame {\n functionName: string;\n displayName: string;\n file?: string;\n line?: number;\n location?: string;\n kind: \"frame\" | \"locked\" | \"waiting_on\" | \"waiting_to_lock\" | \"parking\";\n runtime: boolean;\n nativeMethod: boolean;\n annotationText?: string;\n // Optional fully-qualified class name (e.g. \"com.example.admin.pas.Foo\").\n // Lets renderers filter or group by package without re-splitting\n // functionName. Populated by parseJavaStackTrace; left undefined by the\n // thread-dump parser since its frames are raw \"fn(src)\" pairs.\n class?: string;\n method?: string;\n // Optional source-context window populated by clicky.SourceResolver\n // (or its TS equivalent). sourceLines[line - sourceStartLine] is the focal\n // line. Empty/undefined when no resolver was attached.\n sourceLines?: string[];\n sourceLineNumbers?: number[];\n sourceStartLine?: number;\n sourceLanguage?: string;\n}\n\nexport interface ParsedThread {\n id: number;\n nid?: string;\n name: string;\n state: string;\n rawState: string;\n priority?: number;\n daemon?: boolean;\n frames: ParsedThreadFrame[];\n raw: string;\n userFrameCount: number;\n topFunction?: string;\n searchText: string;\n}\n\nconst headerRe = /^\"(?<name>[^\"]*)\"(?<rest>.*)$/;\nconst stateRe = /^\\s*java\\.lang\\.Thread\\.State:\\s+(?<state>[A-Z_]+)(?:\\s+\\((?<sub>[^)]+)\\))?/;\nconst frameRe = /^\\s*at\\s+(?<fn>[^\\s(]+)\\((?<src>[^)]+)\\)\\s*$/;\nconst srcLineRe = /^(?<file>[^:]+):(?<line>\\d+)$/;\nconst annotationRe =\n /^\\s*-\\s+(?<kind>locked|waiting on|waiting to lock|parking to wait for)\\b(?<rest>.*)$/;\n\nexport function parseJvmThreadDump(text: string): ParsedThread[] {\n const trimmed = text.trim();\n if (!trimmed) return [];\n\n // Split on blank lines OR on a new `\"...\"` header that follows immediately.\n const blocks = splitIntoThreadBlocks(trimmed);\n const threads: ParsedThread[] = [];\n\n for (const block of blocks) {\n const parsed = parseThreadBlock(block);\n if (parsed) threads.push(parsed);\n }\n return threads;\n}\n\nfunction splitIntoThreadBlocks(text: string): string[] {\n const out: string[] = [];\n let current: string[] = [];\n const lines = text.split(\"\\n\");\n for (const raw of lines) {\n const line = raw.replace(/\\r$/, \"\");\n if (line.startsWith('\"') && current.length > 0) {\n out.push(current.join(\"\\n\"));\n current = [line];\n } else {\n current.push(line);\n }\n }\n if (current.length > 0) out.push(current.join(\"\\n\"));\n return out;\n}\n\nfunction parseThreadBlock(block: string): ParsedThread | null {\n const lines = block.split(\"\\n\");\n const header = lines[0]?.trim() ?? \"\";\n const headerMatch = headerRe.exec(header);\n if (!headerMatch?.groups) return null;\n\n const name = headerMatch.groups.name;\n if (!name) return null;\n const rest = headerMatch.groups.rest ?? \"\";\n const idMatch = /#(\\d+)\\b/.exec(rest);\n const prioMatch = /\\bprio=(\\d+)/.exec(rest);\n const nidMatch = /\\bnid=(0x[0-9a-f]+)/i.exec(rest);\n const daemon = /\\bdaemon\\b/.test(rest);\n const headerStateTrail = extractHeaderStateTrail(rest);\n\n let rawState = headerStateTrail ?? \"\";\n let state = normalizeJvmState(rawState);\n const frames: ParsedThreadFrame[] = [];\n\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i];\n if (line == null) continue;\n if (!line.trim()) continue;\n\n const stateMatch = stateRe.exec(line);\n if (stateMatch?.groups) {\n const primary = stateMatch.groups.state;\n if (!primary) continue;\n const sub = stateMatch.groups.sub;\n rawState = sub ? `${primary} (${sub})` : primary;\n state = normalizeJvmState(primary);\n continue;\n }\n\n const frameMatch = frameRe.exec(line);\n if (frameMatch?.groups) {\n const functionName = frameMatch.groups.fn;\n const src = frameMatch.groups.src;\n if (!functionName || !src) continue;\n const frame: ParsedThreadFrame = {\n functionName,\n displayName: sanitizeJvmFunctionName(functionName),\n kind: \"frame\",\n runtime: isJvmRuntimeFrame(functionName),\n nativeMethod: src === \"Native Method\",\n ...splitClassMethod(functionName),\n };\n const srcMatch = srcLineRe.exec(src);\n if (srcMatch?.groups?.file && srcMatch.groups.line) {\n frame.file = srcMatch.groups.file;\n frame.line = Number(srcMatch.groups.line);\n frame.location = `${frame.file}:${frame.line}`;\n } else if (src === \"Native Method\") {\n frame.location = \"Native Method\";\n } else {\n frame.location = src;\n }\n frames.push(frame);\n continue;\n }\n\n const annoMatch = annotationRe.exec(line);\n if (annoMatch?.groups?.kind) {\n const annotationKind = annoMatch.groups.kind;\n const kind = mapAnnotationKind(annotationKind);\n frames.push({\n functionName: annotationKind,\n displayName: annotationKind,\n kind,\n runtime: false,\n nativeMethod: false,\n annotationText: (annoMatch.groups.rest ?? \"\").trim(),\n });\n continue;\n }\n }\n\n const userFrameCount = frames.filter((f) => f.kind === \"frame\" && !f.runtime).length;\n const topFunction = frames.find((f) => f.kind === \"frame\")?.functionName;\n const searchText = [\n header,\n ...frames.map((f) => `${f.functionName} ${f.location ?? \"\"} ${f.annotationText ?? \"\"}`),\n ]\n .join(\"\\n\")\n .toLowerCase();\n\n return {\n id: idMatch ? Number(idMatch[1]) : deriveSyntheticId(name, rest),\n name,\n state: state || \"unknown\",\n rawState: rawState || \"\",\n daemon,\n frames,\n raw: block,\n userFrameCount,\n searchText,\n ...(nidMatch?.[1] !== undefined ? { nid: nidMatch[1] } : {}),\n ...(prioMatch?.[1] !== undefined ? { priority: Number(prioMatch[1]) } : {}),\n ...(topFunction !== undefined ? { topFunction } : {}),\n };\n}\n\nfunction extractHeaderStateTrail(rest: string): string | undefined {\n // Example header tails: \"... nid=0x1903 waiting on condition [0x...]\"\n // Capture the descriptor between nid=... and the trailing [address].\n const tail = rest.match(/nid=0x[0-9a-f]+\\s+(?<desc>[^[]+?)(?:\\s+\\[0x[0-9a-f]+\\])?\\s*$/i);\n return tail?.groups?.desc?.trim();\n}\n\nfunction deriveSyntheticId(name: string, rest: string): number {\n const tid = /\\btid=(0x[0-9a-f]+)/i.exec(rest);\n if (tid?.[1]) {\n // stable non-negative int derived from tid hex suffix\n const hex = tid[1].slice(2);\n const n = Number.parseInt(hex.slice(-8), 16);\n if (Number.isFinite(n)) return n;\n }\n // Fallback: hash of name\n let h = 0;\n for (let i = 0; i < name.length; i++) h = (h * 31 + name.charCodeAt(i)) | 0;\n return Math.abs(h);\n}\n\nfunction mapAnnotationKind(kind: string): ParsedThreadFrame[\"kind\"] {\n switch (kind) {\n case \"locked\":\n return \"locked\";\n case \"waiting on\":\n return \"waiting_on\";\n case \"waiting to lock\":\n return \"waiting_to_lock\";\n case \"parking to wait for\":\n return \"parking\";\n default:\n return \"frame\";\n }\n}\n\nexport function countThreadsByState(threads: ParsedThread[]): Map<string, number> {\n const counts = new Map<string, number>();\n for (const t of threads) counts.set(t.state, (counts.get(t.state) ?? 0) + 1);\n return counts;\n}\n\nfunction normalizeJvmState(value: string): string {\n if (!value) return \"\";\n const upper = value.trim().toUpperCase();\n if (upper.startsWith(\"RUNNABLE\")) return \"runnable\";\n if (upper.startsWith(\"TIMED_WAITING\")) return \"timed_waiting\";\n if (upper.startsWith(\"WAITING\")) return \"waiting\";\n if (upper.startsWith(\"BLOCKED\")) return \"blocked\";\n if (upper.startsWith(\"NEW\")) return \"new\";\n if (upper.startsWith(\"TERMINATED\")) return \"terminated\";\n // Header fragments like \"waiting on condition\", \"runnable\", \"sleeping\"\n const lower = value.trim().toLowerCase();\n if (lower.includes(\"runnable\")) return \"runnable\";\n if (lower.includes(\"waiting on condition\") || lower.includes(\"sleeping\")) return \"timed_waiting\";\n if (lower.includes(\"waiting\")) return \"waiting\";\n if (lower.includes(\"blocked\")) return \"blocked\";\n return lower.split(/\\s+/)[0] ?? \"\";\n}\n\nconst runtimePrefixes = [\"java.\", \"javax.\", \"sun.\", \"jdk.\", \"com.sun.\", \"or\" + \"acle.jrockit.\"];\nfunction isJvmRuntimeFrame(functionName: string): boolean {\n return runtimePrefixes.some((p) => functionName.startsWith(p));\n}\n\n// splitClassMethod separates a JVM frame's `fully.qualified.Class.method` into\n// its class and method. The method is the last dot segment; everything before\n// is the (possibly inner) class. Returns no fields when the name has no dot, so\n// frames like a bare `<init>` are left without a class rather than guessed.\nfunction splitClassMethod(functionName: string): { class?: string; method?: string } {\n const lastDot = functionName.lastIndexOf(\".\");\n if (lastDot <= 0) return {};\n return {\n class: functionName.slice(0, lastDot),\n method: functionName.slice(lastDot + 1),\n };\n}\n\nfunction sanitizeJvmFunctionName(functionName: string): string {\n // e.g. \"com.example.App$Inner.method\" → \"App$Inner.method\"\n const parts = functionName.split(\".\");\n if (parts.length < 2) return functionName;\n const method = parts[parts.length - 1];\n const cls = parts[parts.length - 2];\n return `${cls}.${method}`;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"jvm-stacktrace.cjs","sources":["../../../src/data/diagnostics/jvm-stacktrace.ts"],"sourcesContent":["export interface ParsedThreadFrame {\n functionName: string;\n displayName: string;\n file?: string;\n line?: number;\n location?: string;\n kind: \"frame\" | \"locked\" | \"waiting_on\" | \"waiting_to_lock\" | \"parking\";\n runtime: boolean;\n nativeMethod: boolean;\n annotationText?: string;\n // Optional fully-qualified class name (e.g. \"com.example.admin.pas.Foo\").\n // Lets renderers filter or group by package without re-splitting\n // functionName. Populated by parseJavaStackTrace; left undefined by the\n // thread-dump parser since its frames are raw \"fn(src)\" pairs.\n class?: string;\n method?: string;\n // Optional source-context window populated by clicky.SourceResolver\n // (or its TS equivalent). sourceLines[line - sourceStartLine] is the focal\n // line. Empty/undefined when no resolver was attached.\n sourceLines?: string[];\n sourceLineNumbers?: number[];\n sourceStartLine?: number;\n sourceLanguage?: string;\n}\n\nexport interface ParsedThread {\n id: number;\n nid?: string;\n name: string;\n state: string;\n rawState: string;\n priority?: number;\n daemon?: boolean;\n frames: ParsedThreadFrame[];\n raw: string;\n userFrameCount: number;\n topFunction?: string;\n searchText: string;\n}\n\nconst headerRe = /^\"(?<name>[^\"]*)\"(?<rest>.*)$/;\nconst stateRe = /^\\s*java\\.lang\\.Thread\\.State:\\s+(?<state>[A-Z_]+)(?:\\s+\\((?<sub>[^)]+)\\))?/;\nconst frameRe = /^\\s*at\\s+(?<fn>[^\\s(]+)\\((?<src>[^)]+)\\)\\s*$/;\nconst srcLineRe = /^(?<file>[^:]+):(?<line>\\d+)$/;\nconst annotationRe =\n /^\\s*-\\s+(?<kind>locked|waiting on|waiting to lock|parking to wait for)\\b(?<rest>.*)$/;\n\nexport function parseJvmThreadDump(text: string): ParsedThread[] {\n const trimmed = text.trim();\n if (!trimmed) return [];\n\n // Split on blank lines OR on a new `\"...\"` header that follows immediately.\n const blocks = splitIntoThreadBlocks(trimmed);\n const threads: ParsedThread[] = [];\n\n for (const block of blocks) {\n const parsed = parseThreadBlock(block);\n if (parsed) threads.push(parsed);\n }\n return threads;\n}\n\nfunction splitIntoThreadBlocks(text: string): string[] {\n const out: string[] = [];\n let current: string[] = [];\n const lines = text.split(\"\\n\");\n for (const raw of lines) {\n const line = raw.replace(/\\r$/, \"\");\n if (line.startsWith('\"') && current.length > 0) {\n out.push(current.join(\"\\n\"));\n current = [line];\n } else {\n current.push(line);\n }\n }\n if (current.length > 0) out.push(current.join(\"\\n\"));\n return out;\n}\n\nfunction parseThreadBlock(block: string): ParsedThread | null {\n const lines = block.split(\"\\n\");\n const header = lines[0]?.trim() ?? \"\";\n const headerMatch = headerRe.exec(header);\n if (!headerMatch?.groups) return null;\n\n const name = headerMatch.groups.name;\n if (!name) return null;\n const rest = headerMatch.groups.rest ?? \"\";\n const idMatch = /#(\\d+)\\b/.exec(rest);\n const prioMatch = /\\bprio=(\\d+)/.exec(rest);\n const nidMatch = /\\bnid=(0x[0-9a-f]+)/i.exec(rest);\n const daemon = /\\bdaemon\\b/.test(rest);\n const headerStateTrail = extractHeaderStateTrail(rest);\n\n let rawState = headerStateTrail ?? \"\";\n let state = normalizeJvmState(rawState);\n const frames: ParsedThreadFrame[] = [];\n\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i];\n if (line == null) continue;\n if (!line.trim()) continue;\n\n const stateMatch = stateRe.exec(line);\n if (stateMatch?.groups) {\n const primary = stateMatch.groups.state;\n if (!primary) continue;\n const sub = stateMatch.groups.sub;\n rawState = sub ? `${primary} (${sub})` : primary;\n state = normalizeJvmState(primary);\n continue;\n }\n\n const frameMatch = frameRe.exec(line);\n if (frameMatch?.groups) {\n const functionName = frameMatch.groups.fn;\n const src = frameMatch.groups.src;\n if (!functionName || !src) continue;\n const frame: ParsedThreadFrame = {\n functionName,\n displayName: sanitizeJvmFunctionName(functionName),\n kind: \"frame\",\n runtime: isJvmRuntimeFrame(functionName),\n nativeMethod: src === \"Native Method\",\n ...splitClassMethod(functionName),\n };\n const srcMatch = srcLineRe.exec(src);\n if (srcMatch?.groups?.file && srcMatch.groups.line) {\n frame.file = srcMatch.groups.file;\n frame.line = Number(srcMatch.groups.line);\n frame.location = `${frame.file}:${frame.line}`;\n } else if (src === \"Native Method\") {\n frame.location = \"Native Method\";\n } else {\n frame.location = src;\n }\n frames.push(frame);\n continue;\n }\n\n const annoMatch = annotationRe.exec(line);\n if (annoMatch?.groups?.kind) {\n const annotationKind = annoMatch.groups.kind;\n const kind = mapAnnotationKind(annotationKind);\n frames.push({\n functionName: annotationKind,\n displayName: annotationKind,\n kind,\n runtime: false,\n nativeMethod: false,\n annotationText: (annoMatch.groups.rest ?? \"\").trim(),\n });\n continue;\n }\n }\n\n const userFrameCount = frames.filter((f) => f.kind === \"frame\" && !f.runtime).length;\n const topFunction = frames.find((f) => f.kind === \"frame\")?.functionName;\n const searchText = [\n header,\n ...frames.map((f) => `${f.functionName} ${f.location ?? \"\"} ${f.annotationText ?? \"\"}`),\n ]\n .join(\"\\n\")\n .toLowerCase();\n\n return {\n id: idMatch ? Number(idMatch[1]) : deriveSyntheticId(name, rest),\n name,\n state: state || \"unknown\",\n rawState: rawState || \"\",\n daemon,\n frames,\n raw: block,\n userFrameCount,\n searchText,\n ...(nidMatch?.[1] !== undefined ? { nid: nidMatch[1] } : {}),\n ...(prioMatch?.[1] !== undefined ? { priority: Number(prioMatch[1]) } : {}),\n ...(topFunction !== undefined ? { topFunction } : {}),\n };\n}\n\nfunction extractHeaderStateTrail(rest: string): string | undefined {\n const lower = rest.toLowerCase();\n const marker = \"nid=0x\";\n const markerStart = lower.indexOf(marker);\n if (markerStart === -1) return undefined;\n\n let stateStart = markerStart + marker.length;\n const hexStart = stateStart;\n while (isHexDigit(rest[stateStart])) stateStart++;\n if (stateStart === hexStart || !isWhitespace(rest[stateStart])) return undefined;\n while (isWhitespace(rest[stateStart])) stateStart++;\n\n let stateEnd = rest.length;\n while (stateEnd > stateStart && isWhitespace(rest[stateEnd - 1])) stateEnd--;\n if (rest[stateEnd - 1] === \"]\") {\n const addressStart = lower.lastIndexOf(\"[0x\", stateEnd - 1);\n if (\n addressStart > stateStart &&\n isHexSequence(rest, addressStart + 3, stateEnd - 1) &&\n isWhitespace(rest[addressStart - 1])\n ) {\n stateEnd = addressStart;\n while (stateEnd > stateStart && isWhitespace(rest[stateEnd - 1])) stateEnd--;\n }\n }\n\n const state = rest.slice(stateStart, stateEnd);\n return state || undefined;\n}\n\nfunction isHexDigit(value: string | undefined): boolean {\n if (value === undefined) return false;\n const code = value.toLowerCase().charCodeAt(0);\n return (code >= 48 && code <= 57) || (code >= 97 && code <= 102);\n}\n\nfunction isHexSequence(value: string, start: number, end: number): boolean {\n if (start >= end) return false;\n for (let index = start; index < end; index++) {\n if (!isHexDigit(value[index])) return false;\n }\n return true;\n}\n\nfunction isWhitespace(value: string | undefined): boolean {\n return value !== undefined && value.trim() === \"\";\n}\n\nfunction deriveSyntheticId(name: string, rest: string): number {\n const tid = /\\btid=(0x[0-9a-f]+)/i.exec(rest);\n if (tid?.[1]) {\n // stable non-negative int derived from tid hex suffix\n const hex = tid[1].slice(2);\n const n = Number.parseInt(hex.slice(-8), 16);\n if (Number.isFinite(n)) return n;\n }\n // Fallback: hash of name\n let h = 0;\n for (let i = 0; i < name.length; i++) h = (h * 31 + name.charCodeAt(i)) | 0;\n return Math.abs(h);\n}\n\nfunction mapAnnotationKind(kind: string): ParsedThreadFrame[\"kind\"] {\n switch (kind) {\n case \"locked\":\n return \"locked\";\n case \"waiting on\":\n return \"waiting_on\";\n case \"waiting to lock\":\n return \"waiting_to_lock\";\n case \"parking to wait for\":\n return \"parking\";\n default:\n return \"frame\";\n }\n}\n\nexport function countThreadsByState(threads: ParsedThread[]): Map<string, number> {\n const counts = new Map<string, number>();\n for (const t of threads) counts.set(t.state, (counts.get(t.state) ?? 0) + 1);\n return counts;\n}\n\nfunction normalizeJvmState(value: string): string {\n if (!value) return \"\";\n const upper = value.trim().toUpperCase();\n if (upper.startsWith(\"RUNNABLE\")) return \"runnable\";\n if (upper.startsWith(\"TIMED_WAITING\")) return \"timed_waiting\";\n if (upper.startsWith(\"WAITING\")) return \"waiting\";\n if (upper.startsWith(\"BLOCKED\")) return \"blocked\";\n if (upper.startsWith(\"NEW\")) return \"new\";\n if (upper.startsWith(\"TERMINATED\")) return \"terminated\";\n // Header fragments like \"waiting on condition\", \"runnable\", \"sleeping\"\n const lower = value.trim().toLowerCase();\n if (lower.includes(\"runnable\")) return \"runnable\";\n if (lower.includes(\"waiting on condition\") || lower.includes(\"sleeping\")) return \"timed_waiting\";\n if (lower.includes(\"waiting\")) return \"waiting\";\n if (lower.includes(\"blocked\")) return \"blocked\";\n return lower.split(/\\s+/)[0] ?? \"\";\n}\n\nconst runtimePrefixes = [\"java.\", \"javax.\", \"sun.\", \"jdk.\", \"com.sun.\", \"or\" + \"acle.jrockit.\"];\nfunction isJvmRuntimeFrame(functionName: string): boolean {\n return runtimePrefixes.some((p) => functionName.startsWith(p));\n}\n\n// splitClassMethod separates a JVM frame's `fully.qualified.Class.method` into\n// its class and method. The method is the last dot segment; everything before\n// is the (possibly inner) class. Returns no fields when the name has no dot, so\n// frames like a bare `<init>` are left without a class rather than guessed.\nfunction splitClassMethod(functionName: string): { class?: string; method?: string } {\n const lastDot = functionName.lastIndexOf(\".\");\n if (lastDot <= 0) return {};\n return {\n class: functionName.slice(0, lastDot),\n method: functionName.slice(lastDot + 1),\n };\n}\n\nfunction sanitizeJvmFunctionName(functionName: string): string {\n // e.g. \"com.example.App$Inner.method\" → \"App$Inner.method\"\n const parts = functionName.split(\".\");\n if (parts.length < 2) return functionName;\n const method = parts[parts.length - 1];\n const cls = parts[parts.length - 2];\n return `${cls}.${method}`;\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"jvm-stacktrace.d.ts","sourceRoot":"","sources":["../../../src/data/diagnostics/jvm-stacktrace.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,YAAY,GAAG,iBAAiB,GAAG,SAAS,CAAC;IACxE,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IAKxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAIhB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AASD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,EAAE,CAa/D;AA6JD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAIhF"}
1
+ {"version":3,"file":"jvm-stacktrace.d.ts","sourceRoot":"","sources":["../../../src/data/diagnostics/jvm-stacktrace.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,YAAY,GAAG,iBAAiB,GAAG,SAAS,CAAC;IACxE,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IAKxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAIhB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AASD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,EAAE,CAa/D;AAsMD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAIhF"}