@flanksource/clicky-ui 0.3.56 → 0.3.58

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 (145) hide show
  1. package/dist/components/ErrorWrapper.cjs +15 -4
  2. package/dist/components/ErrorWrapper.cjs.map +1 -1
  3. package/dist/components/ErrorWrapper.d.ts +7 -0
  4. package/dist/components/ErrorWrapper.d.ts.map +1 -1
  5. package/dist/components/ErrorWrapper.js +15 -4
  6. package/dist/components/ErrorWrapper.js.map +1 -1
  7. package/dist/data/ai/PromptCatalog/PromptLayerStrip.cjs +6 -3
  8. package/dist/data/ai/PromptCatalog/PromptLayerStrip.cjs.map +1 -1
  9. package/dist/data/ai/PromptCatalog/PromptLayerStrip.js +6 -3
  10. package/dist/data/ai/PromptCatalog/PromptLayerStrip.js.map +1 -1
  11. package/dist/data/ai/PromptCatalog/PromptPage.cjs +2 -1
  12. package/dist/data/ai/PromptCatalog/PromptPage.cjs.map +1 -1
  13. package/dist/data/ai/PromptCatalog/PromptPage.d.ts.map +1 -1
  14. package/dist/data/ai/PromptCatalog/PromptPage.js +2 -1
  15. package/dist/data/ai/PromptCatalog/PromptPage.js.map +1 -1
  16. package/dist/data/ai/PromptCatalog/PromptPageHeader.cjs +9 -6
  17. package/dist/data/ai/PromptCatalog/PromptPageHeader.cjs.map +1 -1
  18. package/dist/data/ai/PromptCatalog/PromptPageHeader.d.ts.map +1 -1
  19. package/dist/data/ai/PromptCatalog/PromptPageHeader.js +9 -6
  20. package/dist/data/ai/PromptCatalog/PromptPageHeader.js.map +1 -1
  21. package/dist/data/ai/PromptCatalog/PromptPageSaveBar.cjs +3 -3
  22. package/dist/data/ai/PromptCatalog/PromptPageSaveBar.cjs.map +1 -1
  23. package/dist/data/ai/PromptCatalog/PromptPageSaveBar.d.ts +2 -1
  24. package/dist/data/ai/PromptCatalog/PromptPageSaveBar.d.ts.map +1 -1
  25. package/dist/data/ai/PromptCatalog/PromptPageSaveBar.js +3 -3
  26. package/dist/data/ai/PromptCatalog/PromptPageSaveBar.js.map +1 -1
  27. package/dist/data/ai/PromptCatalog/prompt-page-model.cjs +4 -3
  28. package/dist/data/ai/PromptCatalog/prompt-page-model.cjs.map +1 -1
  29. package/dist/data/ai/PromptCatalog/prompt-page-model.d.ts +1 -1
  30. package/dist/data/ai/PromptCatalog/prompt-page-model.d.ts.map +1 -1
  31. package/dist/data/ai/PromptCatalog/prompt-page-model.js +4 -3
  32. package/dist/data/ai/PromptCatalog/prompt-page-model.js.map +1 -1
  33. package/dist/data/ai/PromptCatalog/types.d.ts +1 -0
  34. package/dist/data/ai/PromptCatalog/types.d.ts.map +1 -1
  35. package/dist/data/traces/index.d.ts +7 -0
  36. package/dist/data/traces/index.d.ts.map +1 -1
  37. package/dist/data/traces/otel/OperationList.cjs +64 -0
  38. package/dist/data/traces/otel/OperationList.cjs.map +1 -0
  39. package/dist/data/traces/otel/OperationList.d.ts +10 -0
  40. package/dist/data/traces/otel/OperationList.d.ts.map +1 -0
  41. package/dist/data/traces/otel/OperationList.js +64 -0
  42. package/dist/data/traces/otel/OperationList.js.map +1 -0
  43. package/dist/data/traces/otel/OtelTraceDetail.cjs +781 -0
  44. package/dist/data/traces/otel/OtelTraceDetail.cjs.map +1 -0
  45. package/dist/data/traces/otel/OtelTraceDetail.d.ts +7 -0
  46. package/dist/data/traces/otel/OtelTraceDetail.d.ts.map +1 -0
  47. package/dist/data/traces/otel/OtelTraceDetail.js +781 -0
  48. package/dist/data/traces/otel/OtelTraceDetail.js.map +1 -0
  49. package/dist/data/traces/otel/OtelTraceSearch.cjs +145 -0
  50. package/dist/data/traces/otel/OtelTraceSearch.cjs.map +1 -0
  51. package/dist/data/traces/otel/OtelTraceSearch.d.ts +16 -0
  52. package/dist/data/traces/otel/OtelTraceSearch.d.ts.map +1 -0
  53. package/dist/data/traces/otel/OtelTraceSearch.js +145 -0
  54. package/dist/data/traces/otel/OtelTraceSearch.js.map +1 -0
  55. package/dist/data/traces/otel/OtelTraceTable.cjs +47 -0
  56. package/dist/data/traces/otel/OtelTraceTable.cjs.map +1 -0
  57. package/dist/data/traces/otel/OtelTraceTable.d.ts +12 -0
  58. package/dist/data/traces/otel/OtelTraceTable.d.ts.map +1 -0
  59. package/dist/data/traces/otel/OtelTraceTable.js +47 -0
  60. package/dist/data/traces/otel/OtelTraceTable.js.map +1 -0
  61. package/dist/data/traces/otel/QueryBar.cjs +158 -0
  62. package/dist/data/traces/otel/QueryBar.cjs.map +1 -0
  63. package/dist/data/traces/otel/QueryBar.d.ts +12 -0
  64. package/dist/data/traces/otel/QueryBar.d.ts.map +1 -0
  65. package/dist/data/traces/otel/QueryBar.js +158 -0
  66. package/dist/data/traces/otel/QueryBar.js.map +1 -0
  67. package/dist/data/traces/otel/SpanCards.cjs +264 -0
  68. package/dist/data/traces/otel/SpanCards.cjs.map +1 -0
  69. package/dist/data/traces/otel/SpanCards.d.ts +17 -0
  70. package/dist/data/traces/otel/SpanCards.d.ts.map +1 -0
  71. package/dist/data/traces/otel/SpanCards.js +261 -0
  72. package/dist/data/traces/otel/SpanCards.js.map +1 -0
  73. package/dist/data/traces/otel/SpanCategory.cjs +18 -0
  74. package/dist/data/traces/otel/SpanCategory.cjs.map +1 -0
  75. package/dist/data/traces/otel/SpanCategory.d.ts +7 -0
  76. package/dist/data/traces/otel/SpanCategory.d.ts.map +1 -0
  77. package/dist/data/traces/otel/SpanCategory.js +18 -0
  78. package/dist/data/traces/otel/SpanCategory.js.map +1 -0
  79. package/dist/data/traces/otel/TraceResults.cjs +195 -0
  80. package/dist/data/traces/otel/TraceResults.cjs.map +1 -0
  81. package/dist/data/traces/otel/TraceResults.d.ts +19 -0
  82. package/dist/data/traces/otel/TraceResults.d.ts.map +1 -0
  83. package/dist/data/traces/otel/TraceResults.js +193 -0
  84. package/dist/data/traces/otel/TraceResults.js.map +1 -0
  85. package/dist/data/traces/otel/api.cjs +36 -0
  86. package/dist/data/traces/otel/api.cjs.map +1 -0
  87. package/dist/data/traces/otel/api.d.ts +87 -0
  88. package/dist/data/traces/otel/api.d.ts.map +1 -0
  89. package/dist/data/traces/otel/api.js +33 -0
  90. package/dist/data/traces/otel/api.js.map +1 -0
  91. package/dist/data/traces/otel/fixtures.d.ts +4 -0
  92. package/dist/data/traces/otel/fixtures.d.ts.map +1 -0
  93. package/dist/data/traces/otel/metrics.cjs +7 -0
  94. package/dist/data/traces/otel/metrics.cjs.map +1 -0
  95. package/dist/data/traces/otel/metrics.d.ts +2 -0
  96. package/dist/data/traces/otel/metrics.d.ts.map +1 -0
  97. package/dist/data/traces/otel/metrics.js +7 -0
  98. package/dist/data/traces/otel/metrics.js.map +1 -0
  99. package/dist/data/traces/otel/model.cjs +167 -0
  100. package/dist/data/traces/otel/model.cjs.map +1 -0
  101. package/dist/data/traces/otel/model.d.ts +81 -0
  102. package/dist/data/traces/otel/model.d.ts.map +1 -0
  103. package/dist/data/traces/otel/model.js +154 -0
  104. package/dist/data/traces/otel/model.js.map +1 -0
  105. package/dist/data/traces/otel/query.cjs +90 -0
  106. package/dist/data/traces/otel/query.cjs.map +1 -0
  107. package/dist/data/traces/otel/query.d.ts +20 -0
  108. package/dist/data/traces/otel/query.d.ts.map +1 -0
  109. package/dist/data/traces/otel/query.js +86 -0
  110. package/dist/data/traces/otel/query.js.map +1 -0
  111. package/dist/data/traces/otel/result-model.cjs +25 -0
  112. package/dist/data/traces/otel/result-model.cjs.map +1 -0
  113. package/dist/data/traces/otel/result-model.d.ts +5 -0
  114. package/dist/data/traces/otel/result-model.d.ts.map +1 -0
  115. package/dist/data/traces/otel/result-model.js +24 -0
  116. package/dist/data/traces/otel/result-model.js.map +1 -0
  117. package/dist/data/traces/otel/source.cjs +11 -0
  118. package/dist/data/traces/otel/source.cjs.map +1 -0
  119. package/dist/data/traces/otel/source.d.ts +5 -0
  120. package/dist/data/traces/otel/source.d.ts.map +1 -0
  121. package/dist/data/traces/otel/source.js +10 -0
  122. package/dist/data/traces/otel/source.js.map +1 -0
  123. package/dist/data/traces/otel/span-traces.cjs +39 -0
  124. package/dist/data/traces/otel/span-traces.cjs.map +1 -0
  125. package/dist/data/traces/otel/span-traces.d.ts +3 -0
  126. package/dist/data/traces/otel/span-traces.d.ts.map +1 -0
  127. package/dist/data/traces/otel/span-traces.js +39 -0
  128. package/dist/data/traces/otel/span-traces.js.map +1 -0
  129. package/dist/data/version-info.cjs +3 -3
  130. package/dist/data/version-info.js +3 -3
  131. package/dist/data.cjs +11 -0
  132. package/dist/data.js +6 -1
  133. package/dist/index.cjs +11 -0
  134. package/dist/index.js +6 -1
  135. package/dist/profiles/editor/profileEditorSections.cjs +4 -0
  136. package/dist/profiles/editor/profileEditorSections.cjs.map +1 -1
  137. package/dist/profiles/editor/profileEditorSections.d.ts.map +1 -1
  138. package/dist/profiles/editor/profileEditorSections.js +4 -0
  139. package/dist/profiles/editor/profileEditorSections.js.map +1 -1
  140. package/dist/rpc/CommandForm.cjs +1 -1
  141. package/dist/rpc/CommandForm.cjs.map +1 -1
  142. package/dist/rpc/CommandForm.js +1 -1
  143. package/dist/rpc/CommandForm.js.map +1 -1
  144. package/dist/styles.css +1 -1
  145. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PromptPageHeader.cjs","names":["effectiveLayer","layersAbove","Button","UiArrowLeft","PromptSourceBadge","CopyBadge","Badge","runtimeSummary","_Fragment","layerLabel","UiWarningTriangle"],"sources":["../../../../src/data/ai/PromptCatalog/PromptPageHeader.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Button } from \"../../../components/button\";\nimport { UiArrowLeft, UiWarningTriangle } from \"../../../icons\";\nimport { Badge } from \"../../Badge\";\nimport { CopyBadge } from \"../../diagnostics/ErrorDetails\";\nimport {\n effectiveLayer,\n layerLabel,\n layersAbove,\n runtimeSummary,\n} from \"./prompt-catalog-model\";\nimport { PromptSourceBadge } from \"./PromptSourceBadge\";\nimport type { PromptCatalogEntry, PromptCatalogLayer } from \"./types\";\n\nexport type PromptPageHeaderProps = {\n entry: PromptCatalogEntry;\n selectedLayer?: PromptCatalogLayer | undefined;\n onBack?: (() => void) | undefined;\n actions?: ReactNode | undefined;\n};\n\nexport function PromptPageHeader({\n entry,\n selectedLayer,\n onBack,\n actions,\n}: PromptPageHeaderProps) {\n const effective = effectiveLayer(entry);\n const shadowing = selectedLayer ? layersAbove(entry, selectedLayer) : [];\n return (\n <header className=\"flex flex-col gap-2 border-b border-border px-density-4 py-density-3\">\n <div className=\"flex items-start gap-3\">\n {onBack ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={onBack}\n aria-label=\"Back to prompts\"\n >\n <UiArrowLeft />\n </Button>\n ) : null}\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h1 className=\"text-lg font-semibold leading-tight\">\n {entry.title}\n </h1>\n <PromptSourceBadge\n source={entry.source}\n parseError={entry.parseError}\n />\n <CopyBadge label=\"id\" value={entry.id} />\n {entry.configPath && entry.configPath !== entry.id ? (\n <CopyBadge label=\"config\" value={entry.configPath} />\n ) : null}\n </div>\n {entry.description ? (\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {entry.description}\n </p>\n ) : null}\n <dl className=\"mt-2 grid gap-x-6 gap-y-1 text-xs sm:grid-cols-[auto_1fr]\">\n <dt className=\"text-muted-foreground\">Used by</dt>\n <dd className=\"flex flex-wrap gap-1\">\n {(entry.usedBy ?? []).length === 0 ? (\n <span className=\"text-muted-foreground\">—</span>\n ) : (\n (entry.usedBy ?? []).map((command) => (\n <Badge\n key={command}\n variant=\"soft\"\n tone=\"neutral\"\n size=\"xs\"\n className=\"font-mono\"\n clickToCopy={false}\n >\n {command}\n </Badge>\n ))\n )}\n </dd>\n <dt className=\"text-muted-foreground\">Runs as</dt>\n <dd\n className={\n entry.effective.error ? \"text-destructive\" : \"font-mono\"\n }\n >\n {runtimeSummary(entry.effective)}\n {entry.effective.model ? (\n <span className=\"ml-1 font-sans text-muted-foreground\">\n (from {entry.effective.modelSource})\n </span>\n ) : null}\n </dd>\n <dt className=\"text-muted-foreground\">Runs from</dt>\n <dd>\n {effective ? (\n <>\n {layerLabel(effective.origin)}\n <span className=\"ml-1 font-mono text-muted-foreground\">\n {effective.filePath ?? effective.path}\n </span>\n </>\n ) : (\n \"built-in default\"\n )}\n </dd>\n </dl>\n </div>\n {actions ? <div className=\"shrink-0\">{actions}</div> : null}\n </div>\n {shadowing.length > 0 ? (\n <div\n role=\"alert\"\n className=\"flex items-center gap-2 rounded-md border border-amber-300 bg-amber-500/10 px-3 py-2 text-xs text-amber-800 dark:border-amber-500/40 dark:text-amber-300\"\n >\n <UiWarningTriangle className=\"shrink-0\" />\n <span>\n A higher layer (\n {shadowing.map((layer) => layerLabel(layer.origin)).join(\", \")})\n overrides this prompt; saving here changes nothing until that\n override is removed.\n </span>\n </div>\n ) : null}\n </header>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PromptPageHeader.cjs","names":["effectiveLayer","layersAbove","Button","UiArrowLeft","PromptSourceBadge","CopyBadge","Badge","runtimeSummary","_Fragment","layerLabel","UiWarningTriangle"],"sources":["../../../../src/data/ai/PromptCatalog/PromptPageHeader.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Button } from \"../../../components/button\";\nimport { UiArrowLeft, UiWarningTriangle } from \"../../../icons\";\nimport { Badge } from \"../../Badge\";\nimport { CopyBadge } from \"../../diagnostics/ErrorDetails\";\nimport {\n effectiveLayer,\n layerLabel,\n layersAbove,\n runtimeSummary,\n} from \"./prompt-catalog-model\";\nimport { PromptSourceBadge } from \"./PromptSourceBadge\";\nimport type { PromptCatalogEntry, PromptCatalogLayer } from \"./types\";\n\nexport type PromptPageHeaderProps = {\n entry: PromptCatalogEntry;\n selectedLayer?: PromptCatalogLayer | undefined;\n onBack?: (() => void) | undefined;\n actions?: ReactNode | undefined;\n};\n\nexport function PromptPageHeader({\n entry,\n selectedLayer,\n onBack,\n actions,\n}: PromptPageHeaderProps) {\n const effective = effectiveLayer(entry);\n const shadowing = selectedLayer ? layersAbove(entry, selectedLayer) : [];\n return (\n <header className=\"flex flex-col gap-2 border-b border-border px-density-4 py-density-3\">\n <div className=\"flex items-start gap-3\">\n {onBack ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={onBack}\n aria-label=\"Back to prompts\"\n >\n <UiArrowLeft />\n </Button>\n ) : null}\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h1 className=\"break-words text-lg font-semibold leading-tight\">\n {entry.title}\n </h1>\n <PromptSourceBadge\n source={entry.source}\n parseError={entry.parseError}\n />\n <CopyBadge label=\"id\" value={entry.id} />\n {entry.configPath && entry.configPath !== entry.id ? (\n <CopyBadge label=\"config\" value={entry.configPath} />\n ) : null}\n </div>\n {entry.description ? (\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {entry.description}\n </p>\n ) : null}\n <dl className=\"mt-2 grid gap-x-6 gap-y-1 text-xs sm:grid-cols-[auto_1fr]\">\n <dt className=\"text-muted-foreground\">Used by</dt>\n <dd className=\"flex flex-wrap gap-1\">\n {(entry.usedBy ?? []).length === 0 ? (\n <span className=\"text-muted-foreground\">—</span>\n ) : (\n (entry.usedBy ?? []).map((command) => (\n <Badge\n key={command}\n variant=\"soft\"\n tone=\"neutral\"\n size=\"xs\"\n className=\"font-mono\"\n clickToCopy={false}\n >\n {command}\n </Badge>\n ))\n )}\n </dd>\n <dt className=\"text-muted-foreground\">Runs as</dt>\n <dd\n className={\n entry.effective.error\n ? \"min-w-0 break-all text-destructive\"\n : \"min-w-0 break-all font-mono\"\n }\n >\n {runtimeSummary(entry.effective)}\n {entry.effective.model ? (\n <span className=\"ml-1 font-sans text-muted-foreground\">\n (from {entry.effective.modelSource})\n </span>\n ) : null}\n </dd>\n <dt className=\"text-muted-foreground\">Runs from</dt>\n <dd className=\"min-w-0 break-all\">\n {effective ? (\n <>\n {layerLabel(effective.origin)}\n <span className=\"ml-1 font-mono text-muted-foreground\">\n {effective.filePath ?? effective.path}\n </span>\n </>\n ) : (\n \"built-in default\"\n )}\n </dd>\n </dl>\n </div>\n {actions ? <div className=\"shrink-0\">{actions}</div> : null}\n </div>\n {shadowing.length > 0 ? (\n <div\n role=\"alert\"\n className=\"flex items-center gap-2 rounded-md border border-amber-300 bg-amber-500/10 px-3 py-2 text-xs text-amber-800 dark:border-amber-500/40 dark:text-amber-300\"\n >\n <UiWarningTriangle className=\"shrink-0\" />\n <span>\n A higher layer (\n {shadowing.map((layer) => layerLabel(layer.origin)).join(\", \")})\n overrides this prompt; saving here changes nothing until that\n override is removed.\n </span>\n </div>\n ) : null}\n </header>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PromptPageHeader.d.ts","sourceRoot":"","sources":["../../../../src/data/ai/PromptCatalog/PromptPageHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAYvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAEtE,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,aAAa,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAC/C,MAAM,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IAClC,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;CACjC,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,aAAa,EACb,MAAM,EACN,OAAO,GACR,EAAE,qBAAqB,+BAsGvB"}
1
+ {"version":3,"file":"PromptPageHeader.d.ts","sourceRoot":"","sources":["../../../../src/data/ai/PromptCatalog/PromptPageHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAYvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAEtE,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,aAAa,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAC/C,MAAM,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IAClC,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;CACjC,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,aAAa,EACb,MAAM,EACN,OAAO,GACR,EAAE,qBAAqB,+BAwGvB"}
@@ -30,7 +30,7 @@ function PromptPageHeader({ entry, selectedLayer, onBack, actions }) {
30
30
  className: "flex flex-wrap items-center gap-2",
31
31
  children: [
32
32
  /* @__PURE__ */ jsx("h1", {
33
- className: "text-lg font-semibold leading-tight",
33
+ className: "break-words text-lg font-semibold leading-tight",
34
34
  children: entry.title
35
35
  }),
36
36
  /* @__PURE__ */ jsx(PromptSourceBadge, {
@@ -77,7 +77,7 @@ function PromptPageHeader({ entry, selectedLayer, onBack, actions }) {
77
77
  children: "Runs as"
78
78
  }),
79
79
  /* @__PURE__ */ jsxs("dd", {
80
- className: entry.effective.error ? "text-destructive" : "font-mono",
80
+ className: entry.effective.error ? "min-w-0 break-all text-destructive" : "min-w-0 break-all font-mono",
81
81
  children: [runtimeSummary(entry.effective), entry.effective.model ? /* @__PURE__ */ jsxs("span", {
82
82
  className: "ml-1 font-sans text-muted-foreground",
83
83
  children: [
@@ -91,10 +91,13 @@ function PromptPageHeader({ entry, selectedLayer, onBack, actions }) {
91
91
  className: "text-muted-foreground",
92
92
  children: "Runs from"
93
93
  }),
94
- /* @__PURE__ */ jsx("dd", { children: effective ? /* @__PURE__ */ jsxs(Fragment, { children: [layerLabel(effective.origin), /* @__PURE__ */ jsx("span", {
95
- className: "ml-1 font-mono text-muted-foreground",
96
- children: effective.filePath ?? effective.path
97
- })] }) : "built-in default" })
94
+ /* @__PURE__ */ jsx("dd", {
95
+ className: "min-w-0 break-all",
96
+ children: effective ? /* @__PURE__ */ jsxs(Fragment, { children: [layerLabel(effective.origin), /* @__PURE__ */ jsx("span", {
97
+ className: "ml-1 font-mono text-muted-foreground",
98
+ children: effective.filePath ?? effective.path
99
+ })] }) : "built-in default"
100
+ })
98
101
  ]
99
102
  })
100
103
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"PromptPageHeader.js","names":["_Fragment"],"sources":["../../../../src/data/ai/PromptCatalog/PromptPageHeader.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Button } from \"../../../components/button\";\nimport { UiArrowLeft, UiWarningTriangle } from \"../../../icons\";\nimport { Badge } from \"../../Badge\";\nimport { CopyBadge } from \"../../diagnostics/ErrorDetails\";\nimport {\n effectiveLayer,\n layerLabel,\n layersAbove,\n runtimeSummary,\n} from \"./prompt-catalog-model\";\nimport { PromptSourceBadge } from \"./PromptSourceBadge\";\nimport type { PromptCatalogEntry, PromptCatalogLayer } from \"./types\";\n\nexport type PromptPageHeaderProps = {\n entry: PromptCatalogEntry;\n selectedLayer?: PromptCatalogLayer | undefined;\n onBack?: (() => void) | undefined;\n actions?: ReactNode | undefined;\n};\n\nexport function PromptPageHeader({\n entry,\n selectedLayer,\n onBack,\n actions,\n}: PromptPageHeaderProps) {\n const effective = effectiveLayer(entry);\n const shadowing = selectedLayer ? layersAbove(entry, selectedLayer) : [];\n return (\n <header className=\"flex flex-col gap-2 border-b border-border px-density-4 py-density-3\">\n <div className=\"flex items-start gap-3\">\n {onBack ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={onBack}\n aria-label=\"Back to prompts\"\n >\n <UiArrowLeft />\n </Button>\n ) : null}\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h1 className=\"text-lg font-semibold leading-tight\">\n {entry.title}\n </h1>\n <PromptSourceBadge\n source={entry.source}\n parseError={entry.parseError}\n />\n <CopyBadge label=\"id\" value={entry.id} />\n {entry.configPath && entry.configPath !== entry.id ? (\n <CopyBadge label=\"config\" value={entry.configPath} />\n ) : null}\n </div>\n {entry.description ? (\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {entry.description}\n </p>\n ) : null}\n <dl className=\"mt-2 grid gap-x-6 gap-y-1 text-xs sm:grid-cols-[auto_1fr]\">\n <dt className=\"text-muted-foreground\">Used by</dt>\n <dd className=\"flex flex-wrap gap-1\">\n {(entry.usedBy ?? []).length === 0 ? (\n <span className=\"text-muted-foreground\">—</span>\n ) : (\n (entry.usedBy ?? []).map((command) => (\n <Badge\n key={command}\n variant=\"soft\"\n tone=\"neutral\"\n size=\"xs\"\n className=\"font-mono\"\n clickToCopy={false}\n >\n {command}\n </Badge>\n ))\n )}\n </dd>\n <dt className=\"text-muted-foreground\">Runs as</dt>\n <dd\n className={\n entry.effective.error ? \"text-destructive\" : \"font-mono\"\n }\n >\n {runtimeSummary(entry.effective)}\n {entry.effective.model ? (\n <span className=\"ml-1 font-sans text-muted-foreground\">\n (from {entry.effective.modelSource})\n </span>\n ) : null}\n </dd>\n <dt className=\"text-muted-foreground\">Runs from</dt>\n <dd>\n {effective ? (\n <>\n {layerLabel(effective.origin)}\n <span className=\"ml-1 font-mono text-muted-foreground\">\n {effective.filePath ?? effective.path}\n </span>\n </>\n ) : (\n \"built-in default\"\n )}\n </dd>\n </dl>\n </div>\n {actions ? <div className=\"shrink-0\">{actions}</div> : null}\n </div>\n {shadowing.length > 0 ? (\n <div\n role=\"alert\"\n className=\"flex items-center gap-2 rounded-md border border-amber-300 bg-amber-500/10 px-3 py-2 text-xs text-amber-800 dark:border-amber-500/40 dark:text-amber-300\"\n >\n <UiWarningTriangle className=\"shrink-0\" />\n <span>\n A higher layer (\n {shadowing.map((layer) => layerLabel(layer.origin)).join(\", \")})\n overrides this prompt; saving here changes nothing until that\n override is removed.\n </span>\n </div>\n ) : null}\n </header>\n );\n}\n"],"mappings":";;;;;;;;;AAqBA,SAAgB,iBAAiB,EAC/B,OACA,eACA,QACA,WACwB;CACxB,MAAM,YAAY,eAAe,KAAK;CACtC,MAAM,YAAY,gBAAgB,YAAY,OAAO,aAAa,IAAI,CAAC;CACvE,OACE,qBAAC,UAAD;EAAQ,WAAU;EAAlB,UAAA,CACE,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACG,SACC,oBAAC,QAAD;KACE,MAAK;KACL,SAAQ;KACR,MAAK;KACL,SAAS;KACT,cAAW;KAEX,UAAA,oBAAC,aAAD,CAAc,CAAA;IACR,CAAA,IACN;IACJ,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA;MACE,qBAAC,OAAD;OAAK,WAAU;OAAf,UAAA;QACE,oBAAC,MAAD;SAAI,WAAU;SACX,UAAA,MAAM;QACL,CAAA;QACJ,oBAAC,mBAAD;SACE,QAAQ,MAAM;SACd,YAAY,MAAM;QACnB,CAAA;QACD,oBAAC,WAAD;SAAW,OAAM;SAAK,OAAO,MAAM;QAAK,CAAA;QACvC,MAAM,cAAc,MAAM,eAAe,MAAM,KAC9C,oBAAC,WAAD;SAAW,OAAM;SAAS,OAAO,MAAM;QAAa,CAAA,IAClD;OACD;;MACJ,MAAM,cACL,oBAAC,KAAD;OAAG,WAAU;OACV,UAAA,MAAM;MACN,CAAA,IACD;MACJ,qBAAC,MAAD;OAAI,WAAU;OAAd,UAAA;QACE,oBAAC,MAAD;SAAI,WAAU;SAAwB,UAAA;QAAW,CAAA;QACjD,oBAAC,MAAD;SAAI,WAAU;SACV,WAAA,MAAM,UAAU,CAAC,EAAA,CAAG,WAAW,IAC/B,oBAAC,QAAD;UAAM,WAAU;UAAwB,UAAA;SAAO,CAAA,KAE9C,MAAM,UAAU,CAAC,EAAA,CAAG,KAAK,YACxB,oBAAC,OAAD;UAEE,SAAQ;UACR,MAAK;UACL,MAAK;UACL,WAAU;UACV,aAAa;UAEZ,UAAA;SACI,GARA,OAQA,CACR;QAED,CAAA;QACJ,oBAAC,MAAD;SAAI,WAAU;SAAwB,UAAA;QAAW,CAAA;QACjD,qBAAC,MAAD;SACE,WACE,MAAM,UAAU,QAAQ,qBAAqB;SAFjD,UAAA,CAKG,eAAe,MAAM,SAAS,GAC9B,MAAM,UAAU,QACf,qBAAC,QAAD;UAAM,WAAU;UAAhB,UAAA;WAAuD;WAC9C,MAAM,UAAU;WAAY;UAC/B;SACJ,CAAA,IAAA,IACF;;QACJ,oBAAC,MAAD;SAAI,WAAU;SAAwB,UAAA;QAAa,CAAA;QACnD,oBAAC,MAAD,EAAA,UACG,YACC,qBAAAA,UAAA,EAAA,UAAA,CACG,WAAW,UAAU,MAAM,GAC5B,oBAAC,QAAD;SAAM,WAAU;SACb,UAAA,UAAU,YAAY,UAAU;QAC7B,CAAA,CACN,EAAA,CAAA,IAEF,mBAEA,CAAA;OACF;;KACD;;IACJ,UAAU,oBAAC,OAAD;KAAK,WAAU;KAAY,UAAA;IAAa,CAAA,IAAI;GACpD;EACJ,CAAA,GAAA,UAAU,SAAS,IAClB,qBAAC,OAAD;GACE,MAAK;GACL,WAAU;GAFZ,UAAA,CAIE,oBAAC,mBAAD,EAAmB,WAAU,WAAY,CAAA,GACzC,qBAAC,QAAD,EAAA,UAAA;IAAM;IAEH,UAAU,KAAK,UAAU,WAAW,MAAM,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI;IAAE;GAG3D,EAAA,CAAA,CACH;EACH,CAAA,IAAA,IACE;;AAEZ"}
1
+ {"version":3,"file":"PromptPageHeader.js","names":["_Fragment"],"sources":["../../../../src/data/ai/PromptCatalog/PromptPageHeader.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Button } from \"../../../components/button\";\nimport { UiArrowLeft, UiWarningTriangle } from \"../../../icons\";\nimport { Badge } from \"../../Badge\";\nimport { CopyBadge } from \"../../diagnostics/ErrorDetails\";\nimport {\n effectiveLayer,\n layerLabel,\n layersAbove,\n runtimeSummary,\n} from \"./prompt-catalog-model\";\nimport { PromptSourceBadge } from \"./PromptSourceBadge\";\nimport type { PromptCatalogEntry, PromptCatalogLayer } from \"./types\";\n\nexport type PromptPageHeaderProps = {\n entry: PromptCatalogEntry;\n selectedLayer?: PromptCatalogLayer | undefined;\n onBack?: (() => void) | undefined;\n actions?: ReactNode | undefined;\n};\n\nexport function PromptPageHeader({\n entry,\n selectedLayer,\n onBack,\n actions,\n}: PromptPageHeaderProps) {\n const effective = effectiveLayer(entry);\n const shadowing = selectedLayer ? layersAbove(entry, selectedLayer) : [];\n return (\n <header className=\"flex flex-col gap-2 border-b border-border px-density-4 py-density-3\">\n <div className=\"flex items-start gap-3\">\n {onBack ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={onBack}\n aria-label=\"Back to prompts\"\n >\n <UiArrowLeft />\n </Button>\n ) : null}\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h1 className=\"break-words text-lg font-semibold leading-tight\">\n {entry.title}\n </h1>\n <PromptSourceBadge\n source={entry.source}\n parseError={entry.parseError}\n />\n <CopyBadge label=\"id\" value={entry.id} />\n {entry.configPath && entry.configPath !== entry.id ? (\n <CopyBadge label=\"config\" value={entry.configPath} />\n ) : null}\n </div>\n {entry.description ? (\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {entry.description}\n </p>\n ) : null}\n <dl className=\"mt-2 grid gap-x-6 gap-y-1 text-xs sm:grid-cols-[auto_1fr]\">\n <dt className=\"text-muted-foreground\">Used by</dt>\n <dd className=\"flex flex-wrap gap-1\">\n {(entry.usedBy ?? []).length === 0 ? (\n <span className=\"text-muted-foreground\">—</span>\n ) : (\n (entry.usedBy ?? []).map((command) => (\n <Badge\n key={command}\n variant=\"soft\"\n tone=\"neutral\"\n size=\"xs\"\n className=\"font-mono\"\n clickToCopy={false}\n >\n {command}\n </Badge>\n ))\n )}\n </dd>\n <dt className=\"text-muted-foreground\">Runs as</dt>\n <dd\n className={\n entry.effective.error\n ? \"min-w-0 break-all text-destructive\"\n : \"min-w-0 break-all font-mono\"\n }\n >\n {runtimeSummary(entry.effective)}\n {entry.effective.model ? (\n <span className=\"ml-1 font-sans text-muted-foreground\">\n (from {entry.effective.modelSource})\n </span>\n ) : null}\n </dd>\n <dt className=\"text-muted-foreground\">Runs from</dt>\n <dd className=\"min-w-0 break-all\">\n {effective ? (\n <>\n {layerLabel(effective.origin)}\n <span className=\"ml-1 font-mono text-muted-foreground\">\n {effective.filePath ?? effective.path}\n </span>\n </>\n ) : (\n \"built-in default\"\n )}\n </dd>\n </dl>\n </div>\n {actions ? <div className=\"shrink-0\">{actions}</div> : null}\n </div>\n {shadowing.length > 0 ? (\n <div\n role=\"alert\"\n className=\"flex items-center gap-2 rounded-md border border-amber-300 bg-amber-500/10 px-3 py-2 text-xs text-amber-800 dark:border-amber-500/40 dark:text-amber-300\"\n >\n <UiWarningTriangle className=\"shrink-0\" />\n <span>\n A higher layer (\n {shadowing.map((layer) => layerLabel(layer.origin)).join(\", \")})\n overrides this prompt; saving here changes nothing until that\n override is removed.\n </span>\n </div>\n ) : null}\n </header>\n );\n}\n"],"mappings":";;;;;;;;;AAqBA,SAAgB,iBAAiB,EAC/B,OACA,eACA,QACA,WACwB;CACxB,MAAM,YAAY,eAAe,KAAK;CACtC,MAAM,YAAY,gBAAgB,YAAY,OAAO,aAAa,IAAI,CAAC;CACvE,OACE,qBAAC,UAAD;EAAQ,WAAU;EAAlB,UAAA,CACE,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACG,SACC,oBAAC,QAAD;KACE,MAAK;KACL,SAAQ;KACR,MAAK;KACL,SAAS;KACT,cAAW;KAEX,UAAA,oBAAC,aAAD,CAAc,CAAA;IACR,CAAA,IACN;IACJ,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA;MACE,qBAAC,OAAD;OAAK,WAAU;OAAf,UAAA;QACE,oBAAC,MAAD;SAAI,WAAU;SACX,UAAA,MAAM;QACL,CAAA;QACJ,oBAAC,mBAAD;SACE,QAAQ,MAAM;SACd,YAAY,MAAM;QACnB,CAAA;QACD,oBAAC,WAAD;SAAW,OAAM;SAAK,OAAO,MAAM;QAAK,CAAA;QACvC,MAAM,cAAc,MAAM,eAAe,MAAM,KAC9C,oBAAC,WAAD;SAAW,OAAM;SAAS,OAAO,MAAM;QAAa,CAAA,IAClD;OACD;;MACJ,MAAM,cACL,oBAAC,KAAD;OAAG,WAAU;OACV,UAAA,MAAM;MACN,CAAA,IACD;MACJ,qBAAC,MAAD;OAAI,WAAU;OAAd,UAAA;QACE,oBAAC,MAAD;SAAI,WAAU;SAAwB,UAAA;QAAW,CAAA;QACjD,oBAAC,MAAD;SAAI,WAAU;SACV,WAAA,MAAM,UAAU,CAAC,EAAA,CAAG,WAAW,IAC/B,oBAAC,QAAD;UAAM,WAAU;UAAwB,UAAA;SAAO,CAAA,KAE9C,MAAM,UAAU,CAAC,EAAA,CAAG,KAAK,YACxB,oBAAC,OAAD;UAEE,SAAQ;UACR,MAAK;UACL,MAAK;UACL,WAAU;UACV,aAAa;UAEZ,UAAA;SACI,GARA,OAQA,CACR;QAED,CAAA;QACJ,oBAAC,MAAD;SAAI,WAAU;SAAwB,UAAA;QAAW,CAAA;QACjD,qBAAC,MAAD;SACE,WACE,MAAM,UAAU,QACZ,uCACA;SAJR,UAAA,CAOG,eAAe,MAAM,SAAS,GAC9B,MAAM,UAAU,QACf,qBAAC,QAAD;UAAM,WAAU;UAAhB,UAAA;WAAuD;WAC9C,MAAM,UAAU;WAAY;UAC/B;SACJ,CAAA,IAAA,IACF;;QACJ,oBAAC,MAAD;SAAI,WAAU;SAAwB,UAAA;QAAa,CAAA;QACnD,oBAAC,MAAD;SAAI,WAAU;SACX,UAAA,YACC,qBAAAA,UAAA,EAAA,UAAA,CACG,WAAW,UAAU,MAAM,GAC5B,oBAAC,QAAD;UAAM,WAAU;UACb,UAAA,UAAU,YAAY,UAAU;SAC7B,CAAA,CACN,EAAA,CAAA,IAEF;QAEA,CAAA;OACF;;KACD;;IACJ,UAAU,oBAAC,OAAD;KAAK,WAAU;KAAY,UAAA;IAAa,CAAA,IAAI;GACpD;EACJ,CAAA,GAAA,UAAU,SAAS,IAClB,qBAAC,OAAD;GACE,MAAK;GACL,WAAU;GAFZ,UAAA,CAIE,oBAAC,mBAAD,EAAmB,WAAU,WAAY,CAAA,GACzC,qBAAC,QAAD,EAAA,UAAA;IAAM;IAEH,UAAU,KAAK,UAAU,WAAW,MAAM,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI;IAAE;GAG3D,EAAA,CAAA,CACH;EACH,CAAA,IAAA,IACE;;AAEZ"}
@@ -15,7 +15,7 @@ var SOURCE_OPTIONS = [{
15
15
  label: "File",
16
16
  title: "Store the whole document in a .prompt file"
17
17
  }];
18
- function PromptPageSaveBar({ source, onSourceChange, path, onPathChange, dirty, saving, canRemove, error, conflict, onSave, onRemove, onReload }) {
18
+ function PromptPageSaveBar({ sources, source, onSourceChange, path, onPathChange, dirty, saving, canRemove, error, conflict, onSave, onRemove, onReload }) {
19
19
  const [confirmingRemove, setConfirmingRemove] = (0, react.useState)(false);
20
20
  const pathMissing = source === "file" && path.trim() === "";
21
21
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -54,7 +54,7 @@ function PromptPageSaveBar({ source, onSourceChange, path, onPathChange, dirty,
54
54
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SegmentedControl.SegmentedControl, {
55
55
  size: "sm",
56
56
  value: source,
57
- options: SOURCE_OPTIONS,
57
+ options: sources ? SOURCE_OPTIONS.filter((option) => sources.includes(option.id)) : SOURCE_OPTIONS,
58
58
  onChange: onSourceChange,
59
59
  "aria-label": "Save location"
60
60
  }),
@@ -68,7 +68,7 @@ function PromptPageSaveBar({ source, onSourceChange, path, onPathChange, dirty,
68
68
  onChange: (event) => onPathChange(event.currentTarget.value)
69
69
  }) : null,
70
70
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
71
- className: "ml-auto flex items-center gap-2",
71
+ className: "ml-auto flex max-w-full flex-wrap items-center justify-end gap-2",
72
72
  children: [
73
73
  canRemove && !confirmingRemove ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_button.Button, {
74
74
  type: "button",
@@ -1 +1 @@
1
- {"version":3,"file":"PromptPageSaveBar.cjs","names":["useState","UiWarningTriangle","Button","UiRefresh","SegmentedControl","UiSave"],"sources":["../../../../src/data/ai/PromptCatalog/PromptPageSaveBar.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { Button } from \"../../../components/button\";\nimport {\n SegmentedControl,\n type SegmentedOption,\n} from \"../../../components/SegmentedControl\";\nimport { UiRefresh, UiSave, UiWarningTriangle } from \"../../../icons\";\nimport type { PromptSaveSource } from \"./prompt-page-model\";\n\nconst SOURCE_OPTIONS: SegmentedOption<PromptSaveSource>[] = [\n {\n id: \"inline\",\n label: \"Inline\",\n title: \"Store the spec in this layer's config\",\n },\n {\n id: \"file\",\n label: \"File\",\n title: \"Store the whole document in a .prompt file\",\n },\n];\n\nexport type PromptPageSaveBarProps = {\n source: PromptSaveSource;\n onSourceChange: (source: PromptSaveSource) => void;\n path: string;\n onPathChange: (path: string) => void;\n dirty: boolean;\n saving: boolean;\n canRemove: boolean;\n error?: string | undefined;\n conflict: boolean;\n onSave: () => void;\n onRemove: () => void;\n onReload: () => void;\n};\n\n// PromptPageSaveBar holds the destination choice, the save/remove/reload\n// actions and their errors. A stale-base rejection is a conflict, not a\n// failure: it names the fix (reload) instead of inviting a retry that would\n// hit the same wall.\nexport function PromptPageSaveBar({\n source,\n onSourceChange,\n path,\n onPathChange,\n dirty,\n saving,\n canRemove,\n error,\n conflict,\n onSave,\n onRemove,\n onReload,\n}: PromptPageSaveBarProps) {\n const [confirmingRemove, setConfirmingRemove] = useState(false);\n const pathMissing = source === \"file\" && path.trim() === \"\";\n\n return (\n <div className=\"flex flex-col gap-2 border-t border-border px-density-4 py-density-3\">\n <div className=\"mx-auto flex w-full max-w-[820px] flex-col gap-2\">\n {conflict ? (\n <div\n role=\"alert\"\n className=\"flex items-center gap-2 rounded-md border border-amber-300 bg-amber-500/10 px-3 py-2 text-xs text-amber-800 dark:border-amber-500/40 dark:text-amber-300\"\n >\n <UiWarningTriangle className=\"shrink-0\" />\n <span className=\"min-w-0 flex-1\">\n This layer changed since it was loaded. Reload to see the current\n document; your draft will be discarded.\n </span>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={onReload}\n disabled={saving}\n >\n <UiRefresh className=\"mr-1\" />\n Reload\n </Button>\n </div>\n ) : error ? (\n <p\n role=\"alert\"\n className=\"whitespace-pre-wrap text-xs text-destructive\"\n >\n {error}\n </p>\n ) : null}\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Save to\n </span>\n <SegmentedControl\n size=\"sm\"\n value={source}\n options={SOURCE_OPTIONS}\n onChange={onSourceChange}\n aria-label=\"Save location\"\n />\n {source === \"file\" ? (\n <input\n type=\"text\"\n aria-label=\"Prompt file path\"\n className=\"min-w-64 flex-1 rounded-md border border-border bg-background p-1.5 font-mono text-xs\"\n value={path}\n placeholder=\".gavel/prompts/my-prompt.prompt\"\n spellCheck={false}\n onChange={(event) => onPathChange(event.currentTarget.value)}\n />\n ) : null}\n <div className=\"ml-auto flex items-center gap-2\">\n {canRemove && !confirmingRemove ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setConfirmingRemove(true)}\n disabled={saving}\n >\n Remove override from this layer\n </Button>\n ) : null}\n {confirmingRemove ? (\n <span className=\"flex items-center gap-1 text-xs\">\n <span className=\"text-muted-foreground\">\n Remove this layer&apos;s override?\n </span>\n <Button\n type=\"button\"\n variant=\"destructive\"\n size=\"sm\"\n onClick={() => {\n setConfirmingRemove(false);\n onRemove();\n }}\n disabled={saving}\n >\n Remove\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setConfirmingRemove(false)}\n disabled={saving}\n >\n Keep\n </Button>\n </span>\n ) : null}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={onReload}\n disabled={saving}\n >\n <UiRefresh className=\"mr-1\" />\n Reload\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={onSave}\n disabled={saving || !dirty || pathMissing}\n loading={saving}\n >\n <UiSave className=\"mr-1\" />\n {saving ? \"Saving…\" : \"Save\"}\n </Button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PromptPageSaveBar.cjs","names":["useState","UiWarningTriangle","Button","UiRefresh","SegmentedControl","UiSave"],"sources":["../../../../src/data/ai/PromptCatalog/PromptPageSaveBar.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { Button } from \"../../../components/button\";\nimport {\n SegmentedControl,\n type SegmentedOption,\n} from \"../../../components/SegmentedControl\";\nimport { UiRefresh, UiSave, UiWarningTriangle } from \"../../../icons\";\nimport type { PromptSaveSource } from \"./prompt-page-model\";\n\nconst SOURCE_OPTIONS: SegmentedOption<PromptSaveSource>[] = [\n {\n id: \"inline\",\n label: \"Inline\",\n title: \"Store the spec in this layer's config\",\n },\n {\n id: \"file\",\n label: \"File\",\n title: \"Store the whole document in a .prompt file\",\n },\n];\n\nexport type PromptPageSaveBarProps = {\n sources?: PromptSaveSource[] | undefined;\n source: PromptSaveSource;\n onSourceChange: (source: PromptSaveSource) => void;\n path: string;\n onPathChange: (path: string) => void;\n dirty: boolean;\n saving: boolean;\n canRemove: boolean;\n error?: string | undefined;\n conflict: boolean;\n onSave: () => void;\n onRemove: () => void;\n onReload: () => void;\n};\n\n// PromptPageSaveBar holds the destination choice, the save/remove/reload\n// actions and their errors. A stale-base rejection is a conflict, not a\n// failure: it names the fix (reload) instead of inviting a retry that would\n// hit the same wall.\nexport function PromptPageSaveBar({\n sources,\n source,\n onSourceChange,\n path,\n onPathChange,\n dirty,\n saving,\n canRemove,\n error,\n conflict,\n onSave,\n onRemove,\n onReload,\n}: PromptPageSaveBarProps) {\n const [confirmingRemove, setConfirmingRemove] = useState(false);\n const pathMissing = source === \"file\" && path.trim() === \"\";\n\n return (\n <div className=\"flex flex-col gap-2 border-t border-border px-density-4 py-density-3\">\n <div className=\"mx-auto flex w-full max-w-[820px] flex-col gap-2\">\n {conflict ? (\n <div\n role=\"alert\"\n className=\"flex items-center gap-2 rounded-md border border-amber-300 bg-amber-500/10 px-3 py-2 text-xs text-amber-800 dark:border-amber-500/40 dark:text-amber-300\"\n >\n <UiWarningTriangle className=\"shrink-0\" />\n <span className=\"min-w-0 flex-1\">\n This layer changed since it was loaded. Reload to see the current\n document; your draft will be discarded.\n </span>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={onReload}\n disabled={saving}\n >\n <UiRefresh className=\"mr-1\" />\n Reload\n </Button>\n </div>\n ) : error ? (\n <p\n role=\"alert\"\n className=\"whitespace-pre-wrap text-xs text-destructive\"\n >\n {error}\n </p>\n ) : null}\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Save to\n </span>\n <SegmentedControl\n size=\"sm\"\n value={source}\n options={\n sources\n ? SOURCE_OPTIONS.filter((option) => sources.includes(option.id))\n : SOURCE_OPTIONS\n }\n onChange={onSourceChange}\n aria-label=\"Save location\"\n />\n {source === \"file\" ? (\n <input\n type=\"text\"\n aria-label=\"Prompt file path\"\n className=\"min-w-64 flex-1 rounded-md border border-border bg-background p-1.5 font-mono text-xs\"\n value={path}\n placeholder=\".gavel/prompts/my-prompt.prompt\"\n spellCheck={false}\n onChange={(event) => onPathChange(event.currentTarget.value)}\n />\n ) : null}\n <div className=\"ml-auto flex max-w-full flex-wrap items-center justify-end gap-2\">\n {canRemove && !confirmingRemove ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setConfirmingRemove(true)}\n disabled={saving}\n >\n Remove override from this layer\n </Button>\n ) : null}\n {confirmingRemove ? (\n <span className=\"flex items-center gap-1 text-xs\">\n <span className=\"text-muted-foreground\">\n Remove this layer&apos;s override?\n </span>\n <Button\n type=\"button\"\n variant=\"destructive\"\n size=\"sm\"\n onClick={() => {\n setConfirmingRemove(false);\n onRemove();\n }}\n disabled={saving}\n >\n Remove\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setConfirmingRemove(false)}\n disabled={saving}\n >\n Keep\n </Button>\n </span>\n ) : null}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={onReload}\n disabled={saving}\n >\n <UiRefresh className=\"mr-1\" />\n Reload\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={onSave}\n disabled={saving || !dirty || pathMissing}\n loading={saving}\n >\n <UiSave className=\"mr-1\" />\n {saving ? \"Saving…\" : \"Save\"}\n </Button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { PromptSaveSource } from './prompt-page-model.js';
2
2
  export type PromptPageSaveBarProps = {
3
+ sources?: PromptSaveSource[] | undefined;
3
4
  source: PromptSaveSource;
4
5
  onSourceChange: (source: PromptSaveSource) => void;
5
6
  path: string;
@@ -13,5 +14,5 @@ export type PromptPageSaveBarProps = {
13
14
  onRemove: () => void;
14
15
  onReload: () => void;
15
16
  };
16
- export declare function PromptPageSaveBar({ source, onSourceChange, path, onPathChange, dirty, saving, canRemove, error, conflict, onSave, onRemove, onReload, }: PromptPageSaveBarProps): import("react").JSX.Element;
17
+ export declare function PromptPageSaveBar({ sources, source, onSourceChange, path, onPathChange, dirty, saving, canRemove, error, conflict, onSave, onRemove, onReload, }: PromptPageSaveBarProps): import("react").JSX.Element;
17
18
  //# sourceMappingURL=PromptPageSaveBar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PromptPageSaveBar.d.ts","sourceRoot":"","sources":["../../../../src/data/ai/PromptCatalog/PromptPageSaveBar.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAe5D,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,EAAE,gBAAgB,CAAC;IACzB,cAAc,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAMF,wBAAgB,iBAAiB,CAAC,EAChC,MAAM,EACN,cAAc,EACd,IAAI,EACJ,YAAY,EACZ,KAAK,EACL,MAAM,EACN,SAAS,EACT,KAAK,EACL,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,QAAQ,GACT,EAAE,sBAAsB,+BA2HxB"}
1
+ {"version":3,"file":"PromptPageSaveBar.d.ts","sourceRoot":"","sources":["../../../../src/data/ai/PromptCatalog/PromptPageSaveBar.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAe5D,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,CAAC,EAAE,gBAAgB,EAAE,GAAG,SAAS,CAAC;IACzC,MAAM,EAAE,gBAAgB,CAAC;IACzB,cAAc,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAMF,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,MAAM,EACN,cAAc,EACd,IAAI,EACJ,YAAY,EACZ,KAAK,EACL,MAAM,EACN,SAAS,EACT,KAAK,EACL,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,QAAQ,GACT,EAAE,sBAAsB,+BA+HxB"}
@@ -15,7 +15,7 @@ var SOURCE_OPTIONS = [{
15
15
  label: "File",
16
16
  title: "Store the whole document in a .prompt file"
17
17
  }];
18
- function PromptPageSaveBar({ source, onSourceChange, path, onPathChange, dirty, saving, canRemove, error, conflict, onSave, onRemove, onReload }) {
18
+ function PromptPageSaveBar({ sources, source, onSourceChange, path, onPathChange, dirty, saving, canRemove, error, conflict, onSave, onRemove, onReload }) {
19
19
  const [confirmingRemove, setConfirmingRemove] = useState(false);
20
20
  const pathMissing = source === "file" && path.trim() === "";
21
21
  return /* @__PURE__ */ jsx("div", {
@@ -54,7 +54,7 @@ function PromptPageSaveBar({ source, onSourceChange, path, onPathChange, dirty,
54
54
  /* @__PURE__ */ jsx(SegmentedControl, {
55
55
  size: "sm",
56
56
  value: source,
57
- options: SOURCE_OPTIONS,
57
+ options: sources ? SOURCE_OPTIONS.filter((option) => sources.includes(option.id)) : SOURCE_OPTIONS,
58
58
  onChange: onSourceChange,
59
59
  "aria-label": "Save location"
60
60
  }),
@@ -68,7 +68,7 @@ function PromptPageSaveBar({ source, onSourceChange, path, onPathChange, dirty,
68
68
  onChange: (event) => onPathChange(event.currentTarget.value)
69
69
  }) : null,
70
70
  /* @__PURE__ */ jsxs("div", {
71
- className: "ml-auto flex items-center gap-2",
71
+ className: "ml-auto flex max-w-full flex-wrap items-center justify-end gap-2",
72
72
  children: [
73
73
  canRemove && !confirmingRemove ? /* @__PURE__ */ jsx(Button, {
74
74
  type: "button",
@@ -1 +1 @@
1
- {"version":3,"file":"PromptPageSaveBar.js","names":[],"sources":["../../../../src/data/ai/PromptCatalog/PromptPageSaveBar.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { Button } from \"../../../components/button\";\nimport {\n SegmentedControl,\n type SegmentedOption,\n} from \"../../../components/SegmentedControl\";\nimport { UiRefresh, UiSave, UiWarningTriangle } from \"../../../icons\";\nimport type { PromptSaveSource } from \"./prompt-page-model\";\n\nconst SOURCE_OPTIONS: SegmentedOption<PromptSaveSource>[] = [\n {\n id: \"inline\",\n label: \"Inline\",\n title: \"Store the spec in this layer's config\",\n },\n {\n id: \"file\",\n label: \"File\",\n title: \"Store the whole document in a .prompt file\",\n },\n];\n\nexport type PromptPageSaveBarProps = {\n source: PromptSaveSource;\n onSourceChange: (source: PromptSaveSource) => void;\n path: string;\n onPathChange: (path: string) => void;\n dirty: boolean;\n saving: boolean;\n canRemove: boolean;\n error?: string | undefined;\n conflict: boolean;\n onSave: () => void;\n onRemove: () => void;\n onReload: () => void;\n};\n\n// PromptPageSaveBar holds the destination choice, the save/remove/reload\n// actions and their errors. A stale-base rejection is a conflict, not a\n// failure: it names the fix (reload) instead of inviting a retry that would\n// hit the same wall.\nexport function PromptPageSaveBar({\n source,\n onSourceChange,\n path,\n onPathChange,\n dirty,\n saving,\n canRemove,\n error,\n conflict,\n onSave,\n onRemove,\n onReload,\n}: PromptPageSaveBarProps) {\n const [confirmingRemove, setConfirmingRemove] = useState(false);\n const pathMissing = source === \"file\" && path.trim() === \"\";\n\n return (\n <div className=\"flex flex-col gap-2 border-t border-border px-density-4 py-density-3\">\n <div className=\"mx-auto flex w-full max-w-[820px] flex-col gap-2\">\n {conflict ? (\n <div\n role=\"alert\"\n className=\"flex items-center gap-2 rounded-md border border-amber-300 bg-amber-500/10 px-3 py-2 text-xs text-amber-800 dark:border-amber-500/40 dark:text-amber-300\"\n >\n <UiWarningTriangle className=\"shrink-0\" />\n <span className=\"min-w-0 flex-1\">\n This layer changed since it was loaded. Reload to see the current\n document; your draft will be discarded.\n </span>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={onReload}\n disabled={saving}\n >\n <UiRefresh className=\"mr-1\" />\n Reload\n </Button>\n </div>\n ) : error ? (\n <p\n role=\"alert\"\n className=\"whitespace-pre-wrap text-xs text-destructive\"\n >\n {error}\n </p>\n ) : null}\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Save to\n </span>\n <SegmentedControl\n size=\"sm\"\n value={source}\n options={SOURCE_OPTIONS}\n onChange={onSourceChange}\n aria-label=\"Save location\"\n />\n {source === \"file\" ? (\n <input\n type=\"text\"\n aria-label=\"Prompt file path\"\n className=\"min-w-64 flex-1 rounded-md border border-border bg-background p-1.5 font-mono text-xs\"\n value={path}\n placeholder=\".gavel/prompts/my-prompt.prompt\"\n spellCheck={false}\n onChange={(event) => onPathChange(event.currentTarget.value)}\n />\n ) : null}\n <div className=\"ml-auto flex items-center gap-2\">\n {canRemove && !confirmingRemove ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setConfirmingRemove(true)}\n disabled={saving}\n >\n Remove override from this layer\n </Button>\n ) : null}\n {confirmingRemove ? (\n <span className=\"flex items-center gap-1 text-xs\">\n <span className=\"text-muted-foreground\">\n Remove this layer&apos;s override?\n </span>\n <Button\n type=\"button\"\n variant=\"destructive\"\n size=\"sm\"\n onClick={() => {\n setConfirmingRemove(false);\n onRemove();\n }}\n disabled={saving}\n >\n Remove\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setConfirmingRemove(false)}\n disabled={saving}\n >\n Keep\n </Button>\n </span>\n ) : null}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={onReload}\n disabled={saving}\n >\n <UiRefresh className=\"mr-1\" />\n Reload\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={onSave}\n disabled={saving || !dirty || pathMissing}\n loading={saving}\n >\n <UiSave className=\"mr-1\" />\n {saving ? \"Saving…\" : \"Save\"}\n </Button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;AASA,IAAM,iBAAsD,CAC1D;CACE,IAAI;CACJ,OAAO;CACP,OAAO;AACT,GACA;CACE,IAAI;CACJ,OAAO;CACP,OAAO;AACT,CACF;AAqBA,SAAgB,kBAAkB,EAChC,QACA,gBACA,MACA,cACA,OACA,QACA,WACA,OACA,UACA,QACA,UACA,YACyB;CACzB,MAAM,CAAC,kBAAkB,uBAAuB,SAAS,KAAK;CAC9D,MAAM,cAAc,WAAW,UAAU,KAAK,KAAK,MAAM;CAEzD,OACE,oBAAC,OAAD;EAAK,WAAU;EACb,UAAA,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACG,WACC,qBAAC,OAAD;IACE,MAAK;IACL,WAAU;IAFZ,UAAA;KAIE,oBAAC,mBAAD,EAAmB,WAAU,WAAY,CAAA;KACzC,oBAAC,QAAD;MAAM,WAAU;MAAiB,UAAA;KAG3B,CAAA;KACN,qBAAC,QAAD;MACE,MAAK;MACL,MAAK;MACL,SAAQ;MACR,SAAS;MACT,UAAU;MALZ,UAAA,CAOE,oBAAC,WAAD,EAAW,WAAU,OAAQ,CAAA,GAAC,QAExB;;IACL;GACH,CAAA,IAAA,QACF,oBAAC,KAAD;IACE,MAAK;IACL,WAAU;IAET,UAAA;GACA,CAAA,IACD,MACJ,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,oBAAC,QAAD;MAAM,WAAU;MAA4C,UAAA;KAEtD,CAAA;KACN,oBAAC,kBAAD;MACE,MAAK;MACL,OAAO;MACP,SAAS;MACT,UAAU;MACV,cAAW;KACZ,CAAA;KACA,WAAW,SACV,oBAAC,SAAD;MACE,MAAK;MACL,cAAW;MACX,WAAU;MACV,OAAO;MACP,aAAY;MACZ,YAAY;MACZ,WAAW,UAAU,aAAa,MAAM,cAAc,KAAK;KAC5D,CAAA,IACC;KACJ,qBAAC,OAAD;MAAK,WAAU;MAAf,UAAA;OACG,aAAa,CAAC,mBACb,oBAAC,QAAD;QACE,MAAK;QACL,SAAQ;QACR,MAAK;QACL,eAAe,oBAAoB,IAAI;QACvC,UAAU;QACX,UAAA;OAEO,CAAA,IACN;OACH,mBACC,qBAAC,QAAD;QAAM,WAAU;QAAhB,UAAA;SACE,oBAAC,QAAD;UAAM,WAAU;UAAwB,UAAA;SAElC,CAAA;SACN,oBAAC,QAAD;UACE,MAAK;UACL,SAAQ;UACR,MAAK;UACL,eAAe;WACb,oBAAoB,KAAK;WACzB,SAAS;UACX;UACA,UAAU;UACX,UAAA;SAEO,CAAA;SACR,oBAAC,QAAD;UACE,MAAK;UACL,SAAQ;UACR,MAAK;UACL,eAAe,oBAAoB,KAAK;UACxC,UAAU;UACX,UAAA;SAEO,CAAA;QACJ;OACJ,CAAA,IAAA;OACJ,qBAAC,QAAD;QACE,MAAK;QACL,SAAQ;QACR,MAAK;QACL,SAAS;QACT,UAAU;QALZ,UAAA,CAOE,oBAAC,WAAD,EAAW,WAAU,OAAQ,CAAA,GAAC,QAExB;;OACR,qBAAC,QAAD;QACE,MAAK;QACL,MAAK;QACL,SAAS;QACT,UAAU,UAAU,CAAC,SAAS;QAC9B,SAAS;QALX,UAAA,CAOE,oBAAC,QAAD,EAAQ,WAAU,OAAQ,CAAA,GACzB,SAAS,YAAY,MAChB;;MACL;;IACF;GACF,CAAA,CAAA;;CACF,CAAA;AAET"}
1
+ {"version":3,"file":"PromptPageSaveBar.js","names":[],"sources":["../../../../src/data/ai/PromptCatalog/PromptPageSaveBar.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { Button } from \"../../../components/button\";\nimport {\n SegmentedControl,\n type SegmentedOption,\n} from \"../../../components/SegmentedControl\";\nimport { UiRefresh, UiSave, UiWarningTriangle } from \"../../../icons\";\nimport type { PromptSaveSource } from \"./prompt-page-model\";\n\nconst SOURCE_OPTIONS: SegmentedOption<PromptSaveSource>[] = [\n {\n id: \"inline\",\n label: \"Inline\",\n title: \"Store the spec in this layer's config\",\n },\n {\n id: \"file\",\n label: \"File\",\n title: \"Store the whole document in a .prompt file\",\n },\n];\n\nexport type PromptPageSaveBarProps = {\n sources?: PromptSaveSource[] | undefined;\n source: PromptSaveSource;\n onSourceChange: (source: PromptSaveSource) => void;\n path: string;\n onPathChange: (path: string) => void;\n dirty: boolean;\n saving: boolean;\n canRemove: boolean;\n error?: string | undefined;\n conflict: boolean;\n onSave: () => void;\n onRemove: () => void;\n onReload: () => void;\n};\n\n// PromptPageSaveBar holds the destination choice, the save/remove/reload\n// actions and their errors. A stale-base rejection is a conflict, not a\n// failure: it names the fix (reload) instead of inviting a retry that would\n// hit the same wall.\nexport function PromptPageSaveBar({\n sources,\n source,\n onSourceChange,\n path,\n onPathChange,\n dirty,\n saving,\n canRemove,\n error,\n conflict,\n onSave,\n onRemove,\n onReload,\n}: PromptPageSaveBarProps) {\n const [confirmingRemove, setConfirmingRemove] = useState(false);\n const pathMissing = source === \"file\" && path.trim() === \"\";\n\n return (\n <div className=\"flex flex-col gap-2 border-t border-border px-density-4 py-density-3\">\n <div className=\"mx-auto flex w-full max-w-[820px] flex-col gap-2\">\n {conflict ? (\n <div\n role=\"alert\"\n className=\"flex items-center gap-2 rounded-md border border-amber-300 bg-amber-500/10 px-3 py-2 text-xs text-amber-800 dark:border-amber-500/40 dark:text-amber-300\"\n >\n <UiWarningTriangle className=\"shrink-0\" />\n <span className=\"min-w-0 flex-1\">\n This layer changed since it was loaded. Reload to see the current\n document; your draft will be discarded.\n </span>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={onReload}\n disabled={saving}\n >\n <UiRefresh className=\"mr-1\" />\n Reload\n </Button>\n </div>\n ) : error ? (\n <p\n role=\"alert\"\n className=\"whitespace-pre-wrap text-xs text-destructive\"\n >\n {error}\n </p>\n ) : null}\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Save to\n </span>\n <SegmentedControl\n size=\"sm\"\n value={source}\n options={\n sources\n ? SOURCE_OPTIONS.filter((option) => sources.includes(option.id))\n : SOURCE_OPTIONS\n }\n onChange={onSourceChange}\n aria-label=\"Save location\"\n />\n {source === \"file\" ? (\n <input\n type=\"text\"\n aria-label=\"Prompt file path\"\n className=\"min-w-64 flex-1 rounded-md border border-border bg-background p-1.5 font-mono text-xs\"\n value={path}\n placeholder=\".gavel/prompts/my-prompt.prompt\"\n spellCheck={false}\n onChange={(event) => onPathChange(event.currentTarget.value)}\n />\n ) : null}\n <div className=\"ml-auto flex max-w-full flex-wrap items-center justify-end gap-2\">\n {canRemove && !confirmingRemove ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setConfirmingRemove(true)}\n disabled={saving}\n >\n Remove override from this layer\n </Button>\n ) : null}\n {confirmingRemove ? (\n <span className=\"flex items-center gap-1 text-xs\">\n <span className=\"text-muted-foreground\">\n Remove this layer&apos;s override?\n </span>\n <Button\n type=\"button\"\n variant=\"destructive\"\n size=\"sm\"\n onClick={() => {\n setConfirmingRemove(false);\n onRemove();\n }}\n disabled={saving}\n >\n Remove\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setConfirmingRemove(false)}\n disabled={saving}\n >\n Keep\n </Button>\n </span>\n ) : null}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={onReload}\n disabled={saving}\n >\n <UiRefresh className=\"mr-1\" />\n Reload\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={onSave}\n disabled={saving || !dirty || pathMissing}\n loading={saving}\n >\n <UiSave className=\"mr-1\" />\n {saving ? \"Saving…\" : \"Save\"}\n </Button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;AASA,IAAM,iBAAsD,CAC1D;CACE,IAAI;CACJ,OAAO;CACP,OAAO;AACT,GACA;CACE,IAAI;CACJ,OAAO;CACP,OAAO;AACT,CACF;AAsBA,SAAgB,kBAAkB,EAChC,SACA,QACA,gBACA,MACA,cACA,OACA,QACA,WACA,OACA,UACA,QACA,UACA,YACyB;CACzB,MAAM,CAAC,kBAAkB,uBAAuB,SAAS,KAAK;CAC9D,MAAM,cAAc,WAAW,UAAU,KAAK,KAAK,MAAM;CAEzD,OACE,oBAAC,OAAD;EAAK,WAAU;EACb,UAAA,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACG,WACC,qBAAC,OAAD;IACE,MAAK;IACL,WAAU;IAFZ,UAAA;KAIE,oBAAC,mBAAD,EAAmB,WAAU,WAAY,CAAA;KACzC,oBAAC,QAAD;MAAM,WAAU;MAAiB,UAAA;KAG3B,CAAA;KACN,qBAAC,QAAD;MACE,MAAK;MACL,MAAK;MACL,SAAQ;MACR,SAAS;MACT,UAAU;MALZ,UAAA,CAOE,oBAAC,WAAD,EAAW,WAAU,OAAQ,CAAA,GAAC,QAExB;;IACL;GACH,CAAA,IAAA,QACF,oBAAC,KAAD;IACE,MAAK;IACL,WAAU;IAET,UAAA;GACA,CAAA,IACD,MACJ,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,oBAAC,QAAD;MAAM,WAAU;MAA4C,UAAA;KAEtD,CAAA;KACN,oBAAC,kBAAD;MACE,MAAK;MACL,OAAO;MACP,SACE,UACI,eAAe,QAAQ,WAAW,QAAQ,SAAS,OAAO,EAAE,CAAC,IAC7D;MAEN,UAAU;MACV,cAAW;KACZ,CAAA;KACA,WAAW,SACV,oBAAC,SAAD;MACE,MAAK;MACL,cAAW;MACX,WAAU;MACV,OAAO;MACP,aAAY;MACZ,YAAY;MACZ,WAAW,UAAU,aAAa,MAAM,cAAc,KAAK;KAC5D,CAAA,IACC;KACJ,qBAAC,OAAD;MAAK,WAAU;MAAf,UAAA;OACG,aAAa,CAAC,mBACb,oBAAC,QAAD;QACE,MAAK;QACL,SAAQ;QACR,MAAK;QACL,eAAe,oBAAoB,IAAI;QACvC,UAAU;QACX,UAAA;OAEO,CAAA,IACN;OACH,mBACC,qBAAC,QAAD;QAAM,WAAU;QAAhB,UAAA;SACE,oBAAC,QAAD;UAAM,WAAU;UAAwB,UAAA;SAElC,CAAA;SACN,oBAAC,QAAD;UACE,MAAK;UACL,SAAQ;UACR,MAAK;UACL,eAAe;WACb,oBAAoB,KAAK;WACzB,SAAS;UACX;UACA,UAAU;UACX,UAAA;SAEO,CAAA;SACR,oBAAC,QAAD;UACE,MAAK;UACL,SAAQ;UACR,MAAK;UACL,eAAe,oBAAoB,KAAK;UACxC,UAAU;UACX,UAAA;SAEO,CAAA;QACJ;OACJ,CAAA,IAAA;OACJ,qBAAC,QAAD;QACE,MAAK;QACL,SAAQ;QACR,MAAK;QACL,SAAS;QACT,UAAU;QALZ,UAAA,CAOE,oBAAC,WAAD,EAAW,WAAU,OAAQ,CAAA,GAAC,QAExB;;OACR,qBAAC,QAAD;QACE,MAAK;QACL,MAAK;QACL,SAAS;QACT,UAAU,UAAU,CAAC,SAAS;QAC9B,SAAS;QALX,UAAA,CAOE,oBAAC,QAAD,EAAQ,WAAU,OAAQ,CAAA,GACzB,SAAS,YAAY,MAChB;;MACL;;IACF;GACF,CAAA,CAAA;;CACF,CAAA;AAET"}
@@ -29,7 +29,7 @@ function isDraftDirty(draft, detail) {
29
29
  }
30
30
  function isPromptPageDirty({ draft, detail, source, path, entry, layer }) {
31
31
  if (isDraftDirty(draft, detail)) return true;
32
- if (source !== initialSaveSource(detail)) return true;
32
+ if (source !== initialSaveSource(detail, layer)) return true;
33
33
  return source === "file" && path !== defaultFilePath(entry, layer, detail);
34
34
  }
35
35
  function draftRaw(draft) {
@@ -55,8 +55,9 @@ function buildSavePayload(draft, detail, source, path) {
55
55
  baseRaw: detail.raw
56
56
  };
57
57
  }
58
- function initialSaveSource(detail) {
59
- return detail.source === "file" ? "file" : "inline";
58
+ function initialSaveSource(detail, layer) {
59
+ const source = detail.source === "file" ? "file" : "inline";
60
+ return layer?.saveSources?.length && !layer.saveSources.includes(source) ? layer.saveSources[0] : source;
60
61
  }
61
62
  function defaultFilePath(entry, layer, detail) {
62
63
  if (detail?.source === "file" && detail.path) return detail.path;
@@ -1 +1 @@
1
- {"version":3,"file":"prompt-page-model.cjs","names":["isValidPromptSpecDetail","specToPromptRuntimeValue","promptRuntimeValueToPayload","stringify"],"sources":["../../../../src/data/ai/PromptCatalog/prompt-page-model.ts"],"sourcesContent":["import { stringify } from \"yaml\";\nimport type { TabItem } from \"../../../layout/Tabs\";\nimport type { AISpecRuntimeValue } from \"../SpecRuntimeEditor.model\";\nimport {\n promptRuntimeValueToPayload,\n specToPromptRuntimeValue,\n} from \"../PromptPicker/prompt-runtime\";\nimport {\n isValidPromptSpecDetail,\n type PromptSpecDetail,\n type PromptSpecSavePayload,\n} from \"../PromptPicker/types\";\nimport type {\n PromptCatalogEntry,\n PromptCatalogLayer,\n PromptPageTab,\n} from \"./types\";\n\nexport type PromptEditMode = \"raw\" | \"structured\";\nexport type PromptSaveSource = \"inline\" | \"file\";\n\n// PromptDraft is the page's unsaved edit in exactly one representation: the\n// whole .prompt text, or the parsed spec + body the structured editor binds.\n// Switching representation while dirty would need a client-side parser, so\n// the page only switches from a clean state.\nexport type PromptDraft = {\n mode: PromptEditMode;\n raw: string;\n value: AISpecRuntimeValue | undefined;\n};\n\nexport const PROMPT_PAGE_TAB = {\n prompt: \"prompt\",\n preview: \"preview\",\n diff: \"diff\",\n} as const;\n\nexport function detailRuntimeValue(\n detail: PromptSpecDetail,\n): AISpecRuntimeValue | undefined {\n return isValidPromptSpecDetail(detail)\n ? specToPromptRuntimeValue(detail.spec, detail.body)\n : undefined;\n}\n\n// draftFor seeds a draft from a loaded detail: structured when the document\n// parsed, raw (the only repair path) when it did not.\nexport function draftFor(\n detail: PromptSpecDetail,\n mode: PromptEditMode = \"structured\",\n): PromptDraft {\n const value = detailRuntimeValue(detail);\n if (!value || mode === \"raw\")\n return { mode: \"raw\", raw: detail.raw, value: undefined };\n return { mode: \"structured\", raw: detail.raw, value };\n}\n\nexport function isDraftDirty(\n draft: PromptDraft,\n detail: PromptSpecDetail,\n): boolean {\n if (draft.mode === \"raw\") return draft.raw !== detail.raw;\n return (\n JSON.stringify(draft.value ?? null) !==\n JSON.stringify(detailRuntimeValue(detail) ?? null)\n );\n}\n\nexport function isPromptPageDirty({\n draft,\n detail,\n source,\n path,\n entry,\n layer,\n}: {\n draft: PromptDraft;\n detail: PromptSpecDetail;\n source: PromptSaveSource;\n path: string;\n entry: PromptCatalogEntry;\n layer: PromptCatalogLayer;\n}): boolean {\n if (isDraftDirty(draft, detail)) return true;\n const initialSource = initialSaveSource(detail);\n if (source !== initialSource) return true;\n return source === \"file\" && path !== defaultFilePath(entry, layer, detail);\n}\n\n// draftRaw is the .prompt text a draft stands for — the raw text itself, or a\n// structured edit composed back into frontmatter + body so it can be previewed\n// and diffed before it is saved.\nexport function draftRaw(draft: PromptDraft): string {\n if (draft.mode === \"raw\" || !draft.value) return draft.raw;\n const { spec, body } = promptRuntimeValueToPayload(draft.value);\n if (Object.keys(spec).length === 0) return body;\n return `---\\n${stringify(spec)}---\\n${body}`;\n}\n\nexport function buildSavePayload(\n draft: PromptDraft,\n detail: PromptSpecDetail,\n source: PromptSaveSource,\n path: string,\n): PromptSpecSavePayload {\n const filePath = source === \"file\" ? path : undefined;\n if (draft.mode === \"raw\" || !draft.value) {\n return { source, path: filePath, raw: draft.raw, baseRaw: detail.raw };\n }\n const { spec, body } = promptRuntimeValueToPayload(draft.value);\n return { source, path: filePath, spec, body, baseRaw: detail.raw };\n}\n\nexport function initialSaveSource(detail: PromptSpecDetail): PromptSaveSource {\n return detail.source === \"file\" ? \"file\" : \"inline\";\n}\n\n// defaultFilePath is where a file override lands unless the user types a\n// path: the file the layer already points at, else a conventional path under\n// the layer's directory.\nexport function defaultFilePath(\n entry: PromptCatalogEntry,\n layer: PromptCatalogLayer,\n detail?: PromptSpecDetail,\n): string {\n if (detail?.source === \"file\" && detail.path) return detail.path;\n if (layer.filePath) return layer.filePath;\n return `.gavel/prompts/${entry.id.replace(/\\./g, \"-\")}.prompt`;\n}\n\n// isConflictError recognises the backend's optimistic-concurrency rejection\n// (the layer changed after the detail loaded) so the page offers a reload\n// instead of a generic failure.\nexport function isConflictError(message: string): boolean {\n return /changed since it was loaded|reload before saving/i.test(message);\n}\n\nexport function errorMessage(error: unknown, fallback: string): string {\n return error instanceof Error && error.message ? error.message : fallback;\n}\n\nexport function seedVariables(entry: PromptCatalogEntry): string {\n const seed: Record<string, string> = {};\n for (const name of entry.variables ?? []) seed[name] = \"\";\n return JSON.stringify(seed, null, 2);\n}\n\nexport function parseVariables(\n text: string,\n): { variables: Record<string, unknown> } | { error: string } {\n const trimmed = text.trim();\n if (!trimmed) return { variables: {} };\n try {\n const parsed: unknown = JSON.parse(trimmed);\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return { error: \"variables must be a JSON object\" };\n }\n return { variables: parsed as Record<string, unknown> };\n } catch (error) {\n return { error: errorMessage(error, \"invalid JSON\") };\n }\n}\n\nexport function pageTabs(options: {\n canPreview: boolean;\n canDiff: boolean;\n extraTabs?: PromptPageTab[] | undefined;\n}): TabItem[] {\n const tabs: TabItem[] = [{ id: PROMPT_PAGE_TAB.prompt, label: \"Prompt\" }];\n if (options.canPreview)\n tabs.push({ id: PROMPT_PAGE_TAB.preview, label: \"Preview\" });\n if (options.canDiff)\n tabs.push({ id: PROMPT_PAGE_TAB.diff, label: \"Diff vs default\" });\n for (const tab of options.extraTabs ?? []) {\n tabs.push({\n id: tab.id,\n label: tab.label,\n ...(tab.count !== undefined ? { count: tab.count } : {}),\n });\n }\n return tabs;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"prompt-page-model.cjs","names":["isValidPromptSpecDetail","specToPromptRuntimeValue","promptRuntimeValueToPayload","stringify"],"sources":["../../../../src/data/ai/PromptCatalog/prompt-page-model.ts"],"sourcesContent":["import { stringify } from \"yaml\";\nimport type { TabItem } from \"../../../layout/Tabs\";\nimport type { AISpecRuntimeValue } from \"../SpecRuntimeEditor.model\";\nimport {\n promptRuntimeValueToPayload,\n specToPromptRuntimeValue,\n} from \"../PromptPicker/prompt-runtime\";\nimport {\n isValidPromptSpecDetail,\n type PromptSpecDetail,\n type PromptSpecSavePayload,\n} from \"../PromptPicker/types\";\nimport type {\n PromptCatalogEntry,\n PromptCatalogLayer,\n PromptPageTab,\n} from \"./types\";\n\nexport type PromptEditMode = \"raw\" | \"structured\";\nexport type PromptSaveSource = \"inline\" | \"file\";\n\n// PromptDraft is the page's unsaved edit in exactly one representation: the\n// whole .prompt text, or the parsed spec + body the structured editor binds.\n// Switching representation while dirty would need a client-side parser, so\n// the page only switches from a clean state.\nexport type PromptDraft = {\n mode: PromptEditMode;\n raw: string;\n value: AISpecRuntimeValue | undefined;\n};\n\nexport const PROMPT_PAGE_TAB = {\n prompt: \"prompt\",\n preview: \"preview\",\n diff: \"diff\",\n} as const;\n\nexport function detailRuntimeValue(\n detail: PromptSpecDetail,\n): AISpecRuntimeValue | undefined {\n return isValidPromptSpecDetail(detail)\n ? specToPromptRuntimeValue(detail.spec, detail.body)\n : undefined;\n}\n\n// draftFor seeds a draft from a loaded detail: structured when the document\n// parsed, raw (the only repair path) when it did not.\nexport function draftFor(\n detail: PromptSpecDetail,\n mode: PromptEditMode = \"structured\",\n): PromptDraft {\n const value = detailRuntimeValue(detail);\n if (!value || mode === \"raw\")\n return { mode: \"raw\", raw: detail.raw, value: undefined };\n return { mode: \"structured\", raw: detail.raw, value };\n}\n\nexport function isDraftDirty(\n draft: PromptDraft,\n detail: PromptSpecDetail,\n): boolean {\n if (draft.mode === \"raw\") return draft.raw !== detail.raw;\n return (\n JSON.stringify(draft.value ?? null) !==\n JSON.stringify(detailRuntimeValue(detail) ?? null)\n );\n}\n\nexport function isPromptPageDirty({\n draft,\n detail,\n source,\n path,\n entry,\n layer,\n}: {\n draft: PromptDraft;\n detail: PromptSpecDetail;\n source: PromptSaveSource;\n path: string;\n entry: PromptCatalogEntry;\n layer: PromptCatalogLayer;\n}): boolean {\n if (isDraftDirty(draft, detail)) return true;\n const initialSource = initialSaveSource(detail, layer);\n if (source !== initialSource) return true;\n return source === \"file\" && path !== defaultFilePath(entry, layer, detail);\n}\n\n// draftRaw is the .prompt text a draft stands for — the raw text itself, or a\n// structured edit composed back into frontmatter + body so it can be previewed\n// and diffed before it is saved.\nexport function draftRaw(draft: PromptDraft): string {\n if (draft.mode === \"raw\" || !draft.value) return draft.raw;\n const { spec, body } = promptRuntimeValueToPayload(draft.value);\n if (Object.keys(spec).length === 0) return body;\n return `---\\n${stringify(spec)}---\\n${body}`;\n}\n\nexport function buildSavePayload(\n draft: PromptDraft,\n detail: PromptSpecDetail,\n source: PromptSaveSource,\n path: string,\n): PromptSpecSavePayload {\n const filePath = source === \"file\" ? path : undefined;\n if (draft.mode === \"raw\" || !draft.value) {\n return { source, path: filePath, raw: draft.raw, baseRaw: detail.raw };\n }\n const { spec, body } = promptRuntimeValueToPayload(draft.value);\n return { source, path: filePath, spec, body, baseRaw: detail.raw };\n}\n\nexport function initialSaveSource(\n detail: PromptSpecDetail,\n layer?: PromptCatalogLayer,\n): PromptSaveSource {\n const source = detail.source === \"file\" ? \"file\" : \"inline\";\n return layer?.saveSources?.length && !layer.saveSources.includes(source)\n ? layer.saveSources[0]!\n : source;\n}\n\n// defaultFilePath is where a file override lands unless the user types a\n// path: the file the layer already points at, else a conventional path under\n// the layer's directory.\nexport function defaultFilePath(\n entry: PromptCatalogEntry,\n layer: PromptCatalogLayer,\n detail?: PromptSpecDetail,\n): string {\n if (detail?.source === \"file\" && detail.path) return detail.path;\n if (layer.filePath) return layer.filePath;\n return `.gavel/prompts/${entry.id.replace(/\\./g, \"-\")}.prompt`;\n}\n\n// isConflictError recognises the backend's optimistic-concurrency rejection\n// (the layer changed after the detail loaded) so the page offers a reload\n// instead of a generic failure.\nexport function isConflictError(message: string): boolean {\n return /changed since it was loaded|reload before saving/i.test(message);\n}\n\nexport function errorMessage(error: unknown, fallback: string): string {\n return error instanceof Error && error.message ? error.message : fallback;\n}\n\nexport function seedVariables(entry: PromptCatalogEntry): string {\n const seed: Record<string, string> = {};\n for (const name of entry.variables ?? []) seed[name] = \"\";\n return JSON.stringify(seed, null, 2);\n}\n\nexport function parseVariables(\n text: string,\n): { variables: Record<string, unknown> } | { error: string } {\n const trimmed = text.trim();\n if (!trimmed) return { variables: {} };\n try {\n const parsed: unknown = JSON.parse(trimmed);\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return { error: \"variables must be a JSON object\" };\n }\n return { variables: parsed as Record<string, unknown> };\n } catch (error) {\n return { error: errorMessage(error, \"invalid JSON\") };\n }\n}\n\nexport function pageTabs(options: {\n canPreview: boolean;\n canDiff: boolean;\n extraTabs?: PromptPageTab[] | undefined;\n}): TabItem[] {\n const tabs: TabItem[] = [{ id: PROMPT_PAGE_TAB.prompt, label: \"Prompt\" }];\n if (options.canPreview)\n tabs.push({ id: PROMPT_PAGE_TAB.preview, label: \"Preview\" });\n if (options.canDiff)\n tabs.push({ id: PROMPT_PAGE_TAB.diff, label: \"Diff vs default\" });\n for (const tab of options.extraTabs ?? []) {\n tabs.push({\n id: tab.id,\n label: tab.label,\n ...(tab.count !== undefined ? { count: tab.count } : {}),\n });\n }\n return tabs;\n}\n"],"mappings":"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"}
@@ -27,7 +27,7 @@ export declare function isPromptPageDirty({ draft, detail, source, path, entry,
27
27
  }): boolean;
28
28
  export declare function draftRaw(draft: PromptDraft): string;
29
29
  export declare function buildSavePayload(draft: PromptDraft, detail: PromptSpecDetail, source: PromptSaveSource, path: string): PromptSpecSavePayload;
30
- export declare function initialSaveSource(detail: PromptSpecDetail): PromptSaveSource;
30
+ export declare function initialSaveSource(detail: PromptSpecDetail, layer?: PromptCatalogLayer): PromptSaveSource;
31
31
  export declare function defaultFilePath(entry: PromptCatalogEntry, layer: PromptCatalogLayer, detail?: PromptSpecDetail): string;
32
32
  export declare function isConflictError(message: string): boolean;
33
33
  export declare function errorMessage(error: unknown, fallback: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"prompt-page-model.d.ts","sourceRoot":"","sources":["../../../../src/data/ai/PromptCatalog/prompt-page-model.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAKrE,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACd,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,YAAY,CAAC;AAClD,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,MAAM,CAAC;AAMjD,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,kBAAkB,GAAG,SAAS,CAAC;CACvC,CAAC;AAEF,eAAO,MAAM,eAAe;;;;CAIlB,CAAC;AAEX,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,gBAAgB,GACvB,kBAAkB,GAAG,SAAS,CAIhC;AAID,wBAAgB,QAAQ,CACtB,MAAM,EAAE,gBAAgB,EACxB,IAAI,GAAE,cAA6B,GAClC,WAAW,CAKb;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAMT;AAED,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,MAAM,EACN,MAAM,EACN,IAAI,EACJ,KAAK,EACL,KAAK,GACN,EAAE;IACD,KAAK,EAAE,WAAW,CAAC;IACnB,MAAM,EAAE,gBAAgB,CAAC;IACzB,MAAM,EAAE,gBAAgB,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,kBAAkB,CAAC;IAC1B,KAAK,EAAE,kBAAkB,CAAC;CAC3B,GAAG,OAAO,CAKV;AAKD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAKnD;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,MAAM,GACX,qBAAqB,CAOvB;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,GAAG,gBAAgB,CAE5E;AAKD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,kBAAkB,EACzB,KAAK,EAAE,kBAAkB,EACzB,MAAM,CAAC,EAAE,gBAAgB,GACxB,MAAM,CAIR;AAKD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAI/D;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,GACX;IAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAY5D;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE;IAChC,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,aAAa,EAAE,GAAG,SAAS,CAAC;CACzC,GAAG,OAAO,EAAE,CAcZ"}
1
+ {"version":3,"file":"prompt-page-model.d.ts","sourceRoot":"","sources":["../../../../src/data/ai/PromptCatalog/prompt-page-model.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAKrE,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACd,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,YAAY,CAAC;AAClD,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,MAAM,CAAC;AAMjD,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,kBAAkB,GAAG,SAAS,CAAC;CACvC,CAAC;AAEF,eAAO,MAAM,eAAe;;;;CAIlB,CAAC;AAEX,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,gBAAgB,GACvB,kBAAkB,GAAG,SAAS,CAIhC;AAID,wBAAgB,QAAQ,CACtB,MAAM,EAAE,gBAAgB,EACxB,IAAI,GAAE,cAA6B,GAClC,WAAW,CAKb;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAMT;AAED,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,MAAM,EACN,MAAM,EACN,IAAI,EACJ,KAAK,EACL,KAAK,GACN,EAAE;IACD,KAAK,EAAE,WAAW,CAAC;IACnB,MAAM,EAAE,gBAAgB,CAAC;IACzB,MAAM,EAAE,gBAAgB,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,kBAAkB,CAAC;IAC1B,KAAK,EAAE,kBAAkB,CAAC;CAC3B,GAAG,OAAO,CAKV;AAKD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAKnD;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,MAAM,GACX,qBAAqB,CAOvB;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,gBAAgB,EACxB,KAAK,CAAC,EAAE,kBAAkB,GACzB,gBAAgB,CAKlB;AAKD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,kBAAkB,EACzB,KAAK,EAAE,kBAAkB,EACzB,MAAM,CAAC,EAAE,gBAAgB,GACxB,MAAM,CAIR;AAKD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAI/D;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,GACX;IAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAY5D;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE;IAChC,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,aAAa,EAAE,GAAG,SAAS,CAAC;CACzC,GAAG,OAAO,EAAE,CAcZ"}
@@ -29,7 +29,7 @@ function isDraftDirty(draft, detail) {
29
29
  }
30
30
  function isPromptPageDirty({ draft, detail, source, path, entry, layer }) {
31
31
  if (isDraftDirty(draft, detail)) return true;
32
- if (source !== initialSaveSource(detail)) return true;
32
+ if (source !== initialSaveSource(detail, layer)) return true;
33
33
  return source === "file" && path !== defaultFilePath(entry, layer, detail);
34
34
  }
35
35
  function draftRaw(draft) {
@@ -55,8 +55,9 @@ function buildSavePayload(draft, detail, source, path) {
55
55
  baseRaw: detail.raw
56
56
  };
57
57
  }
58
- function initialSaveSource(detail) {
59
- return detail.source === "file" ? "file" : "inline";
58
+ function initialSaveSource(detail, layer) {
59
+ const source = detail.source === "file" ? "file" : "inline";
60
+ return layer?.saveSources?.length && !layer.saveSources.includes(source) ? layer.saveSources[0] : source;
60
61
  }
61
62
  function defaultFilePath(entry, layer, detail) {
62
63
  if (detail?.source === "file" && detail.path) return detail.path;
@@ -1 +1 @@
1
- {"version":3,"file":"prompt-page-model.js","names":[],"sources":["../../../../src/data/ai/PromptCatalog/prompt-page-model.ts"],"sourcesContent":["import { stringify } from \"yaml\";\nimport type { TabItem } from \"../../../layout/Tabs\";\nimport type { AISpecRuntimeValue } from \"../SpecRuntimeEditor.model\";\nimport {\n promptRuntimeValueToPayload,\n specToPromptRuntimeValue,\n} from \"../PromptPicker/prompt-runtime\";\nimport {\n isValidPromptSpecDetail,\n type PromptSpecDetail,\n type PromptSpecSavePayload,\n} from \"../PromptPicker/types\";\nimport type {\n PromptCatalogEntry,\n PromptCatalogLayer,\n PromptPageTab,\n} from \"./types\";\n\nexport type PromptEditMode = \"raw\" | \"structured\";\nexport type PromptSaveSource = \"inline\" | \"file\";\n\n// PromptDraft is the page's unsaved edit in exactly one representation: the\n// whole .prompt text, or the parsed spec + body the structured editor binds.\n// Switching representation while dirty would need a client-side parser, so\n// the page only switches from a clean state.\nexport type PromptDraft = {\n mode: PromptEditMode;\n raw: string;\n value: AISpecRuntimeValue | undefined;\n};\n\nexport const PROMPT_PAGE_TAB = {\n prompt: \"prompt\",\n preview: \"preview\",\n diff: \"diff\",\n} as const;\n\nexport function detailRuntimeValue(\n detail: PromptSpecDetail,\n): AISpecRuntimeValue | undefined {\n return isValidPromptSpecDetail(detail)\n ? specToPromptRuntimeValue(detail.spec, detail.body)\n : undefined;\n}\n\n// draftFor seeds a draft from a loaded detail: structured when the document\n// parsed, raw (the only repair path) when it did not.\nexport function draftFor(\n detail: PromptSpecDetail,\n mode: PromptEditMode = \"structured\",\n): PromptDraft {\n const value = detailRuntimeValue(detail);\n if (!value || mode === \"raw\")\n return { mode: \"raw\", raw: detail.raw, value: undefined };\n return { mode: \"structured\", raw: detail.raw, value };\n}\n\nexport function isDraftDirty(\n draft: PromptDraft,\n detail: PromptSpecDetail,\n): boolean {\n if (draft.mode === \"raw\") return draft.raw !== detail.raw;\n return (\n JSON.stringify(draft.value ?? null) !==\n JSON.stringify(detailRuntimeValue(detail) ?? null)\n );\n}\n\nexport function isPromptPageDirty({\n draft,\n detail,\n source,\n path,\n entry,\n layer,\n}: {\n draft: PromptDraft;\n detail: PromptSpecDetail;\n source: PromptSaveSource;\n path: string;\n entry: PromptCatalogEntry;\n layer: PromptCatalogLayer;\n}): boolean {\n if (isDraftDirty(draft, detail)) return true;\n const initialSource = initialSaveSource(detail);\n if (source !== initialSource) return true;\n return source === \"file\" && path !== defaultFilePath(entry, layer, detail);\n}\n\n// draftRaw is the .prompt text a draft stands for — the raw text itself, or a\n// structured edit composed back into frontmatter + body so it can be previewed\n// and diffed before it is saved.\nexport function draftRaw(draft: PromptDraft): string {\n if (draft.mode === \"raw\" || !draft.value) return draft.raw;\n const { spec, body } = promptRuntimeValueToPayload(draft.value);\n if (Object.keys(spec).length === 0) return body;\n return `---\\n${stringify(spec)}---\\n${body}`;\n}\n\nexport function buildSavePayload(\n draft: PromptDraft,\n detail: PromptSpecDetail,\n source: PromptSaveSource,\n path: string,\n): PromptSpecSavePayload {\n const filePath = source === \"file\" ? path : undefined;\n if (draft.mode === \"raw\" || !draft.value) {\n return { source, path: filePath, raw: draft.raw, baseRaw: detail.raw };\n }\n const { spec, body } = promptRuntimeValueToPayload(draft.value);\n return { source, path: filePath, spec, body, baseRaw: detail.raw };\n}\n\nexport function initialSaveSource(detail: PromptSpecDetail): PromptSaveSource {\n return detail.source === \"file\" ? \"file\" : \"inline\";\n}\n\n// defaultFilePath is where a file override lands unless the user types a\n// path: the file the layer already points at, else a conventional path under\n// the layer's directory.\nexport function defaultFilePath(\n entry: PromptCatalogEntry,\n layer: PromptCatalogLayer,\n detail?: PromptSpecDetail,\n): string {\n if (detail?.source === \"file\" && detail.path) return detail.path;\n if (layer.filePath) return layer.filePath;\n return `.gavel/prompts/${entry.id.replace(/\\./g, \"-\")}.prompt`;\n}\n\n// isConflictError recognises the backend's optimistic-concurrency rejection\n// (the layer changed after the detail loaded) so the page offers a reload\n// instead of a generic failure.\nexport function isConflictError(message: string): boolean {\n return /changed since it was loaded|reload before saving/i.test(message);\n}\n\nexport function errorMessage(error: unknown, fallback: string): string {\n return error instanceof Error && error.message ? error.message : fallback;\n}\n\nexport function seedVariables(entry: PromptCatalogEntry): string {\n const seed: Record<string, string> = {};\n for (const name of entry.variables ?? []) seed[name] = \"\";\n return JSON.stringify(seed, null, 2);\n}\n\nexport function parseVariables(\n text: string,\n): { variables: Record<string, unknown> } | { error: string } {\n const trimmed = text.trim();\n if (!trimmed) return { variables: {} };\n try {\n const parsed: unknown = JSON.parse(trimmed);\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return { error: \"variables must be a JSON object\" };\n }\n return { variables: parsed as Record<string, unknown> };\n } catch (error) {\n return { error: errorMessage(error, \"invalid JSON\") };\n }\n}\n\nexport function pageTabs(options: {\n canPreview: boolean;\n canDiff: boolean;\n extraTabs?: PromptPageTab[] | undefined;\n}): TabItem[] {\n const tabs: TabItem[] = [{ id: PROMPT_PAGE_TAB.prompt, label: \"Prompt\" }];\n if (options.canPreview)\n tabs.push({ id: PROMPT_PAGE_TAB.preview, label: \"Preview\" });\n if (options.canDiff)\n tabs.push({ id: PROMPT_PAGE_TAB.diff, label: \"Diff vs default\" });\n for (const tab of options.extraTabs ?? []) {\n tabs.push({\n id: tab.id,\n label: tab.label,\n ...(tab.count !== undefined ? { count: tab.count } : {}),\n });\n }\n return tabs;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"prompt-page-model.js","names":[],"sources":["../../../../src/data/ai/PromptCatalog/prompt-page-model.ts"],"sourcesContent":["import { stringify } from \"yaml\";\nimport type { TabItem } from \"../../../layout/Tabs\";\nimport type { AISpecRuntimeValue } from \"../SpecRuntimeEditor.model\";\nimport {\n promptRuntimeValueToPayload,\n specToPromptRuntimeValue,\n} from \"../PromptPicker/prompt-runtime\";\nimport {\n isValidPromptSpecDetail,\n type PromptSpecDetail,\n type PromptSpecSavePayload,\n} from \"../PromptPicker/types\";\nimport type {\n PromptCatalogEntry,\n PromptCatalogLayer,\n PromptPageTab,\n} from \"./types\";\n\nexport type PromptEditMode = \"raw\" | \"structured\";\nexport type PromptSaveSource = \"inline\" | \"file\";\n\n// PromptDraft is the page's unsaved edit in exactly one representation: the\n// whole .prompt text, or the parsed spec + body the structured editor binds.\n// Switching representation while dirty would need a client-side parser, so\n// the page only switches from a clean state.\nexport type PromptDraft = {\n mode: PromptEditMode;\n raw: string;\n value: AISpecRuntimeValue | undefined;\n};\n\nexport const PROMPT_PAGE_TAB = {\n prompt: \"prompt\",\n preview: \"preview\",\n diff: \"diff\",\n} as const;\n\nexport function detailRuntimeValue(\n detail: PromptSpecDetail,\n): AISpecRuntimeValue | undefined {\n return isValidPromptSpecDetail(detail)\n ? specToPromptRuntimeValue(detail.spec, detail.body)\n : undefined;\n}\n\n// draftFor seeds a draft from a loaded detail: structured when the document\n// parsed, raw (the only repair path) when it did not.\nexport function draftFor(\n detail: PromptSpecDetail,\n mode: PromptEditMode = \"structured\",\n): PromptDraft {\n const value = detailRuntimeValue(detail);\n if (!value || mode === \"raw\")\n return { mode: \"raw\", raw: detail.raw, value: undefined };\n return { mode: \"structured\", raw: detail.raw, value };\n}\n\nexport function isDraftDirty(\n draft: PromptDraft,\n detail: PromptSpecDetail,\n): boolean {\n if (draft.mode === \"raw\") return draft.raw !== detail.raw;\n return (\n JSON.stringify(draft.value ?? null) !==\n JSON.stringify(detailRuntimeValue(detail) ?? null)\n );\n}\n\nexport function isPromptPageDirty({\n draft,\n detail,\n source,\n path,\n entry,\n layer,\n}: {\n draft: PromptDraft;\n detail: PromptSpecDetail;\n source: PromptSaveSource;\n path: string;\n entry: PromptCatalogEntry;\n layer: PromptCatalogLayer;\n}): boolean {\n if (isDraftDirty(draft, detail)) return true;\n const initialSource = initialSaveSource(detail, layer);\n if (source !== initialSource) return true;\n return source === \"file\" && path !== defaultFilePath(entry, layer, detail);\n}\n\n// draftRaw is the .prompt text a draft stands for — the raw text itself, or a\n// structured edit composed back into frontmatter + body so it can be previewed\n// and diffed before it is saved.\nexport function draftRaw(draft: PromptDraft): string {\n if (draft.mode === \"raw\" || !draft.value) return draft.raw;\n const { spec, body } = promptRuntimeValueToPayload(draft.value);\n if (Object.keys(spec).length === 0) return body;\n return `---\\n${stringify(spec)}---\\n${body}`;\n}\n\nexport function buildSavePayload(\n draft: PromptDraft,\n detail: PromptSpecDetail,\n source: PromptSaveSource,\n path: string,\n): PromptSpecSavePayload {\n const filePath = source === \"file\" ? path : undefined;\n if (draft.mode === \"raw\" || !draft.value) {\n return { source, path: filePath, raw: draft.raw, baseRaw: detail.raw };\n }\n const { spec, body } = promptRuntimeValueToPayload(draft.value);\n return { source, path: filePath, spec, body, baseRaw: detail.raw };\n}\n\nexport function initialSaveSource(\n detail: PromptSpecDetail,\n layer?: PromptCatalogLayer,\n): PromptSaveSource {\n const source = detail.source === \"file\" ? \"file\" : \"inline\";\n return layer?.saveSources?.length && !layer.saveSources.includes(source)\n ? layer.saveSources[0]!\n : source;\n}\n\n// defaultFilePath is where a file override lands unless the user types a\n// path: the file the layer already points at, else a conventional path under\n// the layer's directory.\nexport function defaultFilePath(\n entry: PromptCatalogEntry,\n layer: PromptCatalogLayer,\n detail?: PromptSpecDetail,\n): string {\n if (detail?.source === \"file\" && detail.path) return detail.path;\n if (layer.filePath) return layer.filePath;\n return `.gavel/prompts/${entry.id.replace(/\\./g, \"-\")}.prompt`;\n}\n\n// isConflictError recognises the backend's optimistic-concurrency rejection\n// (the layer changed after the detail loaded) so the page offers a reload\n// instead of a generic failure.\nexport function isConflictError(message: string): boolean {\n return /changed since it was loaded|reload before saving/i.test(message);\n}\n\nexport function errorMessage(error: unknown, fallback: string): string {\n return error instanceof Error && error.message ? error.message : fallback;\n}\n\nexport function seedVariables(entry: PromptCatalogEntry): string {\n const seed: Record<string, string> = {};\n for (const name of entry.variables ?? []) seed[name] = \"\";\n return JSON.stringify(seed, null, 2);\n}\n\nexport function parseVariables(\n text: string,\n): { variables: Record<string, unknown> } | { error: string } {\n const trimmed = text.trim();\n if (!trimmed) return { variables: {} };\n try {\n const parsed: unknown = JSON.parse(trimmed);\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return { error: \"variables must be a JSON object\" };\n }\n return { variables: parsed as Record<string, unknown> };\n } catch (error) {\n return { error: errorMessage(error, \"invalid JSON\") };\n }\n}\n\nexport function pageTabs(options: {\n canPreview: boolean;\n canDiff: boolean;\n extraTabs?: PromptPageTab[] | undefined;\n}): TabItem[] {\n const tabs: TabItem[] = [{ id: PROMPT_PAGE_TAB.prompt, label: \"Prompt\" }];\n if (options.canPreview)\n tabs.push({ id: PROMPT_PAGE_TAB.preview, label: \"Preview\" });\n if (options.canDiff)\n tabs.push({ id: PROMPT_PAGE_TAB.diff, label: \"Diff vs default\" });\n for (const tab of options.extraTabs ?? []) {\n tabs.push({\n id: tab.id,\n label: tab.label,\n ...(tab.count !== undefined ? { count: tab.count } : {}),\n });\n }\n return tabs;\n}\n"],"mappings":"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"}
@@ -23,6 +23,7 @@ export interface PromptCatalogLayer {
23
23
  source: "none" | "inline" | "file";
24
24
  filePath?: string | undefined;
25
25
  fields?: string[] | undefined;
26
+ saveSources?: Array<"inline" | "file"> | undefined;
26
27
  }
27
28
  export interface PromptCatalogRuntime {
28
29
  model?: string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/data/ai/PromptCatalog/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/data/ai/PromptCatalog/types.ts"],"names":[],"mappings":"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"}
@@ -16,4 +16,11 @@ export { TraceWindowList, type TraceWindow, type TraceWindowListProps, type Trac
16
16
  export { buildProcessForest, flattenForest, formatCpuPercent, formatProcessTimestamp, isProcessExited, processLifetimeMs, processSeries, pruneExitedProcesses, type ProcessTreeNode, } from './process-tree.js';
17
17
  export { LabeledSparkline, type LabeledSparklineProps } from './Sparkline.js';
18
18
  export type { HttpExchangeRequest, HttpExchangeResponse, GoProfileRecord, HttpExchangeRow, ProcessDescriptor, ProcessEnv, ProcessNodeRow, ProcessSampleFacet, ProcessSampleRow, ProcessStackTransport, ProfileSample, SqlStatementRow, StackFormat, StackFrame, StackRecord, TerminalEvent, TerminalEventKind, TraceBodyText, TraceRow, } from './types.js';
19
+ export { OtelTraceDetail } from './otel/OtelTraceDetail.js';
20
+ export { OtelTraceSearch } from './otel/OtelTraceSearch.js';
21
+ export { OtelTraceTable, type OtelTraceTableProps } from './otel/OtelTraceTable.js';
22
+ export { searchParams as otelSearchParams, readSearchValues as readOtelSearchValues } from './otel/api.js';
23
+ export { durationOf as otelDurationOf } from './otel/query.js';
24
+ export type { Span as OtelSpan, Summary as OtelSummary, SearchForm as OtelSearchForm } from './otel/api.js';
25
+ export type { Trace as OtelTrace, SearchValues as OtelSearchValues, SearchResult as OtelSearchResult, Source as OtelSource } from './otel/api.js';
19
26
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/data/traces/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,MAAM,eAAe,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3F,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,KAAK,kBAAkB,EAAE,KAAK,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACrH,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACb,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,gBAAgB,GACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,WAAW,EACX,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,KAAK,YAAY,GAClB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EACL,eAAe,EACf,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,oBAAoB,EACpB,KAAK,eAAe,GACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAC3E,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,EACrB,aAAa,EACb,eAAe,EACf,WAAW,EACX,UAAU,EACV,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,QAAQ,GACT,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/data/traces/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ const require_api = require("./api.cjs");
2
+ const require_query = require("./query.cjs");
3
+ let react_jsx_runtime = require("react/jsx-runtime");
4
+ // src/data/traces/otel/OperationList.tsx
5
+ /** The root operations of the window with their counts and p50/p95; choosing one filters to it, "All operations" clears it. */
6
+ function OperationList({ stats, selected, onSelect, hideSingle }) {
7
+ const total = stats.reduce((sum, stat) => sum + stat.count, 0);
8
+ const item = (operation, label, body, dim = false) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
9
+ type: "button",
10
+ "aria-pressed": selected === operation,
11
+ onClick: () => onSelect(operation),
12
+ className: `w-full rounded-md px-density-2 py-1.5 text-left text-xs ${selected === operation ? "bg-accent" : "hover:bg-muted"} ${dim ? "opacity-50" : ""}`,
13
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
14
+ className: "block truncate text-sm font-medium",
15
+ title: operation || label,
16
+ children: label
17
+ }), body]
18
+ }) }, operation || "all");
19
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
20
+ className: "min-w-0 space-y-2 rounded-lg border border-border p-density-2",
21
+ children: [
22
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
23
+ className: "px-density-2 text-xs font-medium uppercase tracking-wide text-muted-foreground",
24
+ children: "Root operations"
25
+ }),
26
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
27
+ className: "space-y-0.5",
28
+ children: [item("", "All operations", /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
29
+ className: "text-muted-foreground",
30
+ children: [
31
+ total.toLocaleString(),
32
+ " ",
33
+ total === 1 ? "trace" : "traces"
34
+ ]
35
+ })), stats.map((stat) => item(stat.operation, require_query.shortOperation(stat.operation), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
36
+ className: "flex items-center gap-1.5 text-muted-foreground",
37
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
38
+ className: "tabular-nums",
39
+ children: [
40
+ stat.count.toLocaleString(),
41
+ " ",
42
+ stat.singleSpan ? "single-span" : stat.count === 1 ? "trace" : "traces"
43
+ ]
44
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
45
+ className: "ml-auto tabular-nums",
46
+ children: [
47
+ "p50 ",
48
+ require_api.duration(stat.p50Ms),
49
+ " · p95 ",
50
+ require_api.duration(stat.p95Ms)
51
+ ]
52
+ })]
53
+ }), hideSingle && stat.singleSpan))]
54
+ }),
55
+ hideSingle && stats.some((stat) => stat.singleSpan) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
56
+ className: "px-density-2 text-xs text-muted-foreground",
57
+ children: "Single-span operations are dimmed while single-span traces are hidden."
58
+ })
59
+ ]
60
+ });
61
+ }
62
+ exports.OperationList = OperationList;
63
+
64
+ //# sourceMappingURL=OperationList.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OperationList.cjs","names":["shortOperation","duration"],"sources":["../../../../src/data/traces/otel/OperationList.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { duration, type OperationStats } from \"./api\";\nimport { shortOperation } from \"./query\";\n\n/** The root operations of the window with their counts and p50/p95; choosing one filters to it, \"All operations\" clears it. */\nexport function OperationList({ stats, selected, onSelect, hideSingle }: {\n stats: OperationStats[];\n /** The one root operation included, \"\" for none, undefined for any other selection. */\n selected: string | undefined;\n onSelect: (operation: string) => void;\n hideSingle: boolean;\n}) {\n const total = stats.reduce((sum, stat) => sum + stat.count, 0);\n const item = (operation: string, label: string, body: ReactNode, dim = false) => (\n <li key={operation || \"all\"}>\n <button\n type=\"button\"\n aria-pressed={selected === operation}\n onClick={() => onSelect(operation)}\n className={`w-full rounded-md px-density-2 py-1.5 text-left text-xs ${selected === operation ? \"bg-accent\" : \"hover:bg-muted\"} ${dim ? \"opacity-50\" : \"\"}`}\n >\n <span className=\"block truncate text-sm font-medium\" title={operation || label}>{label}</span>\n {body}\n </button>\n </li>\n );\n return (\n <aside className=\"min-w-0 space-y-2 rounded-lg border border-border p-density-2\">\n <h3 className=\"px-density-2 text-xs font-medium uppercase tracking-wide text-muted-foreground\">Root operations</h3>\n <ul className=\"space-y-0.5\">\n {item(\"\", \"All operations\", <span className=\"text-muted-foreground\">{total.toLocaleString()} {total === 1 ? \"trace\" : \"traces\"}</span>)}\n {stats.map(stat => item(stat.operation, shortOperation(stat.operation), (\n <span className=\"flex items-center gap-1.5 text-muted-foreground\">\n <span className=\"tabular-nums\">{stat.count.toLocaleString()} {stat.singleSpan ? \"single-span\" : stat.count === 1 ? \"trace\" : \"traces\"}</span>\n <span className=\"ml-auto tabular-nums\">p50 {duration(stat.p50Ms)} · p95 {duration(stat.p95Ms)}</span>\n </span>\n ), hideSingle && stat.singleSpan))}\n </ul>\n {hideSingle && stats.some(stat => stat.singleSpan) && (\n <p className=\"px-density-2 text-xs text-muted-foreground\">Single-span operations are dimmed while single-span traces are hidden.</p>\n )}\n </aside>\n );\n}\n"],"mappings":";;;;;AAKA,SAAgB,cAAc,EAAE,OAAO,UAAU,UAAU,cAMxD;CACD,MAAM,QAAQ,MAAM,QAAQ,KAAK,SAAS,MAAM,KAAK,OAAO,CAAC;CAC7D,MAAM,QAAQ,WAAmB,OAAe,MAAiB,MAAM,UACrE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD,EAAA,UACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;EACE,MAAK;EACL,gBAAc,aAAa;EAC3B,eAAe,SAAS,SAAS;EACjC,WAAW,2DAA2D,aAAa,YAAY,cAAc,iBAAiB,GAAG,MAAM,eAAe;EAJxJ,UAAA,CAME,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;GAAM,WAAU;GAAqC,OAAO,aAAa;GAAQ,UAAA;EAAY,CAAA,GAC5F,IACK;CACN,CAAA,EAAA,GAVK,aAAa,KAUlB;CAEN,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;EAAO,WAAU;EAAjB,UAAA;GACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;IAAI,WAAU;IAAiF,UAAA;GAAmB,CAAA;GAClH,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD;IAAI,WAAU;IAAd,UAAA,CACG,KAAK,IAAI,kBAAkB,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;KAAM,WAAU;KAAhB,UAAA;MAAyC,MAAM,eAAe;MAAE;MAAE,UAAU,IAAI,UAAU;KAAe;IAAC,CAAA,CAAA,GACrI,MAAM,KAAI,SAAQ,KAAK,KAAK,WAAWA,cAAAA,eAAe,KAAK,SAAS,GACnE,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;KAAM,WAAU;KAAhB,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;MAAM,WAAU;MAAhB,UAAA;OAAgC,KAAK,MAAM,eAAe;OAAE;OAAE,KAAK,aAAa,gBAAgB,KAAK,UAAU,IAAI,UAAU;MAAe;KAC5I,CAAA,GAAA,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;MAAM,WAAU;MAAhB,UAAA;OAAuC;OAAKC,YAAAA,SAAS,KAAK,KAAK;OAAE;OAAQA,YAAAA,SAAS,KAAK,KAAK;MAAQ;KAChG,CAAA,CAAA;IACL,CAAA,GAAA,cAAc,KAAK,UAAU,CAAC,CAC/B;;GACH,cAAc,MAAM,MAAK,SAAQ,KAAK,UAAU,KAC/C,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;IAAG,WAAU;IAA6C,UAAA;GAAyE,CAAA;EAEhI;;AAEX"}