@flanksource/clicky-ui 0.3.35 → 0.3.36

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 (111) hide show
  1. package/dist/ai.cjs +2 -1
  2. package/dist/ai.cjs.map +1 -1
  3. package/dist/ai.js +2 -1
  4. package/dist/ai.js.map +1 -1
  5. package/dist/data/TaskHeaderExtras.cjs +35 -0
  6. package/dist/data/TaskHeaderExtras.cjs.map +1 -0
  7. package/dist/data/TaskHeaderExtras.d.ts +27 -0
  8. package/dist/data/TaskHeaderExtras.d.ts.map +1 -0
  9. package/dist/data/TaskHeaderExtras.js +35 -0
  10. package/dist/data/TaskHeaderExtras.js.map +1 -0
  11. package/dist/data/TaskManager.cjs +18 -6
  12. package/dist/data/TaskManager.cjs.map +1 -1
  13. package/dist/data/TaskManager.d.ts +13 -1
  14. package/dist/data/TaskManager.d.ts.map +1 -1
  15. package/dist/data/TaskManager.js +18 -6
  16. package/dist/data/TaskManager.js.map +1 -1
  17. package/dist/data/TaskProcessDetails.cjs +4 -1
  18. package/dist/data/TaskProcessDetails.cjs.map +1 -1
  19. package/dist/data/TaskProcessDetails.d.ts.map +1 -1
  20. package/dist/data/TaskProcessDetails.js +4 -1
  21. package/dist/data/TaskProcessDetails.js.map +1 -1
  22. package/dist/data/TaskProcessMetadata.cjs +50 -0
  23. package/dist/data/TaskProcessMetadata.cjs.map +1 -0
  24. package/dist/data/TaskProcessMetadata.d.ts +20 -0
  25. package/dist/data/TaskProcessMetadata.d.ts.map +1 -0
  26. package/dist/data/TaskProcessMetadata.js +50 -0
  27. package/dist/data/TaskProcessMetadata.js.map +1 -0
  28. package/dist/data/TaskProgress.cjs +22 -31
  29. package/dist/data/TaskProgress.cjs.map +1 -1
  30. package/dist/data/TaskProgress.d.ts +14 -1
  31. package/dist/data/TaskProgress.d.ts.map +1 -1
  32. package/dist/data/TaskProgress.js +22 -31
  33. package/dist/data/TaskProgress.js.map +1 -1
  34. package/dist/data/TaskSnapshot.cjs.map +1 -1
  35. package/dist/data/TaskSnapshot.d.ts +22 -0
  36. package/dist/data/TaskSnapshot.d.ts.map +1 -1
  37. package/dist/data/TaskSnapshot.js.map +1 -1
  38. package/dist/data/TaskStreamTabs.cjs +78 -0
  39. package/dist/data/TaskStreamTabs.cjs.map +1 -0
  40. package/dist/data/TaskStreamTabs.d.ts +35 -0
  41. package/dist/data/TaskStreamTabs.d.ts.map +1 -0
  42. package/dist/data/TaskStreamTabs.js +78 -0
  43. package/dist/data/TaskStreamTabs.js.map +1 -0
  44. package/dist/data/ai/SessionInspector.approvals-model.cjs +9 -0
  45. package/dist/data/ai/SessionInspector.approvals-model.cjs.map +1 -0
  46. package/dist/data/ai/SessionInspector.approvals-model.d.ts +17 -0
  47. package/dist/data/ai/SessionInspector.approvals-model.d.ts.map +1 -0
  48. package/dist/data/ai/SessionInspector.approvals-model.js +9 -0
  49. package/dist/data/ai/SessionInspector.approvals-model.js.map +1 -0
  50. package/dist/data/ai/SessionInspector.approvals.cjs +7 -11
  51. package/dist/data/ai/SessionInspector.approvals.cjs.map +1 -1
  52. package/dist/data/ai/SessionInspector.approvals.d.ts +2 -10
  53. package/dist/data/ai/SessionInspector.approvals.d.ts.map +1 -1
  54. package/dist/data/ai/SessionInspector.approvals.js +4 -8
  55. package/dist/data/ai/SessionInspector.approvals.js.map +1 -1
  56. package/dist/data/ai/SessionInspector.cjs +2 -2
  57. package/dist/data/ai/SessionInspector.cjs.map +1 -1
  58. package/dist/data/ai/SessionInspector.d.ts +1 -1
  59. package/dist/data/ai/SessionInspector.d.ts.map +1 -1
  60. package/dist/data/ai/SessionInspector.js +1 -1
  61. package/dist/data/ai/SessionInspector.js.map +1 -1
  62. package/dist/data/ai/SessionInspector.panel-parts.cjs +0 -13
  63. package/dist/data/ai/SessionInspector.panel-parts.cjs.map +1 -1
  64. package/dist/data/ai/SessionInspector.panel-parts.d.ts +4 -5
  65. package/dist/data/ai/SessionInspector.panel-parts.d.ts.map +1 -1
  66. package/dist/data/ai/SessionInspector.panel-parts.js +1 -14
  67. package/dist/data/ai/SessionInspector.panel-parts.js.map +1 -1
  68. package/dist/data/ai/SessionInspector.panel-values.cjs +18 -0
  69. package/dist/data/ai/SessionInspector.panel-values.cjs.map +1 -0
  70. package/dist/data/ai/SessionInspector.panel-values.d.ts +13 -0
  71. package/dist/data/ai/SessionInspector.panel-values.d.ts.map +1 -0
  72. package/dist/data/ai/SessionInspector.panel-values.js +18 -0
  73. package/dist/data/ai/SessionInspector.panel-values.js.map +1 -0
  74. package/dist/data/ai/SessionInspector.panels.cjs +27 -26
  75. package/dist/data/ai/SessionInspector.panels.cjs.map +1 -1
  76. package/dist/data/ai/SessionInspector.panels.d.ts.map +1 -1
  77. package/dist/data/ai/SessionInspector.panels.js +2 -1
  78. package/dist/data/ai/SessionInspector.panels.js.map +1 -1
  79. package/dist/data/ai/index.d.ts +2 -1
  80. package/dist/data/ai/index.d.ts.map +1 -1
  81. package/dist/data/task-metadata.cjs +36 -0
  82. package/dist/data/task-metadata.cjs.map +1 -0
  83. package/dist/data/task-metadata.d.ts +39 -0
  84. package/dist/data/task-metadata.d.ts.map +1 -0
  85. package/dist/data/task-metadata.js +36 -0
  86. package/dist/data/task-metadata.js.map +1 -0
  87. package/dist/data/task-streams.cjs +39 -0
  88. package/dist/data/task-streams.cjs.map +1 -0
  89. package/dist/data/task-streams.d.ts +60 -0
  90. package/dist/data/task-streams.d.ts.map +1 -0
  91. package/dist/data/task-streams.js +39 -0
  92. package/dist/data/task-streams.js.map +1 -0
  93. package/dist/data/version-info.cjs +3 -3
  94. package/dist/data/version-info.js +3 -3
  95. package/dist/data.cjs +14 -0
  96. package/dist/data.cjs.map +1 -1
  97. package/dist/data.d.ts +6 -1
  98. package/dist/data.d.ts.map +1 -1
  99. package/dist/data.js +14 -0
  100. package/dist/data.js.map +1 -1
  101. package/dist/hooks/use-task-run.cjs +13 -15
  102. package/dist/hooks/use-task-run.cjs.map +1 -1
  103. package/dist/hooks/use-task-run.d.ts.map +1 -1
  104. package/dist/hooks/use-task-run.js +14 -16
  105. package/dist/hooks/use-task-run.js.map +1 -1
  106. package/dist/index.cjs +14 -0
  107. package/dist/index.cjs.map +1 -1
  108. package/dist/index.js +14 -0
  109. package/dist/index.js.map +1 -1
  110. package/dist/styles.css +1 -1
  111. package/package.json +1 -1
@@ -0,0 +1,17 @@
1
+ import { SessionApprovalRequest } from './SessionViewer.unified';
2
+ /** Approve or deny one pending approval. */
3
+ export type ApprovalResolveAction = "approve" | "deny";
4
+ /** Resolves one `session.requests[]` row. Rejecting surfaces the server's
5
+ * refusal text inline on that row (e.g. the prompt run is no longer
6
+ * `waiting`) instead of leaving the Approve/Deny buttons silently inert. */
7
+ export type ApprovalResolveHandler = (approvalId: string, action: ApprovalResolveAction, message?: string) => void | Promise<void>;
8
+ /** The subset of `session.requests[]` the approvals panel surfaces: outstanding
9
+ * tool approvals, regardless of which surface (in-process chat or an external
10
+ * broker) created the request.
11
+ *
12
+ * It lives here rather than beside the panel because it is a selector, not a
13
+ * component, and a module that exports both loses fast refresh for everything
14
+ * in it. Its other caller — the SessionInspector tab badge — only ever wanted
15
+ * the count anyway. */
16
+ export declare function pendingApprovalRequests(requests: SessionApprovalRequest[] | undefined): SessionApprovalRequest[];
17
+ //# sourceMappingURL=SessionInspector.approvals-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionInspector.approvals-model.d.ts","sourceRoot":"","sources":["../../../src/data/ai/SessionInspector.approvals-model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEtE,4CAA4C;AAC5C,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,MAAM,CAAC;AAEvD;;6EAE6E;AAC7E,MAAM,MAAM,sBAAsB,GAAG,CACnC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,qBAAqB,EAC7B,OAAO,CAAC,EAAE,MAAM,KACb,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B;;;;;;;wBAOwB;AACxB,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,sBAAsB,EAAE,GAAG,SAAS,GAC7C,sBAAsB,EAAE,CAI1B"}
@@ -0,0 +1,9 @@
1
+ function pendingApprovalRequests(requests) {
2
+ return (requests ?? []).filter(
3
+ (request) => request.state === "pending" && request.kind === "tool_approval"
4
+ );
5
+ }
6
+ export {
7
+ pendingApprovalRequests
8
+ };
9
+ //# sourceMappingURL=SessionInspector.approvals-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionInspector.approvals-model.js","sources":["../../../src/data/ai/SessionInspector.approvals-model.ts"],"sourcesContent":["import type { SessionApprovalRequest } from \"./SessionViewer.unified\";\n\n/** Approve or deny one pending approval. */\nexport type ApprovalResolveAction = \"approve\" | \"deny\";\n\n/** Resolves one `session.requests[]` row. Rejecting surfaces the server's\n * refusal text inline on that row (e.g. the prompt run is no longer\n * `waiting`) instead of leaving the Approve/Deny buttons silently inert. */\nexport type ApprovalResolveHandler = (\n approvalId: string,\n action: ApprovalResolveAction,\n message?: string,\n) => void | Promise<void>;\n\n/** The subset of `session.requests[]` the approvals panel surfaces: outstanding\n * tool approvals, regardless of which surface (in-process chat or an external\n * broker) created the request.\n *\n * It lives here rather than beside the panel because it is a selector, not a\n * component, and a module that exports both loses fast refresh for everything\n * in it. Its other caller — the SessionInspector tab badge — only ever wanted\n * the count anyway. */\nexport function pendingApprovalRequests(\n requests: SessionApprovalRequest[] | undefined,\n): SessionApprovalRequest[] {\n return (requests ?? []).filter(\n (request) => request.state === \"pending\" && request.kind === \"tool_approval\",\n );\n}\n"],"names":[],"mappings":"AAsBO,SAAS,wBACd,UAC0B;AAC1B,UAAQ,YAAY,CAAA,GAAI;AAAA,IACtB,CAAC,YAAY,QAAQ,UAAU,aAAa,QAAQ,SAAS;AAAA,EAAA;AAEjE;"}
@@ -7,19 +7,16 @@ const Icon = require("../Icon.cjs");
7
7
  const ToolCall = require("../chat/ToolCall.cjs");
8
8
  const SessionInspector_model = require("./SessionInspector.model.cjs");
9
9
  const SessionInspector_panelParts = require("./SessionInspector.panel-parts.cjs");
10
+ const SessionInspector_panelValues = require("./SessionInspector.panel-values.cjs");
11
+ const SessionInspector_approvalsModel = require("./SessionInspector.approvals-model.cjs");
10
12
  const UiClock = require("../../icons/components/UiClock.cjs");
11
- function pendingApprovalRequests(requests) {
12
- return (requests ?? []).filter(
13
- (request) => request.state === "pending" && request.kind === "tool_approval"
14
- );
15
- }
16
13
  function SessionApprovalsPanel({
17
14
  approvals,
18
15
  requests,
19
16
  onResolve
20
17
  }) {
21
18
  var _a;
22
- const pending = pendingApprovalRequests(requests);
19
+ const pending = SessionInspector_approvalsModel.pendingApprovalRequests(requests);
23
20
  const hasResolvedSummary = Boolean(
24
21
  approvals && (approvals.approved || approvals.denied || approvals.cancelled || approvals.expired || ((_a = approvals.denials) == null ? void 0 : _a.length))
25
22
  );
@@ -46,10 +43,10 @@ function ResolvedApprovalsSummary({
46
43
  KeyValueList.KeyValueList,
47
44
  {
48
45
  items: [
49
- SessionInspector_panelParts.kv("Approved", approvals.approved ?? 0),
50
- SessionInspector_panelParts.kv("Denied", approvals.denied ?? 0),
51
- SessionInspector_panelParts.kv("Cancelled", approvals.cancelled ?? 0),
52
- SessionInspector_panelParts.kv("Expired", approvals.expired ?? 0)
46
+ SessionInspector_panelValues.kv("Approved", approvals.approved ?? 0),
47
+ SessionInspector_panelValues.kv("Denied", approvals.denied ?? 0),
48
+ SessionInspector_panelValues.kv("Cancelled", approvals.cancelled ?? 0),
49
+ SessionInspector_panelValues.kv("Expired", approvals.expired ?? 0)
53
50
  ]
54
51
  }
55
52
  ),
@@ -143,5 +140,4 @@ function remainingLabel(expiresAt) {
143
140
  return label ? `${label} left` : "";
144
141
  }
145
142
  exports.SessionApprovalsPanel = SessionApprovalsPanel;
146
- exports.pendingApprovalRequests = pendingApprovalRequests;
147
143
  //# sourceMappingURL=SessionInspector.approvals.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"SessionInspector.approvals.cjs","sources":["../../../src/data/ai/SessionInspector.approvals.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { KeyValueList } from \"../KeyValueList\";\nimport { Icon } from \"../Icon\";\nimport { UiClock } from \"../../icons\";\nimport { ToolCall } from \"../chat/ToolCall\";\nimport type { AnyToolPart } from \"../chat/types\";\nimport { durationLabel, formatDate } from \"./SessionInspector.model\";\nimport { EmptyState, SimpleList, kv } from \"./SessionInspector.panel-parts\";\nimport type {\n SessionApprovalRequest,\n SessionApprovalStats,\n} from \"./SessionViewer.unified\";\n\n/** Approve or deny one pending approval. */\nexport type ApprovalResolveAction = \"approve\" | \"deny\";\n\n/** Resolves one `session.requests[]` row. Rejecting surfaces the server's\n * refusal text inline on that row (e.g. the prompt run is no longer\n * `waiting`) instead of leaving the Approve/Deny buttons silently inert. */\nexport type ApprovalResolveHandler = (\n approvalId: string,\n action: ApprovalResolveAction,\n message?: string,\n) => void | Promise<void>;\n\n/** The subset of `session.requests[]` this panel surfaces: outstanding tool\n * approvals, regardless of which surface (in-process chat or an external\n * broker) created the request. */\nexport function pendingApprovalRequests(\n requests: SessionApprovalRequest[] | undefined,\n): SessionApprovalRequest[] {\n return (requests ?? []).filter(\n (request) => request.state === \"pending\" && request.kind === \"tool_approval\",\n );\n}\n\n/** Renders every pending tool approval directly from `session.requests[]`\n * (never from transcript parts — an approval brokered outside this session's\n * own chat has no transcript part) plus the resolved approve/deny/denial\n * summary the panel previously showed alone. */\nexport function SessionApprovalsPanel({\n approvals,\n requests,\n onResolve,\n}: {\n approvals: SessionApprovalStats | undefined;\n requests?: SessionApprovalRequest[] | undefined;\n onResolve?: ApprovalResolveHandler;\n}) {\n const pending = pendingApprovalRequests(requests);\n const hasResolvedSummary = Boolean(\n approvals &&\n (approvals.approved ||\n approvals.denied ||\n approvals.cancelled ||\n approvals.expired ||\n approvals.denials?.length),\n );\n\n if (!pending.length && !hasResolvedSummary) {\n return <EmptyState>No approval metadata.</EmptyState>;\n }\n\n return (\n <div className=\"space-y-density-4\">\n {pending.length ? (\n <PendingApprovalsList\n requests={pending}\n {...(onResolve ? { onResolve } : {})}\n />\n ) : null}\n {hasResolvedSummary ? (\n <ResolvedApprovalsSummary approvals={approvals!} />\n ) : null}\n </div>\n );\n}\n\nfunction ResolvedApprovalsSummary({\n approvals,\n}: {\n approvals: SessionApprovalStats;\n}) {\n return (\n <div className=\"space-y-density-4\">\n <KeyValueList\n items={[\n kv(\"Approved\", approvals.approved ?? 0),\n kv(\"Denied\", approvals.denied ?? 0),\n kv(\"Cancelled\", approvals.cancelled ?? 0),\n kv(\"Expired\", approvals.expired ?? 0),\n ]}\n />\n {approvals.denials?.length ? (\n <SimpleList\n title=\"Denials\"\n rows={approvals.denials.map((denial, index) => ({\n key: denial.toolUseId || `${denial.tool}-${index}`,\n title: [denial.tool, denial.toolUseId].filter(Boolean).join(\" \"),\n detail: denial.reason,\n }))}\n />\n ) : null}\n </div>\n );\n}\n\nfunction PendingApprovalsList({\n requests,\n onResolve,\n}: {\n requests: SessionApprovalRequest[];\n onResolve?: ApprovalResolveHandler;\n}) {\n return (\n <section>\n <h3 className=\"mb-density-2 flex items-center gap-1.5 text-xs font-semibold uppercase text-amber-600 dark:text-amber-400\">\n <Icon icon={UiClock} className=\"size-3.5\" />\n Awaiting approval ({requests.length})\n </h3>\n <ul className=\"space-y-density-2\">\n {requests.map((request) => (\n <li key={request.id}>\n <PendingApprovalRow\n request={request}\n {...(onResolve ? { onResolve } : {})}\n />\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\nfunction PendingApprovalRow({\n request,\n onResolve,\n}: {\n request: SessionApprovalRequest;\n onResolve?: ApprovalResolveHandler;\n}) {\n const [error, setError] = useState<string | undefined>(undefined);\n const [busy, setBusy] = useState(false);\n\n const part: AnyToolPart = {\n type: \"dynamic-tool\",\n toolName: request.tool,\n toolCallId: request.toolCallId || request.id,\n state: \"approval-requested\",\n input: request.input,\n approval: { id: request.id },\n };\n\n const handleApprove = (\n approvalId: string,\n approved: boolean,\n reason?: string,\n ) => {\n if (!onResolve) return;\n setError(undefined);\n setBusy(true);\n void Promise.resolve(onResolve(approvalId, approved ? \"approve\" : \"deny\", reason))\n .catch((err: unknown) => {\n setError(err instanceof Error ? err.message : String(err));\n })\n .finally(() => setBusy(false));\n };\n\n return (\n <div className=\"rounded-md border border-amber-300/60 bg-amber-50/40 p-density-3 dark:border-amber-800/60 dark:bg-amber-950/20\">\n <div className=\"mb-1 flex flex-wrap items-center justify-between gap-2 text-[11px] text-muted-foreground\">\n <span>\n {request.requestedBy\n ? `Requested by ${request.requestedBy}`\n : \"Requested\"}\n </span>\n <span className=\"flex gap-density-3\">\n {request.createdAt ? (\n <span title={formatDate(request.createdAt)}>\n {ageLabel(request.createdAt)} ago\n </span>\n ) : null}\n {request.expiresAt ? (\n <span title={formatDate(request.expiresAt)}>\n {remainingLabel(request.expiresAt)}\n </span>\n ) : null}\n </span>\n </div>\n <ToolCall\n part={part}\n defaultOpen\n onApprove={busy ? undefined : handleApprove}\n />\n {busy ? (\n <p className=\"mt-1.5 pl-4 text-xs text-muted-foreground\">\n Submitting…\n </p>\n ) : null}\n {error ? (\n <p role=\"alert\" className=\"mt-1.5 pl-4 text-xs text-destructive\">\n {error}\n </p>\n ) : null}\n </div>\n );\n}\n\nfunction ageLabel(createdAt: string): string {\n return durationLabel(createdAt) || \"0s\";\n}\n\nfunction remainingLabel(expiresAt: string): string {\n const expiry = new Date(expiresAt).getTime();\n if (Number.isNaN(expiry)) return \"\";\n const now = Date.now();\n if (expiry <= now) return \"expired\";\n const label = durationLabel(new Date(now).toISOString(), expiresAt);\n return label ? `${label} left` : \"\";\n}\n"],"names":["jsx","EmptyState","jsxs","KeyValueList","kv","SimpleList","Icon","UiClock","useState","formatDate","ToolCall","durationLabel"],"mappings":";;;;;;;;;;AA4BO,SAAS,wBACd,UAC0B;AAC1B,UAAQ,YAAY,CAAA,GAAI;AAAA,IACtB,CAAC,YAAY,QAAQ,UAAU,aAAa,QAAQ,SAAS;AAAA,EAAA;AAEjE;AAMO,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AACF,GAIG;;AACD,QAAM,UAAU,wBAAwB,QAAQ;AAChD,QAAM,qBAAqB;AAAA,IACzB,cACG,UAAU,YACT,UAAU,UACV,UAAU,aACV,UAAU,aACV,eAAU,YAAV,mBAAmB;AAAA,EAAA;AAGzB,MAAI,CAAC,QAAQ,UAAU,CAAC,oBAAoB;AAC1C,WAAOA,2BAAAA,IAACC,4BAAAA,cAAW,UAAA,wBAAA,CAAqB;AAAA,EAC1C;AAEA,SACEC,2BAAAA,KAAC,OAAA,EAAI,WAAU,qBACZ,UAAA;AAAA,IAAA,QAAQ,SACPF,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,UAAU;AAAA,QACT,GAAI,YAAY,EAAE,cAAc,CAAA;AAAA,MAAC;AAAA,IAAA,IAElC;AAAA,IACH,qBACCA,2BAAAA,IAAC,0BAAA,EAAyB,UAAA,CAAuB,IAC/C;AAAA,EAAA,GACN;AAEJ;AAEA,SAAS,yBAAyB;AAAA,EAChC;AACF,GAEG;;AACD,SACEE,2BAAAA,KAAC,OAAA,EAAI,WAAU,qBACb,UAAA;AAAA,IAAAF,2BAAAA;AAAAA,MAACG,aAAAA;AAAAA,MAAA;AAAA,QACC,OAAO;AAAA,UACLC,4BAAAA,GAAG,YAAY,UAAU,YAAY,CAAC;AAAA,UACtCA,4BAAAA,GAAG,UAAU,UAAU,UAAU,CAAC;AAAA,UAClCA,4BAAAA,GAAG,aAAa,UAAU,aAAa,CAAC;AAAA,UACxCA,4BAAAA,GAAG,WAAW,UAAU,WAAW,CAAC;AAAA,QAAA;AAAA,MACtC;AAAA,IAAA;AAAA,MAED,eAAU,YAAV,mBAAmB,UAClBJ,2BAAAA;AAAAA,MAACK,4BAAAA;AAAAA,MAAA;AAAA,QACC,OAAM;AAAA,QACN,MAAM,UAAU,QAAQ,IAAI,CAAC,QAAQ,WAAW;AAAA,UAC9C,KAAK,OAAO,aAAa,GAAG,OAAO,IAAI,IAAI,KAAK;AAAA,UAChD,OAAO,CAAC,OAAO,MAAM,OAAO,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,UAC/D,QAAQ,OAAO;AAAA,QAAA,EACf;AAAA,MAAA;AAAA,IAAA,IAEF;AAAA,EAAA,GACN;AAEJ;AAEA,SAAS,qBAAqB;AAAA,EAC5B;AAAA,EACA;AACF,GAGG;AACD,yCACG,WAAA,EACC,UAAA;AAAA,IAAAH,2BAAAA,KAAC,MAAA,EAAG,WAAU,6GACZ,UAAA;AAAA,MAAAF,2BAAAA,IAACM,KAAAA,MAAA,EAAK,MAAMC,QAAAA,SAAS,WAAU,YAAW;AAAA,MAAE;AAAA,MACxB,SAAS;AAAA,MAAO;AAAA,IAAA,GACtC;AAAA,IACAP,2BAAAA,IAAC,QAAG,WAAU,qBACX,mBAAS,IAAI,CAAC,YACbA,2BAAAA,IAAC,MAAA,EACC,UAAAA,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACC,GAAI,YAAY,EAAE,cAAc,CAAA;AAAA,MAAC;AAAA,IAAA,KAH7B,QAAQ,EAKjB,CACD,EAAA,CACH;AAAA,EAAA,GACF;AAEJ;AAEA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AACF,GAGG;AACD,QAAM,CAAC,OAAO,QAAQ,IAAIQ,MAAAA,SAA6B,MAAS;AAChE,QAAM,CAAC,MAAM,OAAO,IAAIA,MAAAA,SAAS,KAAK;AAEtC,QAAM,OAAoB;AAAA,IACxB,MAAM;AAAA,IACN,UAAU,QAAQ;AAAA,IAClB,YAAY,QAAQ,cAAc,QAAQ;AAAA,IAC1C,OAAO;AAAA,IACP,OAAO,QAAQ;AAAA,IACf,UAAU,EAAE,IAAI,QAAQ,GAAA;AAAA,EAAG;AAG7B,QAAM,gBAAgB,CACpB,YACA,UACA,WACG;AACH,QAAI,CAAC,UAAW;AAChB,aAAS,MAAS;AAClB,YAAQ,IAAI;AACZ,SAAK,QAAQ,QAAQ,UAAU,YAAY,WAAW,YAAY,QAAQ,MAAM,CAAC,EAC9E,MAAM,CAAC,QAAiB;AACvB,eAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAC3D,CAAC,EACA,QAAQ,MAAM,QAAQ,KAAK,CAAC;AAAA,EACjC;AAEA,SACEN,2BAAAA,KAAC,OAAA,EAAI,WAAU,kHACb,UAAA;AAAA,IAAAA,2BAAAA,KAAC,OAAA,EAAI,WAAU,4FACb,UAAA;AAAA,MAAAF,2BAAAA,IAAC,UACE,UAAA,QAAQ,cACL,gBAAgB,QAAQ,WAAW,KACnC,YAAA,CACN;AAAA,MACAE,2BAAAA,KAAC,QAAA,EAAK,WAAU,sBACb,UAAA;AAAA,QAAA,QAAQ,YACPA,2BAAAA,KAAC,QAAA,EAAK,OAAOO,uBAAAA,WAAW,QAAQ,SAAS,GACtC,UAAA;AAAA,UAAA,SAAS,QAAQ,SAAS;AAAA,UAAE;AAAA,QAAA,EAAA,CAC/B,IACE;AAAA,QACH,QAAQ,YACPT,2BAAAA,IAAC,QAAA,EAAK,OAAOS,uBAAAA,WAAW,QAAQ,SAAS,GACtC,UAAA,eAAe,QAAQ,SAAS,GACnC,IACE;AAAA,MAAA,EAAA,CACN;AAAA,IAAA,GACF;AAAA,IACAT,2BAAAA;AAAAA,MAACU,SAAAA;AAAAA,MAAA;AAAA,QACC;AAAA,QACA,aAAW;AAAA,QACX,WAAW,OAAO,SAAY;AAAA,MAAA;AAAA,IAAA;AAAA,IAE/B,OACCV,2BAAAA,IAAC,KAAA,EAAE,WAAU,6CAA4C,yBAEzD,IACE;AAAA,IACH,uCACE,KAAA,EAAE,MAAK,SAAQ,WAAU,wCACvB,iBACH,IACE;AAAA,EAAA,GACN;AAEJ;AAEA,SAAS,SAAS,WAA2B;AAC3C,SAAOW,uBAAAA,cAAc,SAAS,KAAK;AACrC;AAEA,SAAS,eAAe,WAA2B;AACjD,QAAM,SAAS,IAAI,KAAK,SAAS,EAAE,QAAA;AACnC,MAAI,OAAO,MAAM,MAAM,EAAG,QAAO;AACjC,QAAM,MAAM,KAAK,IAAA;AACjB,MAAI,UAAU,IAAK,QAAO;AAC1B,QAAM,QAAQA,uBAAAA,cAAc,IAAI,KAAK,GAAG,EAAE,YAAA,GAAe,SAAS;AAClE,SAAO,QAAQ,GAAG,KAAK,UAAU;AACnC;;;"}
1
+ {"version":3,"file":"SessionInspector.approvals.cjs","sources":["../../../src/data/ai/SessionInspector.approvals.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { KeyValueList } from \"../KeyValueList\";\nimport { Icon } from \"../Icon\";\nimport { UiClock } from \"../../icons\";\nimport { ToolCall } from \"../chat/ToolCall\";\nimport type { AnyToolPart } from \"../chat/types\";\nimport { durationLabel, formatDate } from \"./SessionInspector.model\";\nimport { EmptyState, SimpleList } from \"./SessionInspector.panel-parts\";\nimport { kv } from \"./SessionInspector.panel-values\";\nimport {\n type ApprovalResolveHandler,\n pendingApprovalRequests,\n} from \"./SessionInspector.approvals-model\";\nimport type {\n SessionApprovalRequest,\n SessionApprovalStats,\n} from \"./SessionViewer.unified\";\n\nexport type {\n ApprovalResolveAction,\n ApprovalResolveHandler,\n} from \"./SessionInspector.approvals-model\";\n\n/** Renders every pending tool approval directly from `session.requests[]`\n * (never from transcript parts — an approval brokered outside this session's\n * own chat has no transcript part) plus the resolved approve/deny/denial\n * summary the panel previously showed alone. */\nexport function SessionApprovalsPanel({\n approvals,\n requests,\n onResolve,\n}: {\n approvals: SessionApprovalStats | undefined;\n requests?: SessionApprovalRequest[] | undefined;\n onResolve?: ApprovalResolveHandler;\n}) {\n const pending = pendingApprovalRequests(requests);\n const hasResolvedSummary = Boolean(\n approvals &&\n (approvals.approved ||\n approvals.denied ||\n approvals.cancelled ||\n approvals.expired ||\n approvals.denials?.length),\n );\n\n if (!pending.length && !hasResolvedSummary) {\n return <EmptyState>No approval metadata.</EmptyState>;\n }\n\n return (\n <div className=\"space-y-density-4\">\n {pending.length ? (\n <PendingApprovalsList\n requests={pending}\n {...(onResolve ? { onResolve } : {})}\n />\n ) : null}\n {hasResolvedSummary ? (\n <ResolvedApprovalsSummary approvals={approvals!} />\n ) : null}\n </div>\n );\n}\n\nfunction ResolvedApprovalsSummary({\n approvals,\n}: {\n approvals: SessionApprovalStats;\n}) {\n return (\n <div className=\"space-y-density-4\">\n <KeyValueList\n items={[\n kv(\"Approved\", approvals.approved ?? 0),\n kv(\"Denied\", approvals.denied ?? 0),\n kv(\"Cancelled\", approvals.cancelled ?? 0),\n kv(\"Expired\", approvals.expired ?? 0),\n ]}\n />\n {approvals.denials?.length ? (\n <SimpleList\n title=\"Denials\"\n rows={approvals.denials.map((denial, index) => ({\n key: denial.toolUseId || `${denial.tool}-${index}`,\n title: [denial.tool, denial.toolUseId].filter(Boolean).join(\" \"),\n detail: denial.reason,\n }))}\n />\n ) : null}\n </div>\n );\n}\n\nfunction PendingApprovalsList({\n requests,\n onResolve,\n}: {\n requests: SessionApprovalRequest[];\n onResolve?: ApprovalResolveHandler;\n}) {\n return (\n <section>\n <h3 className=\"mb-density-2 flex items-center gap-1.5 text-xs font-semibold uppercase text-amber-600 dark:text-amber-400\">\n <Icon icon={UiClock} className=\"size-3.5\" />\n Awaiting approval ({requests.length})\n </h3>\n <ul className=\"space-y-density-2\">\n {requests.map((request) => (\n <li key={request.id}>\n <PendingApprovalRow\n request={request}\n {...(onResolve ? { onResolve } : {})}\n />\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\nfunction PendingApprovalRow({\n request,\n onResolve,\n}: {\n request: SessionApprovalRequest;\n onResolve?: ApprovalResolveHandler;\n}) {\n const [error, setError] = useState<string | undefined>(undefined);\n const [busy, setBusy] = useState(false);\n\n const part: AnyToolPart = {\n type: \"dynamic-tool\",\n toolName: request.tool,\n toolCallId: request.toolCallId || request.id,\n state: \"approval-requested\",\n input: request.input,\n approval: { id: request.id },\n };\n\n const handleApprove = (\n approvalId: string,\n approved: boolean,\n reason?: string,\n ) => {\n if (!onResolve) return;\n setError(undefined);\n setBusy(true);\n void Promise.resolve(onResolve(approvalId, approved ? \"approve\" : \"deny\", reason))\n .catch((err: unknown) => {\n setError(err instanceof Error ? err.message : String(err));\n })\n .finally(() => setBusy(false));\n };\n\n return (\n <div className=\"rounded-md border border-amber-300/60 bg-amber-50/40 p-density-3 dark:border-amber-800/60 dark:bg-amber-950/20\">\n <div className=\"mb-1 flex flex-wrap items-center justify-between gap-2 text-[11px] text-muted-foreground\">\n <span>\n {request.requestedBy\n ? `Requested by ${request.requestedBy}`\n : \"Requested\"}\n </span>\n <span className=\"flex gap-density-3\">\n {request.createdAt ? (\n <span title={formatDate(request.createdAt)}>\n {ageLabel(request.createdAt)} ago\n </span>\n ) : null}\n {request.expiresAt ? (\n <span title={formatDate(request.expiresAt)}>\n {remainingLabel(request.expiresAt)}\n </span>\n ) : null}\n </span>\n </div>\n <ToolCall\n part={part}\n defaultOpen\n onApprove={busy ? undefined : handleApprove}\n />\n {busy ? (\n <p className=\"mt-1.5 pl-4 text-xs text-muted-foreground\">\n Submitting…\n </p>\n ) : null}\n {error ? (\n <p role=\"alert\" className=\"mt-1.5 pl-4 text-xs text-destructive\">\n {error}\n </p>\n ) : null}\n </div>\n );\n}\n\nfunction ageLabel(createdAt: string): string {\n return durationLabel(createdAt) || \"0s\";\n}\n\nfunction remainingLabel(expiresAt: string): string {\n const expiry = new Date(expiresAt).getTime();\n if (Number.isNaN(expiry)) return \"\";\n const now = Date.now();\n if (expiry <= now) return \"expired\";\n const label = durationLabel(new Date(now).toISOString(), expiresAt);\n return label ? `${label} left` : \"\";\n}\n"],"names":["pendingApprovalRequests","jsx","EmptyState","jsxs","KeyValueList","kv","SimpleList","Icon","UiClock","useState","formatDate","ToolCall","durationLabel"],"mappings":";;;;;;;;;;;;AA2BO,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AACF,GAIG;;AACD,QAAM,UAAUA,gCAAAA,wBAAwB,QAAQ;AAChD,QAAM,qBAAqB;AAAA,IACzB,cACG,UAAU,YACT,UAAU,UACV,UAAU,aACV,UAAU,aACV,eAAU,YAAV,mBAAmB;AAAA,EAAA;AAGzB,MAAI,CAAC,QAAQ,UAAU,CAAC,oBAAoB;AAC1C,WAAOC,2BAAAA,IAACC,4BAAAA,cAAW,UAAA,wBAAA,CAAqB;AAAA,EAC1C;AAEA,SACEC,2BAAAA,KAAC,OAAA,EAAI,WAAU,qBACZ,UAAA;AAAA,IAAA,QAAQ,SACPF,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,UAAU;AAAA,QACT,GAAI,YAAY,EAAE,cAAc,CAAA;AAAA,MAAC;AAAA,IAAA,IAElC;AAAA,IACH,qBACCA,2BAAAA,IAAC,0BAAA,EAAyB,UAAA,CAAuB,IAC/C;AAAA,EAAA,GACN;AAEJ;AAEA,SAAS,yBAAyB;AAAA,EAChC;AACF,GAEG;;AACD,SACEE,2BAAAA,KAAC,OAAA,EAAI,WAAU,qBACb,UAAA;AAAA,IAAAF,2BAAAA;AAAAA,MAACG,aAAAA;AAAAA,MAAA;AAAA,QACC,OAAO;AAAA,UACLC,6BAAAA,GAAG,YAAY,UAAU,YAAY,CAAC;AAAA,UACtCA,6BAAAA,GAAG,UAAU,UAAU,UAAU,CAAC;AAAA,UAClCA,6BAAAA,GAAG,aAAa,UAAU,aAAa,CAAC;AAAA,UACxCA,6BAAAA,GAAG,WAAW,UAAU,WAAW,CAAC;AAAA,QAAA;AAAA,MACtC;AAAA,IAAA;AAAA,MAED,eAAU,YAAV,mBAAmB,UAClBJ,2BAAAA;AAAAA,MAACK,4BAAAA;AAAAA,MAAA;AAAA,QACC,OAAM;AAAA,QACN,MAAM,UAAU,QAAQ,IAAI,CAAC,QAAQ,WAAW;AAAA,UAC9C,KAAK,OAAO,aAAa,GAAG,OAAO,IAAI,IAAI,KAAK;AAAA,UAChD,OAAO,CAAC,OAAO,MAAM,OAAO,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,UAC/D,QAAQ,OAAO;AAAA,QAAA,EACf;AAAA,MAAA;AAAA,IAAA,IAEF;AAAA,EAAA,GACN;AAEJ;AAEA,SAAS,qBAAqB;AAAA,EAC5B;AAAA,EACA;AACF,GAGG;AACD,yCACG,WAAA,EACC,UAAA;AAAA,IAAAH,2BAAAA,KAAC,MAAA,EAAG,WAAU,6GACZ,UAAA;AAAA,MAAAF,2BAAAA,IAACM,KAAAA,MAAA,EAAK,MAAMC,QAAAA,SAAS,WAAU,YAAW;AAAA,MAAE;AAAA,MACxB,SAAS;AAAA,MAAO;AAAA,IAAA,GACtC;AAAA,IACAP,2BAAAA,IAAC,QAAG,WAAU,qBACX,mBAAS,IAAI,CAAC,YACbA,2BAAAA,IAAC,MAAA,EACC,UAAAA,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACC,GAAI,YAAY,EAAE,cAAc,CAAA;AAAA,MAAC;AAAA,IAAA,KAH7B,QAAQ,EAKjB,CACD,EAAA,CACH;AAAA,EAAA,GACF;AAEJ;AAEA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AACF,GAGG;AACD,QAAM,CAAC,OAAO,QAAQ,IAAIQ,MAAAA,SAA6B,MAAS;AAChE,QAAM,CAAC,MAAM,OAAO,IAAIA,MAAAA,SAAS,KAAK;AAEtC,QAAM,OAAoB;AAAA,IACxB,MAAM;AAAA,IACN,UAAU,QAAQ;AAAA,IAClB,YAAY,QAAQ,cAAc,QAAQ;AAAA,IAC1C,OAAO;AAAA,IACP,OAAO,QAAQ;AAAA,IACf,UAAU,EAAE,IAAI,QAAQ,GAAA;AAAA,EAAG;AAG7B,QAAM,gBAAgB,CACpB,YACA,UACA,WACG;AACH,QAAI,CAAC,UAAW;AAChB,aAAS,MAAS;AAClB,YAAQ,IAAI;AACZ,SAAK,QAAQ,QAAQ,UAAU,YAAY,WAAW,YAAY,QAAQ,MAAM,CAAC,EAC9E,MAAM,CAAC,QAAiB;AACvB,eAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAC3D,CAAC,EACA,QAAQ,MAAM,QAAQ,KAAK,CAAC;AAAA,EACjC;AAEA,SACEN,2BAAAA,KAAC,OAAA,EAAI,WAAU,kHACb,UAAA;AAAA,IAAAA,2BAAAA,KAAC,OAAA,EAAI,WAAU,4FACb,UAAA;AAAA,MAAAF,2BAAAA,IAAC,UACE,UAAA,QAAQ,cACL,gBAAgB,QAAQ,WAAW,KACnC,YAAA,CACN;AAAA,MACAE,2BAAAA,KAAC,QAAA,EAAK,WAAU,sBACb,UAAA;AAAA,QAAA,QAAQ,YACPA,2BAAAA,KAAC,QAAA,EAAK,OAAOO,uBAAAA,WAAW,QAAQ,SAAS,GACtC,UAAA;AAAA,UAAA,SAAS,QAAQ,SAAS;AAAA,UAAE;AAAA,QAAA,EAAA,CAC/B,IACE;AAAA,QACH,QAAQ,YACPT,2BAAAA,IAAC,QAAA,EAAK,OAAOS,uBAAAA,WAAW,QAAQ,SAAS,GACtC,UAAA,eAAe,QAAQ,SAAS,GACnC,IACE;AAAA,MAAA,EAAA,CACN;AAAA,IAAA,GACF;AAAA,IACAT,2BAAAA;AAAAA,MAACU,SAAAA;AAAAA,MAAA;AAAA,QACC;AAAA,QACA,aAAW;AAAA,QACX,WAAW,OAAO,SAAY;AAAA,MAAA;AAAA,IAAA;AAAA,IAE/B,OACCV,2BAAAA,IAAC,KAAA,EAAE,WAAU,6CAA4C,yBAEzD,IACE;AAAA,IACH,uCACE,KAAA,EAAE,MAAK,SAAQ,WAAU,wCACvB,iBACH,IACE;AAAA,EAAA,GACN;AAEJ;AAEA,SAAS,SAAS,WAA2B;AAC3C,SAAOW,uBAAAA,cAAc,SAAS,KAAK;AACrC;AAEA,SAAS,eAAe,WAA2B;AACjD,QAAM,SAAS,IAAI,KAAK,SAAS,EAAE,QAAA;AACnC,MAAI,OAAO,MAAM,MAAM,EAAG,QAAO;AACjC,QAAM,MAAM,KAAK,IAAA;AACjB,MAAI,UAAU,IAAK,QAAO;AAC1B,QAAM,QAAQA,uBAAAA,cAAc,IAAI,KAAK,GAAG,EAAE,YAAA,GAAe,SAAS;AAClE,SAAO,QAAQ,GAAG,KAAK,UAAU;AACnC;;"}
@@ -1,14 +1,6 @@
1
+ import { ApprovalResolveHandler } from './SessionInspector.approvals-model';
1
2
  import { SessionApprovalRequest, SessionApprovalStats } from './SessionViewer.unified';
2
- /** Approve or deny one pending approval. */
3
- export type ApprovalResolveAction = "approve" | "deny";
4
- /** Resolves one `session.requests[]` row. Rejecting surfaces the server's
5
- * refusal text inline on that row (e.g. the prompt run is no longer
6
- * `waiting`) instead of leaving the Approve/Deny buttons silently inert. */
7
- export type ApprovalResolveHandler = (approvalId: string, action: ApprovalResolveAction, message?: string) => void | Promise<void>;
8
- /** The subset of `session.requests[]` this panel surfaces: outstanding tool
9
- * approvals, regardless of which surface (in-process chat or an external
10
- * broker) created the request. */
11
- export declare function pendingApprovalRequests(requests: SessionApprovalRequest[] | undefined): SessionApprovalRequest[];
3
+ export type { ApprovalResolveAction, ApprovalResolveHandler, } from './SessionInspector.approvals-model';
12
4
  /** Renders every pending tool approval directly from `session.requests[]`
13
5
  * (never from transcript parts — an approval brokered outside this session's
14
6
  * own chat has no transcript part) plus the resolved approve/deny/denial
@@ -1 +1 @@
1
- {"version":3,"file":"SessionInspector.approvals.d.ts","sourceRoot":"","sources":["../../../src/data/ai/SessionInspector.approvals.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,yBAAyB,CAAC;AAEjC,4CAA4C;AAC5C,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,MAAM,CAAC;AAEvD;;6EAE6E;AAC7E,MAAM,MAAM,sBAAsB,GAAG,CACnC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,qBAAqB,EAC7B,OAAO,CAAC,EAAE,MAAM,KACb,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B;;mCAEmC;AACnC,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,sBAAsB,EAAE,GAAG,SAAS,GAC7C,sBAAsB,EAAE,CAI1B;AAED;;;iDAGiD;AACjD,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,QAAQ,EACR,SAAS,GACV,EAAE;IACD,SAAS,EAAE,oBAAoB,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,EAAE,sBAAsB,EAAE,GAAG,SAAS,CAAC;IAChD,SAAS,CAAC,EAAE,sBAAsB,CAAC;CACpC,+BA4BA"}
1
+ {"version":3,"file":"SessionInspector.approvals.d.ts","sourceRoot":"","sources":["../../../src/data/ai/SessionInspector.approvals.tsx"],"names":[],"mappings":"AASA,OAAO,EACL,KAAK,sBAAsB,EAE5B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EACV,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,yBAAyB,CAAC;AAEjC,YAAY,EACV,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,oCAAoC,CAAC;AAE5C;;;iDAGiD;AACjD,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,QAAQ,EACR,SAAS,GACV,EAAE;IACD,SAAS,EAAE,oBAAoB,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,EAAE,sBAAsB,EAAE,GAAG,SAAS,CAAC;IAChD,SAAS,CAAC,EAAE,sBAAsB,CAAC;CACpC,+BA4BA"}
@@ -4,13 +4,10 @@ import { KeyValueList } from "../KeyValueList.js";
4
4
  import { Icon } from "../Icon.js";
5
5
  import { ToolCall } from "../chat/ToolCall.js";
6
6
  import { formatDate, durationLabel } from "./SessionInspector.model.js";
7
- import { EmptyState, kv, SimpleList } from "./SessionInspector.panel-parts.js";
7
+ import { EmptyState, SimpleList } from "./SessionInspector.panel-parts.js";
8
+ import { kv } from "./SessionInspector.panel-values.js";
9
+ import { pendingApprovalRequests } from "./SessionInspector.approvals-model.js";
8
10
  import { UiClock } from "../../icons/components/UiClock.js";
9
- function pendingApprovalRequests(requests) {
10
- return (requests ?? []).filter(
11
- (request) => request.state === "pending" && request.kind === "tool_approval"
12
- );
13
- }
14
11
  function SessionApprovalsPanel({
15
12
  approvals,
16
13
  requests,
@@ -141,7 +138,6 @@ function remainingLabel(expiresAt) {
141
138
  return label ? `${label} left` : "";
142
139
  }
143
140
  export {
144
- SessionApprovalsPanel,
145
- pendingApprovalRequests
141
+ SessionApprovalsPanel
146
142
  };
147
143
  //# sourceMappingURL=SessionInspector.approvals.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SessionInspector.approvals.js","sources":["../../../src/data/ai/SessionInspector.approvals.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { KeyValueList } from \"../KeyValueList\";\nimport { Icon } from \"../Icon\";\nimport { UiClock } from \"../../icons\";\nimport { ToolCall } from \"../chat/ToolCall\";\nimport type { AnyToolPart } from \"../chat/types\";\nimport { durationLabel, formatDate } from \"./SessionInspector.model\";\nimport { EmptyState, SimpleList, kv } from \"./SessionInspector.panel-parts\";\nimport type {\n SessionApprovalRequest,\n SessionApprovalStats,\n} from \"./SessionViewer.unified\";\n\n/** Approve or deny one pending approval. */\nexport type ApprovalResolveAction = \"approve\" | \"deny\";\n\n/** Resolves one `session.requests[]` row. Rejecting surfaces the server's\n * refusal text inline on that row (e.g. the prompt run is no longer\n * `waiting`) instead of leaving the Approve/Deny buttons silently inert. */\nexport type ApprovalResolveHandler = (\n approvalId: string,\n action: ApprovalResolveAction,\n message?: string,\n) => void | Promise<void>;\n\n/** The subset of `session.requests[]` this panel surfaces: outstanding tool\n * approvals, regardless of which surface (in-process chat or an external\n * broker) created the request. */\nexport function pendingApprovalRequests(\n requests: SessionApprovalRequest[] | undefined,\n): SessionApprovalRequest[] {\n return (requests ?? []).filter(\n (request) => request.state === \"pending\" && request.kind === \"tool_approval\",\n );\n}\n\n/** Renders every pending tool approval directly from `session.requests[]`\n * (never from transcript parts — an approval brokered outside this session's\n * own chat has no transcript part) plus the resolved approve/deny/denial\n * summary the panel previously showed alone. */\nexport function SessionApprovalsPanel({\n approvals,\n requests,\n onResolve,\n}: {\n approvals: SessionApprovalStats | undefined;\n requests?: SessionApprovalRequest[] | undefined;\n onResolve?: ApprovalResolveHandler;\n}) {\n const pending = pendingApprovalRequests(requests);\n const hasResolvedSummary = Boolean(\n approvals &&\n (approvals.approved ||\n approvals.denied ||\n approvals.cancelled ||\n approvals.expired ||\n approvals.denials?.length),\n );\n\n if (!pending.length && !hasResolvedSummary) {\n return <EmptyState>No approval metadata.</EmptyState>;\n }\n\n return (\n <div className=\"space-y-density-4\">\n {pending.length ? (\n <PendingApprovalsList\n requests={pending}\n {...(onResolve ? { onResolve } : {})}\n />\n ) : null}\n {hasResolvedSummary ? (\n <ResolvedApprovalsSummary approvals={approvals!} />\n ) : null}\n </div>\n );\n}\n\nfunction ResolvedApprovalsSummary({\n approvals,\n}: {\n approvals: SessionApprovalStats;\n}) {\n return (\n <div className=\"space-y-density-4\">\n <KeyValueList\n items={[\n kv(\"Approved\", approvals.approved ?? 0),\n kv(\"Denied\", approvals.denied ?? 0),\n kv(\"Cancelled\", approvals.cancelled ?? 0),\n kv(\"Expired\", approvals.expired ?? 0),\n ]}\n />\n {approvals.denials?.length ? (\n <SimpleList\n title=\"Denials\"\n rows={approvals.denials.map((denial, index) => ({\n key: denial.toolUseId || `${denial.tool}-${index}`,\n title: [denial.tool, denial.toolUseId].filter(Boolean).join(\" \"),\n detail: denial.reason,\n }))}\n />\n ) : null}\n </div>\n );\n}\n\nfunction PendingApprovalsList({\n requests,\n onResolve,\n}: {\n requests: SessionApprovalRequest[];\n onResolve?: ApprovalResolveHandler;\n}) {\n return (\n <section>\n <h3 className=\"mb-density-2 flex items-center gap-1.5 text-xs font-semibold uppercase text-amber-600 dark:text-amber-400\">\n <Icon icon={UiClock} className=\"size-3.5\" />\n Awaiting approval ({requests.length})\n </h3>\n <ul className=\"space-y-density-2\">\n {requests.map((request) => (\n <li key={request.id}>\n <PendingApprovalRow\n request={request}\n {...(onResolve ? { onResolve } : {})}\n />\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\nfunction PendingApprovalRow({\n request,\n onResolve,\n}: {\n request: SessionApprovalRequest;\n onResolve?: ApprovalResolveHandler;\n}) {\n const [error, setError] = useState<string | undefined>(undefined);\n const [busy, setBusy] = useState(false);\n\n const part: AnyToolPart = {\n type: \"dynamic-tool\",\n toolName: request.tool,\n toolCallId: request.toolCallId || request.id,\n state: \"approval-requested\",\n input: request.input,\n approval: { id: request.id },\n };\n\n const handleApprove = (\n approvalId: string,\n approved: boolean,\n reason?: string,\n ) => {\n if (!onResolve) return;\n setError(undefined);\n setBusy(true);\n void Promise.resolve(onResolve(approvalId, approved ? \"approve\" : \"deny\", reason))\n .catch((err: unknown) => {\n setError(err instanceof Error ? err.message : String(err));\n })\n .finally(() => setBusy(false));\n };\n\n return (\n <div className=\"rounded-md border border-amber-300/60 bg-amber-50/40 p-density-3 dark:border-amber-800/60 dark:bg-amber-950/20\">\n <div className=\"mb-1 flex flex-wrap items-center justify-between gap-2 text-[11px] text-muted-foreground\">\n <span>\n {request.requestedBy\n ? `Requested by ${request.requestedBy}`\n : \"Requested\"}\n </span>\n <span className=\"flex gap-density-3\">\n {request.createdAt ? (\n <span title={formatDate(request.createdAt)}>\n {ageLabel(request.createdAt)} ago\n </span>\n ) : null}\n {request.expiresAt ? (\n <span title={formatDate(request.expiresAt)}>\n {remainingLabel(request.expiresAt)}\n </span>\n ) : null}\n </span>\n </div>\n <ToolCall\n part={part}\n defaultOpen\n onApprove={busy ? undefined : handleApprove}\n />\n {busy ? (\n <p className=\"mt-1.5 pl-4 text-xs text-muted-foreground\">\n Submitting…\n </p>\n ) : null}\n {error ? (\n <p role=\"alert\" className=\"mt-1.5 pl-4 text-xs text-destructive\">\n {error}\n </p>\n ) : null}\n </div>\n );\n}\n\nfunction ageLabel(createdAt: string): string {\n return durationLabel(createdAt) || \"0s\";\n}\n\nfunction remainingLabel(expiresAt: string): string {\n const expiry = new Date(expiresAt).getTime();\n if (Number.isNaN(expiry)) return \"\";\n const now = Date.now();\n if (expiry <= now) return \"expired\";\n const label = durationLabel(new Date(now).toISOString(), expiresAt);\n return label ? `${label} left` : \"\";\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SessionInspector.approvals.js","sources":["../../../src/data/ai/SessionInspector.approvals.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { KeyValueList } from \"../KeyValueList\";\nimport { Icon } from \"../Icon\";\nimport { UiClock } from \"../../icons\";\nimport { ToolCall } from \"../chat/ToolCall\";\nimport type { AnyToolPart } from \"../chat/types\";\nimport { durationLabel, formatDate } from \"./SessionInspector.model\";\nimport { EmptyState, SimpleList } from \"./SessionInspector.panel-parts\";\nimport { kv } from \"./SessionInspector.panel-values\";\nimport {\n type ApprovalResolveHandler,\n pendingApprovalRequests,\n} from \"./SessionInspector.approvals-model\";\nimport type {\n SessionApprovalRequest,\n SessionApprovalStats,\n} from \"./SessionViewer.unified\";\n\nexport type {\n ApprovalResolveAction,\n ApprovalResolveHandler,\n} from \"./SessionInspector.approvals-model\";\n\n/** Renders every pending tool approval directly from `session.requests[]`\n * (never from transcript parts — an approval brokered outside this session's\n * own chat has no transcript part) plus the resolved approve/deny/denial\n * summary the panel previously showed alone. */\nexport function SessionApprovalsPanel({\n approvals,\n requests,\n onResolve,\n}: {\n approvals: SessionApprovalStats | undefined;\n requests?: SessionApprovalRequest[] | undefined;\n onResolve?: ApprovalResolveHandler;\n}) {\n const pending = pendingApprovalRequests(requests);\n const hasResolvedSummary = Boolean(\n approvals &&\n (approvals.approved ||\n approvals.denied ||\n approvals.cancelled ||\n approvals.expired ||\n approvals.denials?.length),\n );\n\n if (!pending.length && !hasResolvedSummary) {\n return <EmptyState>No approval metadata.</EmptyState>;\n }\n\n return (\n <div className=\"space-y-density-4\">\n {pending.length ? (\n <PendingApprovalsList\n requests={pending}\n {...(onResolve ? { onResolve } : {})}\n />\n ) : null}\n {hasResolvedSummary ? (\n <ResolvedApprovalsSummary approvals={approvals!} />\n ) : null}\n </div>\n );\n}\n\nfunction ResolvedApprovalsSummary({\n approvals,\n}: {\n approvals: SessionApprovalStats;\n}) {\n return (\n <div className=\"space-y-density-4\">\n <KeyValueList\n items={[\n kv(\"Approved\", approvals.approved ?? 0),\n kv(\"Denied\", approvals.denied ?? 0),\n kv(\"Cancelled\", approvals.cancelled ?? 0),\n kv(\"Expired\", approvals.expired ?? 0),\n ]}\n />\n {approvals.denials?.length ? (\n <SimpleList\n title=\"Denials\"\n rows={approvals.denials.map((denial, index) => ({\n key: denial.toolUseId || `${denial.tool}-${index}`,\n title: [denial.tool, denial.toolUseId].filter(Boolean).join(\" \"),\n detail: denial.reason,\n }))}\n />\n ) : null}\n </div>\n );\n}\n\nfunction PendingApprovalsList({\n requests,\n onResolve,\n}: {\n requests: SessionApprovalRequest[];\n onResolve?: ApprovalResolveHandler;\n}) {\n return (\n <section>\n <h3 className=\"mb-density-2 flex items-center gap-1.5 text-xs font-semibold uppercase text-amber-600 dark:text-amber-400\">\n <Icon icon={UiClock} className=\"size-3.5\" />\n Awaiting approval ({requests.length})\n </h3>\n <ul className=\"space-y-density-2\">\n {requests.map((request) => (\n <li key={request.id}>\n <PendingApprovalRow\n request={request}\n {...(onResolve ? { onResolve } : {})}\n />\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\nfunction PendingApprovalRow({\n request,\n onResolve,\n}: {\n request: SessionApprovalRequest;\n onResolve?: ApprovalResolveHandler;\n}) {\n const [error, setError] = useState<string | undefined>(undefined);\n const [busy, setBusy] = useState(false);\n\n const part: AnyToolPart = {\n type: \"dynamic-tool\",\n toolName: request.tool,\n toolCallId: request.toolCallId || request.id,\n state: \"approval-requested\",\n input: request.input,\n approval: { id: request.id },\n };\n\n const handleApprove = (\n approvalId: string,\n approved: boolean,\n reason?: string,\n ) => {\n if (!onResolve) return;\n setError(undefined);\n setBusy(true);\n void Promise.resolve(onResolve(approvalId, approved ? \"approve\" : \"deny\", reason))\n .catch((err: unknown) => {\n setError(err instanceof Error ? err.message : String(err));\n })\n .finally(() => setBusy(false));\n };\n\n return (\n <div className=\"rounded-md border border-amber-300/60 bg-amber-50/40 p-density-3 dark:border-amber-800/60 dark:bg-amber-950/20\">\n <div className=\"mb-1 flex flex-wrap items-center justify-between gap-2 text-[11px] text-muted-foreground\">\n <span>\n {request.requestedBy\n ? `Requested by ${request.requestedBy}`\n : \"Requested\"}\n </span>\n <span className=\"flex gap-density-3\">\n {request.createdAt ? (\n <span title={formatDate(request.createdAt)}>\n {ageLabel(request.createdAt)} ago\n </span>\n ) : null}\n {request.expiresAt ? (\n <span title={formatDate(request.expiresAt)}>\n {remainingLabel(request.expiresAt)}\n </span>\n ) : null}\n </span>\n </div>\n <ToolCall\n part={part}\n defaultOpen\n onApprove={busy ? undefined : handleApprove}\n />\n {busy ? (\n <p className=\"mt-1.5 pl-4 text-xs text-muted-foreground\">\n Submitting…\n </p>\n ) : null}\n {error ? (\n <p role=\"alert\" className=\"mt-1.5 pl-4 text-xs text-destructive\">\n {error}\n </p>\n ) : null}\n </div>\n );\n}\n\nfunction ageLabel(createdAt: string): string {\n return durationLabel(createdAt) || \"0s\";\n}\n\nfunction remainingLabel(expiresAt: string): string {\n const expiry = new Date(expiresAt).getTime();\n if (Number.isNaN(expiry)) return \"\";\n const now = Date.now();\n if (expiry <= now) return \"expired\";\n const label = durationLabel(new Date(now).toISOString(), expiresAt);\n return label ? `${label} left` : \"\";\n}\n"],"names":[],"mappings":"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"}
@@ -11,7 +11,7 @@ const SessionInspector_transcript = require("./SessionInspector.transcript.cjs")
11
11
  const SessionInspector_collection = require("./SessionInspector.collection.cjs");
12
12
  const SessionInspector_hierarchy = require("./SessionInspector.hierarchy.cjs");
13
13
  const SessionInspector_hierarchyState = require("./SessionInspector.hierarchy-state.cjs");
14
- const SessionInspector_approvals = require("./SessionInspector.approvals.cjs");
14
+ const SessionInspector_approvalsModel = require("./SessionInspector.approvals-model.cjs");
15
15
  const SessionViewer = require("./SessionViewer.cjs");
16
16
  const UiChatDots = require("../../icons/components/UiChatDots.cjs");
17
17
  const UiFileText = require("../../icons/components/UiFileText.cjs");
@@ -252,7 +252,7 @@ function tabBadge(tab, session) {
252
252
  count: (((_b = (_a = session == null ? void 0 : session.files) == null ? void 0 : _a.read) == null ? void 0 : _b.length) ?? 0) + (((_d = (_c = session == null ? void 0 : session.files) == null ? void 0 : _c.written) == null ? void 0 : _d.length) ?? 0)
253
253
  };
254
254
  case "approvals": {
255
- const pending = SessionInspector_approvals.pendingApprovalRequests(session == null ? void 0 : session.requests).length;
255
+ const pending = SessionInspector_approvalsModel.pendingApprovalRequests(session == null ? void 0 : session.requests).length;
256
256
  if (pending) return { count: pending, color: "bg-amber-500" };
257
257
  return {
258
258
  count: (((_e = session == null ? void 0 : session.approvals) == null ? void 0 : _e.approved) ?? 0) + (((_f = session == null ? void 0 : session.approvals) == null ? void 0 : _f.denied) ?? 0)
@@ -1 +1 @@
1
- {"version":3,"file":"SessionInspector.cjs","sources":["../../../src/data/ai/SessionInspector.tsx"],"sourcesContent":["import { useMemo, useState, type ReactNode } from \"react\";\nimport {\n UiBraces,\n UiChatDots,\n UiCoins,\n UiFileText,\n UiListDashes,\n UiSealCheck,\n UiStrategy,\n} from \"../../icons\";\nimport { cn } from \"../../lib/utils\";\nimport { TabButton } from \"../TabButton\";\nimport { formatCost, costTotal } from \"./session-cost\";\nimport { SessionInspectorPanel } from \"./SessionInspector.panels\";\nimport {\n SessionInspectorHeader,\n SessionInspectorSidebar,\n} from \"./SessionInspector.summary\";\nimport { SessionTranscript } from \"./SessionInspector.transcript\";\nimport {\n isSessionCollectionInput,\n type SessionCollectionInput,\n type SessionCollectionItem,\n type SessionInspectorInput,\n} from \"./SessionInspector.collection\";\nimport { SessionHierarchyPicker } from \"./SessionInspector.hierarchy\";\nimport { useSessionHierarchy } from \"./SessionInspector.hierarchy-state\";\nimport {\n pendingApprovalRequests,\n type ApprovalResolveHandler,\n} from \"./SessionInspector.approvals\";\nimport { SessionViewer, type SessionViewerProps } from \"./SessionViewer\";\nimport type { SessionInput } from \"./SessionViewer.model\";\nimport type { UnifiedSessionInput } from \"./SessionViewer.unified\";\n\nexport type SessionInspectorTab =\n | \"transcript\"\n | \"files\"\n | \"plan\"\n | \"approvals\"\n | \"costs\"\n | \"metadata\"\n | \"raw\";\n\nexport interface SessionInspectorProps {\n session: SessionInspectorInput;\n className?: string;\n defaultTab?: SessionInspectorTab;\n transcriptProps?: Omit<SessionViewerProps, \"session\">;\n renderSessionActions?: (item: SessionCollectionItem) => ReactNode;\n /** Receives edits made in the Plan tab. The inspector also keeps the draft visible locally. */\n onPlanChange?: (content: string) => void;\n /** Resolves one pending tool approval from the Approvals tab. Omitted, the\n * tab still lists pending requests but renders no Approve/Deny controls. */\n onResolveApproval?: ApprovalResolveHandler;\n composer?: ReactNode;\n}\n\nconst TABS = [\n { id: \"transcript\", label: \"Transcript\", icon: UiChatDots },\n { id: \"files\", label: \"Files\", icon: UiFileText },\n { id: \"plan\", label: \"Plan\", icon: UiStrategy },\n { id: \"approvals\", label: \"Approvals\", icon: UiSealCheck },\n { id: \"costs\", label: \"Costs\", icon: UiCoins },\n { id: \"metadata\", label: \"Metadata\", icon: UiListDashes },\n { id: \"raw\", label: \"Raw\", icon: UiBraces },\n] as const;\n\nexport function SessionInspector({\n session,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n renderSessionActions,\n onPlanChange,\n onResolveApproval,\n composer,\n}: SessionInspectorProps) {\n const detail = useMemo(\n () =>\n isSessionCollectionInput(session) ? undefined : asUnifiedSession(session),\n [session],\n );\n const collection = useMemo(\n () =>\n isSessionCollectionInput(session)\n ? session\n : detail\n ? singleSessionCollection(detail)\n : undefined,\n [detail, session],\n );\n\n if (collection) {\n const optionalProps = {\n ...(className ? { className } : {}),\n ...(transcriptProps ? { transcriptProps } : {}),\n ...(renderSessionActions ? { renderSessionActions } : {}),\n ...(onPlanChange ? { onPlanChange } : {}),\n ...(onResolveApproval ? { onResolveApproval } : {}),\n ...(composer ? { composer } : {}),\n };\n return (\n <CollectionSessionInspector\n collection={collection}\n defaultTab={defaultTab}\n {...optionalProps}\n />\n );\n }\n\n return (\n <LegacySessionInspector\n session={session as SessionInput}\n defaultTab={defaultTab}\n {...(className ? { className } : {})}\n {...(transcriptProps ? { transcriptProps } : {})}\n {...(composer ? { composer } : {})}\n />\n );\n}\n\nfunction CollectionSessionInspector({\n collection,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n renderSessionActions,\n onPlanChange,\n onResolveApproval,\n composer,\n}: Omit<SessionInspectorProps, \"session\"> & {\n collection: SessionCollectionInput;\n}) {\n const hierarchy = useSessionHierarchy(collection);\n const [tab, setTab] = useState<SessionInspectorTab>(defaultTab);\n const transcriptClassName = cn(\"h-full\", transcriptProps?.className);\n const panelDetail = tab === \"costs\" ? hierarchy.filtered : hierarchy.current;\n\n return (\n <div\n className={cn(\n \"flex h-full min-h-0 w-full max-w-full flex-col overflow-hidden rounded-xl border border-border bg-background text-sm shadow-sm\",\n className,\n )}\n >\n <SessionInspectorHeader session={hierarchy.current} />\n <div\n role=\"toolbar\"\n aria-label=\"Session content controls\"\n className=\"flex shrink-0 justify-start border-b border-border px-density-2 py-density-2\"\n >\n <SessionHierarchyPicker\n collection={collection}\n state={hierarchy}\n {...(renderSessionActions ? { renderSessionActions } : {})}\n />\n </div>\n <div\n role=\"tablist\"\n aria-label=\"Session detail view\"\n className=\"flex shrink-0 overflow-x-auto border-b border-border px-density-2\"\n >\n {TABS.map((item) => {\n const badge = tabBadge(item.id, hierarchy.current);\n return (\n <TabButton\n key={item.id}\n active={tab === item.id}\n onClick={() => setTab(item.id)}\n label={tabLabel(\n item.id,\n item.label,\n item.id === \"costs\" ? hierarchy.filtered : hierarchy.current,\n )}\n icon={item.icon}\n variant=\"underline\"\n {...(badge.count === undefined ? {} : { count: badge.count })}\n {...(badge.color ? { countColor: badge.color } : {})}\n className=\"shrink-0 py-density-2 [&_svg]:text-muted-foreground\"\n />\n );\n })}\n </div>\n <div className=\"grid min-h-0 flex-1 overflow-y-auto lg:grid-cols-[minmax(0,1fr)_18rem] lg:overflow-hidden\">\n <main className=\"flex min-h-[28rem] min-w-0 flex-col lg:min-h-0\">\n <div\n className={cn(\n \"min-h-0 flex-1\",\n tab === \"transcript\"\n ? \"overflow-hidden\"\n : \"overflow-auto p-density-4\",\n )}\n >\n {tab === \"transcript\" ? (\n <SessionTranscript\n session={hierarchy.filtered}\n viewerProps={{\n ...transcriptProps,\n className: transcriptClassName,\n }}\n />\n ) : (\n <SessionInspectorPanel\n tab={tab}\n detail={panelDetail}\n session={hierarchy.current}\n {...(onPlanChange ? { onPlanChange } : {})}\n {...(onResolveApproval ? { onResolveApproval } : {})}\n />\n )}\n </div>\n {composer ? (\n <div className=\"shrink-0 border-t border-border p-density-3\">\n {composer}\n </div>\n ) : null}\n </main>\n <SessionInspectorSidebar session={hierarchy.current} />\n </div>\n </div>\n );\n}\n\nfunction LegacySessionInspector({\n session,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n composer,\n}: Pick<\n SessionInspectorProps,\n \"className\" | \"defaultTab\" | \"transcriptProps\" | \"composer\"\n> & {\n session: SessionInput;\n}) {\n const [tab, setTab] = useState<SessionInspectorTab>(defaultTab);\n const transcriptClassName = cn(\"h-full\", transcriptProps?.className);\n return (\n <div\n className={cn(\n \"flex h-full min-h-0 w-full max-w-full flex-col overflow-hidden rounded-xl border border-border bg-background text-sm shadow-sm\",\n className,\n )}\n >\n <div\n role=\"tablist\"\n aria-label=\"Session detail view\"\n className=\"flex shrink-0 overflow-x-auto border-b border-border px-density-2\"\n >\n {TABS.map((item) => (\n <TabButton\n key={item.id}\n active={tab === item.id}\n onClick={() => setTab(item.id)}\n label={item.label}\n icon={item.icon}\n variant=\"underline\"\n className=\"shrink-0 py-density-2 [&_svg]:text-muted-foreground\"\n />\n ))}\n </div>\n <div className=\"flex min-h-0 flex-1 flex-col overflow-hidden\">\n <div className=\"min-h-0 flex-1 overflow-hidden\">\n {tab === \"transcript\" ? (\n <SessionViewer\n session={session}\n scrollable\n showRowMetadata\n {...transcriptProps}\n className={transcriptClassName}\n />\n ) : (\n <SessionInspectorPanel\n tab={tab}\n detail={undefined}\n session={session}\n />\n )}\n </div>\n {composer ? (\n <div className=\"shrink-0 border-t border-border p-density-3\">\n {composer}\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n\n/** The tab's count badge and, for a pending-approvals badge, an amber\n * override so an unresolved approval reads as urgent rather than blending\n * into the neutral resolved-count badge every other tab uses. */\nfunction tabBadge(\n tab: SessionInspectorTab,\n session?: UnifiedSessionInput,\n): { count?: number; color?: string } {\n switch (tab) {\n case \"files\":\n return {\n count:\n (session?.files?.read?.length ?? 0) +\n (session?.files?.written?.length ?? 0),\n };\n case \"approvals\": {\n const pending = pendingApprovalRequests(session?.requests).length;\n if (pending) return { count: pending, color: \"bg-amber-500\" };\n return {\n count:\n (session?.approvals?.approved ?? 0) +\n (session?.approvals?.denied ?? 0),\n };\n }\n default:\n return {};\n }\n}\n\nfunction singleSessionCollection(\n session: UnifiedSessionInput,\n): SessionCollectionInput {\n const id = session.id || \"session\";\n return {\n kind: \"session-collection\",\n id,\n currentSessionId: id,\n sessions: [{ id, session }],\n };\n}\n\nfunction tabLabel(\n tab: SessionInspectorTab,\n label: string,\n session?: UnifiedSessionInput,\n) {\n if (tab !== \"costs\") return label;\n const total = costTotal(session?.cost);\n return total ? `${label} ${formatCost(total)}` : label;\n}\n\nfunction asUnifiedSession(\n session: SessionInput,\n): UnifiedSessionInput | undefined {\n if (typeof session !== \"object\" || session === null || Array.isArray(session))\n return undefined;\n return session as UnifiedSessionInput;\n}\n"],"names":["UiChatDots","UiFileText","UiStrategy","UiSealCheck","UiCoins","UiListDashes","UiBraces","useMemo","isSessionCollectionInput","jsx","useSessionHierarchy","useState","cn","jsxs","SessionInspectorHeader","SessionHierarchyPicker","TabButton","SessionTranscript","SessionInspectorPanel","SessionInspectorSidebar","SessionViewer","pendingApprovalRequests","costTotal","formatCost"],"mappings":"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"}
1
+ {"version":3,"file":"SessionInspector.cjs","sources":["../../../src/data/ai/SessionInspector.tsx"],"sourcesContent":["import { useMemo, useState, type ReactNode } from \"react\";\nimport {\n UiBraces,\n UiChatDots,\n UiCoins,\n UiFileText,\n UiListDashes,\n UiSealCheck,\n UiStrategy,\n} from \"../../icons\";\nimport { cn } from \"../../lib/utils\";\nimport { TabButton } from \"../TabButton\";\nimport { formatCost, costTotal } from \"./session-cost\";\nimport { SessionInspectorPanel } from \"./SessionInspector.panels\";\nimport {\n SessionInspectorHeader,\n SessionInspectorSidebar,\n} from \"./SessionInspector.summary\";\nimport { SessionTranscript } from \"./SessionInspector.transcript\";\nimport {\n isSessionCollectionInput,\n type SessionCollectionInput,\n type SessionCollectionItem,\n type SessionInspectorInput,\n} from \"./SessionInspector.collection\";\nimport { SessionHierarchyPicker } from \"./SessionInspector.hierarchy\";\nimport { useSessionHierarchy } from \"./SessionInspector.hierarchy-state\";\nimport {\n pendingApprovalRequests,\n type ApprovalResolveHandler,\n} from \"./SessionInspector.approvals-model\";\nimport { SessionViewer, type SessionViewerProps } from \"./SessionViewer\";\nimport type { SessionInput } from \"./SessionViewer.model\";\nimport type { UnifiedSessionInput } from \"./SessionViewer.unified\";\n\nexport type SessionInspectorTab =\n | \"transcript\"\n | \"files\"\n | \"plan\"\n | \"approvals\"\n | \"costs\"\n | \"metadata\"\n | \"raw\";\n\nexport interface SessionInspectorProps {\n session: SessionInspectorInput;\n className?: string;\n defaultTab?: SessionInspectorTab;\n transcriptProps?: Omit<SessionViewerProps, \"session\">;\n renderSessionActions?: (item: SessionCollectionItem) => ReactNode;\n /** Receives edits made in the Plan tab. The inspector also keeps the draft visible locally. */\n onPlanChange?: (content: string) => void;\n /** Resolves one pending tool approval from the Approvals tab. Omitted, the\n * tab still lists pending requests but renders no Approve/Deny controls. */\n onResolveApproval?: ApprovalResolveHandler;\n composer?: ReactNode;\n}\n\nconst TABS = [\n { id: \"transcript\", label: \"Transcript\", icon: UiChatDots },\n { id: \"files\", label: \"Files\", icon: UiFileText },\n { id: \"plan\", label: \"Plan\", icon: UiStrategy },\n { id: \"approvals\", label: \"Approvals\", icon: UiSealCheck },\n { id: \"costs\", label: \"Costs\", icon: UiCoins },\n { id: \"metadata\", label: \"Metadata\", icon: UiListDashes },\n { id: \"raw\", label: \"Raw\", icon: UiBraces },\n] as const;\n\nexport function SessionInspector({\n session,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n renderSessionActions,\n onPlanChange,\n onResolveApproval,\n composer,\n}: SessionInspectorProps) {\n const detail = useMemo(\n () =>\n isSessionCollectionInput(session) ? undefined : asUnifiedSession(session),\n [session],\n );\n const collection = useMemo(\n () =>\n isSessionCollectionInput(session)\n ? session\n : detail\n ? singleSessionCollection(detail)\n : undefined,\n [detail, session],\n );\n\n if (collection) {\n const optionalProps = {\n ...(className ? { className } : {}),\n ...(transcriptProps ? { transcriptProps } : {}),\n ...(renderSessionActions ? { renderSessionActions } : {}),\n ...(onPlanChange ? { onPlanChange } : {}),\n ...(onResolveApproval ? { onResolveApproval } : {}),\n ...(composer ? { composer } : {}),\n };\n return (\n <CollectionSessionInspector\n collection={collection}\n defaultTab={defaultTab}\n {...optionalProps}\n />\n );\n }\n\n return (\n <LegacySessionInspector\n session={session as SessionInput}\n defaultTab={defaultTab}\n {...(className ? { className } : {})}\n {...(transcriptProps ? { transcriptProps } : {})}\n {...(composer ? { composer } : {})}\n />\n );\n}\n\nfunction CollectionSessionInspector({\n collection,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n renderSessionActions,\n onPlanChange,\n onResolveApproval,\n composer,\n}: Omit<SessionInspectorProps, \"session\"> & {\n collection: SessionCollectionInput;\n}) {\n const hierarchy = useSessionHierarchy(collection);\n const [tab, setTab] = useState<SessionInspectorTab>(defaultTab);\n const transcriptClassName = cn(\"h-full\", transcriptProps?.className);\n const panelDetail = tab === \"costs\" ? hierarchy.filtered : hierarchy.current;\n\n return (\n <div\n className={cn(\n \"flex h-full min-h-0 w-full max-w-full flex-col overflow-hidden rounded-xl border border-border bg-background text-sm shadow-sm\",\n className,\n )}\n >\n <SessionInspectorHeader session={hierarchy.current} />\n <div\n role=\"toolbar\"\n aria-label=\"Session content controls\"\n className=\"flex shrink-0 justify-start border-b border-border px-density-2 py-density-2\"\n >\n <SessionHierarchyPicker\n collection={collection}\n state={hierarchy}\n {...(renderSessionActions ? { renderSessionActions } : {})}\n />\n </div>\n <div\n role=\"tablist\"\n aria-label=\"Session detail view\"\n className=\"flex shrink-0 overflow-x-auto border-b border-border px-density-2\"\n >\n {TABS.map((item) => {\n const badge = tabBadge(item.id, hierarchy.current);\n return (\n <TabButton\n key={item.id}\n active={tab === item.id}\n onClick={() => setTab(item.id)}\n label={tabLabel(\n item.id,\n item.label,\n item.id === \"costs\" ? hierarchy.filtered : hierarchy.current,\n )}\n icon={item.icon}\n variant=\"underline\"\n {...(badge.count === undefined ? {} : { count: badge.count })}\n {...(badge.color ? { countColor: badge.color } : {})}\n className=\"shrink-0 py-density-2 [&_svg]:text-muted-foreground\"\n />\n );\n })}\n </div>\n <div className=\"grid min-h-0 flex-1 overflow-y-auto lg:grid-cols-[minmax(0,1fr)_18rem] lg:overflow-hidden\">\n <main className=\"flex min-h-[28rem] min-w-0 flex-col lg:min-h-0\">\n <div\n className={cn(\n \"min-h-0 flex-1\",\n tab === \"transcript\"\n ? \"overflow-hidden\"\n : \"overflow-auto p-density-4\",\n )}\n >\n {tab === \"transcript\" ? (\n <SessionTranscript\n session={hierarchy.filtered}\n viewerProps={{\n ...transcriptProps,\n className: transcriptClassName,\n }}\n />\n ) : (\n <SessionInspectorPanel\n tab={tab}\n detail={panelDetail}\n session={hierarchy.current}\n {...(onPlanChange ? { onPlanChange } : {})}\n {...(onResolveApproval ? { onResolveApproval } : {})}\n />\n )}\n </div>\n {composer ? (\n <div className=\"shrink-0 border-t border-border p-density-3\">\n {composer}\n </div>\n ) : null}\n </main>\n <SessionInspectorSidebar session={hierarchy.current} />\n </div>\n </div>\n );\n}\n\nfunction LegacySessionInspector({\n session,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n composer,\n}: Pick<\n SessionInspectorProps,\n \"className\" | \"defaultTab\" | \"transcriptProps\" | \"composer\"\n> & {\n session: SessionInput;\n}) {\n const [tab, setTab] = useState<SessionInspectorTab>(defaultTab);\n const transcriptClassName = cn(\"h-full\", transcriptProps?.className);\n return (\n <div\n className={cn(\n \"flex h-full min-h-0 w-full max-w-full flex-col overflow-hidden rounded-xl border border-border bg-background text-sm shadow-sm\",\n className,\n )}\n >\n <div\n role=\"tablist\"\n aria-label=\"Session detail view\"\n className=\"flex shrink-0 overflow-x-auto border-b border-border px-density-2\"\n >\n {TABS.map((item) => (\n <TabButton\n key={item.id}\n active={tab === item.id}\n onClick={() => setTab(item.id)}\n label={item.label}\n icon={item.icon}\n variant=\"underline\"\n className=\"shrink-0 py-density-2 [&_svg]:text-muted-foreground\"\n />\n ))}\n </div>\n <div className=\"flex min-h-0 flex-1 flex-col overflow-hidden\">\n <div className=\"min-h-0 flex-1 overflow-hidden\">\n {tab === \"transcript\" ? (\n <SessionViewer\n session={session}\n scrollable\n showRowMetadata\n {...transcriptProps}\n className={transcriptClassName}\n />\n ) : (\n <SessionInspectorPanel\n tab={tab}\n detail={undefined}\n session={session}\n />\n )}\n </div>\n {composer ? (\n <div className=\"shrink-0 border-t border-border p-density-3\">\n {composer}\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n\n/** The tab's count badge and, for a pending-approvals badge, an amber\n * override so an unresolved approval reads as urgent rather than blending\n * into the neutral resolved-count badge every other tab uses. */\nfunction tabBadge(\n tab: SessionInspectorTab,\n session?: UnifiedSessionInput,\n): { count?: number; color?: string } {\n switch (tab) {\n case \"files\":\n return {\n count:\n (session?.files?.read?.length ?? 0) +\n (session?.files?.written?.length ?? 0),\n };\n case \"approvals\": {\n const pending = pendingApprovalRequests(session?.requests).length;\n if (pending) return { count: pending, color: \"bg-amber-500\" };\n return {\n count:\n (session?.approvals?.approved ?? 0) +\n (session?.approvals?.denied ?? 0),\n };\n }\n default:\n return {};\n }\n}\n\nfunction singleSessionCollection(\n session: UnifiedSessionInput,\n): SessionCollectionInput {\n const id = session.id || \"session\";\n return {\n kind: \"session-collection\",\n id,\n currentSessionId: id,\n sessions: [{ id, session }],\n };\n}\n\nfunction tabLabel(\n tab: SessionInspectorTab,\n label: string,\n session?: UnifiedSessionInput,\n) {\n if (tab !== \"costs\") return label;\n const total = costTotal(session?.cost);\n return total ? `${label} ${formatCost(total)}` : label;\n}\n\nfunction asUnifiedSession(\n session: SessionInput,\n): UnifiedSessionInput | undefined {\n if (typeof session !== \"object\" || session === null || Array.isArray(session))\n return undefined;\n return session as UnifiedSessionInput;\n}\n"],"names":["UiChatDots","UiFileText","UiStrategy","UiSealCheck","UiCoins","UiListDashes","UiBraces","useMemo","isSessionCollectionInput","jsx","useSessionHierarchy","useState","cn","jsxs","SessionInspectorHeader","SessionHierarchyPicker","TabButton","SessionTranscript","SessionInspectorPanel","SessionInspectorSidebar","SessionViewer","pendingApprovalRequests","costTotal","formatCost"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { SessionCollectionItem, SessionInspectorInput } from './SessionInspector.collection';
3
- import { ApprovalResolveHandler } from './SessionInspector.approvals';
3
+ import { ApprovalResolveHandler } from './SessionInspector.approvals-model';
4
4
  import { SessionViewerProps } from './SessionViewer';
5
5
  export type SessionInspectorTab = "transcript" | "files" | "plan" | "approvals" | "costs" | "metadata" | "raw";
6
6
  export interface SessionInspectorProps {
@@ -1 +1 @@
1
- {"version":3,"file":"SessionInspector.d.ts","sourceRoot":"","sources":["../../../src/data/ai/SessionInspector.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAmB1D,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC3B,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAiB,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAIzE,MAAM,MAAM,mBAAmB,GAC3B,YAAY,GACZ,OAAO,GACP,MAAM,GACN,WAAW,GACX,OAAO,GACP,UAAU,GACV,KAAK,CAAC;AAEV,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,qBAAqB,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,eAAe,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,CAAC,CAAC;IACtD,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,qBAAqB,KAAK,SAAS,CAAC;IAClE,+FAA+F;IAC/F,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC;iFAC6E;IAC7E,iBAAiB,CAAC,EAAE,sBAAsB,CAAC;IAC3C,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAYD,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,SAAS,EACT,UAAyB,EACzB,eAAe,EACf,oBAAoB,EACpB,YAAY,EACZ,iBAAiB,EACjB,QAAQ,GACT,EAAE,qBAAqB,+BA2CvB"}
1
+ {"version":3,"file":"SessionInspector.d.ts","sourceRoot":"","sources":["../../../src/data/ai/SessionInspector.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAmB1D,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC3B,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAiB,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAIzE,MAAM,MAAM,mBAAmB,GAC3B,YAAY,GACZ,OAAO,GACP,MAAM,GACN,WAAW,GACX,OAAO,GACP,UAAU,GACV,KAAK,CAAC;AAEV,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,qBAAqB,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,eAAe,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,CAAC,CAAC;IACtD,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,qBAAqB,KAAK,SAAS,CAAC;IAClE,+FAA+F;IAC/F,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC;iFAC6E;IAC7E,iBAAiB,CAAC,EAAE,sBAAsB,CAAC;IAC3C,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAYD,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,SAAS,EACT,UAAyB,EACzB,eAAe,EACf,oBAAoB,EACpB,YAAY,EACZ,iBAAiB,EACjB,QAAQ,GACT,EAAE,qBAAqB,+BA2CvB"}
@@ -9,7 +9,7 @@ import { SessionTranscript } from "./SessionInspector.transcript.js";
9
9
  import { isSessionCollectionInput } from "./SessionInspector.collection.js";
10
10
  import { SessionHierarchyPicker } from "./SessionInspector.hierarchy.js";
11
11
  import { useSessionHierarchy } from "./SessionInspector.hierarchy-state.js";
12
- import { pendingApprovalRequests } from "./SessionInspector.approvals.js";
12
+ import { pendingApprovalRequests } from "./SessionInspector.approvals-model.js";
13
13
  import { SessionViewer } from "./SessionViewer.js";
14
14
  import { UiChatDots } from "../../icons/components/UiChatDots.js";
15
15
  import { UiFileText } from "../../icons/components/UiFileText.js";
@@ -1 +1 @@
1
- {"version":3,"file":"SessionInspector.js","sources":["../../../src/data/ai/SessionInspector.tsx"],"sourcesContent":["import { useMemo, useState, type ReactNode } from \"react\";\nimport {\n UiBraces,\n UiChatDots,\n UiCoins,\n UiFileText,\n UiListDashes,\n UiSealCheck,\n UiStrategy,\n} from \"../../icons\";\nimport { cn } from \"../../lib/utils\";\nimport { TabButton } from \"../TabButton\";\nimport { formatCost, costTotal } from \"./session-cost\";\nimport { SessionInspectorPanel } from \"./SessionInspector.panels\";\nimport {\n SessionInspectorHeader,\n SessionInspectorSidebar,\n} from \"./SessionInspector.summary\";\nimport { SessionTranscript } from \"./SessionInspector.transcript\";\nimport {\n isSessionCollectionInput,\n type SessionCollectionInput,\n type SessionCollectionItem,\n type SessionInspectorInput,\n} from \"./SessionInspector.collection\";\nimport { SessionHierarchyPicker } from \"./SessionInspector.hierarchy\";\nimport { useSessionHierarchy } from \"./SessionInspector.hierarchy-state\";\nimport {\n pendingApprovalRequests,\n type ApprovalResolveHandler,\n} from \"./SessionInspector.approvals\";\nimport { SessionViewer, type SessionViewerProps } from \"./SessionViewer\";\nimport type { SessionInput } from \"./SessionViewer.model\";\nimport type { UnifiedSessionInput } from \"./SessionViewer.unified\";\n\nexport type SessionInspectorTab =\n | \"transcript\"\n | \"files\"\n | \"plan\"\n | \"approvals\"\n | \"costs\"\n | \"metadata\"\n | \"raw\";\n\nexport interface SessionInspectorProps {\n session: SessionInspectorInput;\n className?: string;\n defaultTab?: SessionInspectorTab;\n transcriptProps?: Omit<SessionViewerProps, \"session\">;\n renderSessionActions?: (item: SessionCollectionItem) => ReactNode;\n /** Receives edits made in the Plan tab. The inspector also keeps the draft visible locally. */\n onPlanChange?: (content: string) => void;\n /** Resolves one pending tool approval from the Approvals tab. Omitted, the\n * tab still lists pending requests but renders no Approve/Deny controls. */\n onResolveApproval?: ApprovalResolveHandler;\n composer?: ReactNode;\n}\n\nconst TABS = [\n { id: \"transcript\", label: \"Transcript\", icon: UiChatDots },\n { id: \"files\", label: \"Files\", icon: UiFileText },\n { id: \"plan\", label: \"Plan\", icon: UiStrategy },\n { id: \"approvals\", label: \"Approvals\", icon: UiSealCheck },\n { id: \"costs\", label: \"Costs\", icon: UiCoins },\n { id: \"metadata\", label: \"Metadata\", icon: UiListDashes },\n { id: \"raw\", label: \"Raw\", icon: UiBraces },\n] as const;\n\nexport function SessionInspector({\n session,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n renderSessionActions,\n onPlanChange,\n onResolveApproval,\n composer,\n}: SessionInspectorProps) {\n const detail = useMemo(\n () =>\n isSessionCollectionInput(session) ? undefined : asUnifiedSession(session),\n [session],\n );\n const collection = useMemo(\n () =>\n isSessionCollectionInput(session)\n ? session\n : detail\n ? singleSessionCollection(detail)\n : undefined,\n [detail, session],\n );\n\n if (collection) {\n const optionalProps = {\n ...(className ? { className } : {}),\n ...(transcriptProps ? { transcriptProps } : {}),\n ...(renderSessionActions ? { renderSessionActions } : {}),\n ...(onPlanChange ? { onPlanChange } : {}),\n ...(onResolveApproval ? { onResolveApproval } : {}),\n ...(composer ? { composer } : {}),\n };\n return (\n <CollectionSessionInspector\n collection={collection}\n defaultTab={defaultTab}\n {...optionalProps}\n />\n );\n }\n\n return (\n <LegacySessionInspector\n session={session as SessionInput}\n defaultTab={defaultTab}\n {...(className ? { className } : {})}\n {...(transcriptProps ? { transcriptProps } : {})}\n {...(composer ? { composer } : {})}\n />\n );\n}\n\nfunction CollectionSessionInspector({\n collection,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n renderSessionActions,\n onPlanChange,\n onResolveApproval,\n composer,\n}: Omit<SessionInspectorProps, \"session\"> & {\n collection: SessionCollectionInput;\n}) {\n const hierarchy = useSessionHierarchy(collection);\n const [tab, setTab] = useState<SessionInspectorTab>(defaultTab);\n const transcriptClassName = cn(\"h-full\", transcriptProps?.className);\n const panelDetail = tab === \"costs\" ? hierarchy.filtered : hierarchy.current;\n\n return (\n <div\n className={cn(\n \"flex h-full min-h-0 w-full max-w-full flex-col overflow-hidden rounded-xl border border-border bg-background text-sm shadow-sm\",\n className,\n )}\n >\n <SessionInspectorHeader session={hierarchy.current} />\n <div\n role=\"toolbar\"\n aria-label=\"Session content controls\"\n className=\"flex shrink-0 justify-start border-b border-border px-density-2 py-density-2\"\n >\n <SessionHierarchyPicker\n collection={collection}\n state={hierarchy}\n {...(renderSessionActions ? { renderSessionActions } : {})}\n />\n </div>\n <div\n role=\"tablist\"\n aria-label=\"Session detail view\"\n className=\"flex shrink-0 overflow-x-auto border-b border-border px-density-2\"\n >\n {TABS.map((item) => {\n const badge = tabBadge(item.id, hierarchy.current);\n return (\n <TabButton\n key={item.id}\n active={tab === item.id}\n onClick={() => setTab(item.id)}\n label={tabLabel(\n item.id,\n item.label,\n item.id === \"costs\" ? hierarchy.filtered : hierarchy.current,\n )}\n icon={item.icon}\n variant=\"underline\"\n {...(badge.count === undefined ? {} : { count: badge.count })}\n {...(badge.color ? { countColor: badge.color } : {})}\n className=\"shrink-0 py-density-2 [&_svg]:text-muted-foreground\"\n />\n );\n })}\n </div>\n <div className=\"grid min-h-0 flex-1 overflow-y-auto lg:grid-cols-[minmax(0,1fr)_18rem] lg:overflow-hidden\">\n <main className=\"flex min-h-[28rem] min-w-0 flex-col lg:min-h-0\">\n <div\n className={cn(\n \"min-h-0 flex-1\",\n tab === \"transcript\"\n ? \"overflow-hidden\"\n : \"overflow-auto p-density-4\",\n )}\n >\n {tab === \"transcript\" ? (\n <SessionTranscript\n session={hierarchy.filtered}\n viewerProps={{\n ...transcriptProps,\n className: transcriptClassName,\n }}\n />\n ) : (\n <SessionInspectorPanel\n tab={tab}\n detail={panelDetail}\n session={hierarchy.current}\n {...(onPlanChange ? { onPlanChange } : {})}\n {...(onResolveApproval ? { onResolveApproval } : {})}\n />\n )}\n </div>\n {composer ? (\n <div className=\"shrink-0 border-t border-border p-density-3\">\n {composer}\n </div>\n ) : null}\n </main>\n <SessionInspectorSidebar session={hierarchy.current} />\n </div>\n </div>\n );\n}\n\nfunction LegacySessionInspector({\n session,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n composer,\n}: Pick<\n SessionInspectorProps,\n \"className\" | \"defaultTab\" | \"transcriptProps\" | \"composer\"\n> & {\n session: SessionInput;\n}) {\n const [tab, setTab] = useState<SessionInspectorTab>(defaultTab);\n const transcriptClassName = cn(\"h-full\", transcriptProps?.className);\n return (\n <div\n className={cn(\n \"flex h-full min-h-0 w-full max-w-full flex-col overflow-hidden rounded-xl border border-border bg-background text-sm shadow-sm\",\n className,\n )}\n >\n <div\n role=\"tablist\"\n aria-label=\"Session detail view\"\n className=\"flex shrink-0 overflow-x-auto border-b border-border px-density-2\"\n >\n {TABS.map((item) => (\n <TabButton\n key={item.id}\n active={tab === item.id}\n onClick={() => setTab(item.id)}\n label={item.label}\n icon={item.icon}\n variant=\"underline\"\n className=\"shrink-0 py-density-2 [&_svg]:text-muted-foreground\"\n />\n ))}\n </div>\n <div className=\"flex min-h-0 flex-1 flex-col overflow-hidden\">\n <div className=\"min-h-0 flex-1 overflow-hidden\">\n {tab === \"transcript\" ? (\n <SessionViewer\n session={session}\n scrollable\n showRowMetadata\n {...transcriptProps}\n className={transcriptClassName}\n />\n ) : (\n <SessionInspectorPanel\n tab={tab}\n detail={undefined}\n session={session}\n />\n )}\n </div>\n {composer ? (\n <div className=\"shrink-0 border-t border-border p-density-3\">\n {composer}\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n\n/** The tab's count badge and, for a pending-approvals badge, an amber\n * override so an unresolved approval reads as urgent rather than blending\n * into the neutral resolved-count badge every other tab uses. */\nfunction tabBadge(\n tab: SessionInspectorTab,\n session?: UnifiedSessionInput,\n): { count?: number; color?: string } {\n switch (tab) {\n case \"files\":\n return {\n count:\n (session?.files?.read?.length ?? 0) +\n (session?.files?.written?.length ?? 0),\n };\n case \"approvals\": {\n const pending = pendingApprovalRequests(session?.requests).length;\n if (pending) return { count: pending, color: \"bg-amber-500\" };\n return {\n count:\n (session?.approvals?.approved ?? 0) +\n (session?.approvals?.denied ?? 0),\n };\n }\n default:\n return {};\n }\n}\n\nfunction singleSessionCollection(\n session: UnifiedSessionInput,\n): SessionCollectionInput {\n const id = session.id || \"session\";\n return {\n kind: \"session-collection\",\n id,\n currentSessionId: id,\n sessions: [{ id, session }],\n };\n}\n\nfunction tabLabel(\n tab: SessionInspectorTab,\n label: string,\n session?: UnifiedSessionInput,\n) {\n if (tab !== \"costs\") return label;\n const total = costTotal(session?.cost);\n return total ? `${label} ${formatCost(total)}` : label;\n}\n\nfunction asUnifiedSession(\n session: SessionInput,\n): UnifiedSessionInput | undefined {\n if (typeof session !== \"object\" || session === null || Array.isArray(session))\n return undefined;\n return session as UnifiedSessionInput;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SessionInspector.js","sources":["../../../src/data/ai/SessionInspector.tsx"],"sourcesContent":["import { useMemo, useState, type ReactNode } from \"react\";\nimport {\n UiBraces,\n UiChatDots,\n UiCoins,\n UiFileText,\n UiListDashes,\n UiSealCheck,\n UiStrategy,\n} from \"../../icons\";\nimport { cn } from \"../../lib/utils\";\nimport { TabButton } from \"../TabButton\";\nimport { formatCost, costTotal } from \"./session-cost\";\nimport { SessionInspectorPanel } from \"./SessionInspector.panels\";\nimport {\n SessionInspectorHeader,\n SessionInspectorSidebar,\n} from \"./SessionInspector.summary\";\nimport { SessionTranscript } from \"./SessionInspector.transcript\";\nimport {\n isSessionCollectionInput,\n type SessionCollectionInput,\n type SessionCollectionItem,\n type SessionInspectorInput,\n} from \"./SessionInspector.collection\";\nimport { SessionHierarchyPicker } from \"./SessionInspector.hierarchy\";\nimport { useSessionHierarchy } from \"./SessionInspector.hierarchy-state\";\nimport {\n pendingApprovalRequests,\n type ApprovalResolveHandler,\n} from \"./SessionInspector.approvals-model\";\nimport { SessionViewer, type SessionViewerProps } from \"./SessionViewer\";\nimport type { SessionInput } from \"./SessionViewer.model\";\nimport type { UnifiedSessionInput } from \"./SessionViewer.unified\";\n\nexport type SessionInspectorTab =\n | \"transcript\"\n | \"files\"\n | \"plan\"\n | \"approvals\"\n | \"costs\"\n | \"metadata\"\n | \"raw\";\n\nexport interface SessionInspectorProps {\n session: SessionInspectorInput;\n className?: string;\n defaultTab?: SessionInspectorTab;\n transcriptProps?: Omit<SessionViewerProps, \"session\">;\n renderSessionActions?: (item: SessionCollectionItem) => ReactNode;\n /** Receives edits made in the Plan tab. The inspector also keeps the draft visible locally. */\n onPlanChange?: (content: string) => void;\n /** Resolves one pending tool approval from the Approvals tab. Omitted, the\n * tab still lists pending requests but renders no Approve/Deny controls. */\n onResolveApproval?: ApprovalResolveHandler;\n composer?: ReactNode;\n}\n\nconst TABS = [\n { id: \"transcript\", label: \"Transcript\", icon: UiChatDots },\n { id: \"files\", label: \"Files\", icon: UiFileText },\n { id: \"plan\", label: \"Plan\", icon: UiStrategy },\n { id: \"approvals\", label: \"Approvals\", icon: UiSealCheck },\n { id: \"costs\", label: \"Costs\", icon: UiCoins },\n { id: \"metadata\", label: \"Metadata\", icon: UiListDashes },\n { id: \"raw\", label: \"Raw\", icon: UiBraces },\n] as const;\n\nexport function SessionInspector({\n session,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n renderSessionActions,\n onPlanChange,\n onResolveApproval,\n composer,\n}: SessionInspectorProps) {\n const detail = useMemo(\n () =>\n isSessionCollectionInput(session) ? undefined : asUnifiedSession(session),\n [session],\n );\n const collection = useMemo(\n () =>\n isSessionCollectionInput(session)\n ? session\n : detail\n ? singleSessionCollection(detail)\n : undefined,\n [detail, session],\n );\n\n if (collection) {\n const optionalProps = {\n ...(className ? { className } : {}),\n ...(transcriptProps ? { transcriptProps } : {}),\n ...(renderSessionActions ? { renderSessionActions } : {}),\n ...(onPlanChange ? { onPlanChange } : {}),\n ...(onResolveApproval ? { onResolveApproval } : {}),\n ...(composer ? { composer } : {}),\n };\n return (\n <CollectionSessionInspector\n collection={collection}\n defaultTab={defaultTab}\n {...optionalProps}\n />\n );\n }\n\n return (\n <LegacySessionInspector\n session={session as SessionInput}\n defaultTab={defaultTab}\n {...(className ? { className } : {})}\n {...(transcriptProps ? { transcriptProps } : {})}\n {...(composer ? { composer } : {})}\n />\n );\n}\n\nfunction CollectionSessionInspector({\n collection,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n renderSessionActions,\n onPlanChange,\n onResolveApproval,\n composer,\n}: Omit<SessionInspectorProps, \"session\"> & {\n collection: SessionCollectionInput;\n}) {\n const hierarchy = useSessionHierarchy(collection);\n const [tab, setTab] = useState<SessionInspectorTab>(defaultTab);\n const transcriptClassName = cn(\"h-full\", transcriptProps?.className);\n const panelDetail = tab === \"costs\" ? hierarchy.filtered : hierarchy.current;\n\n return (\n <div\n className={cn(\n \"flex h-full min-h-0 w-full max-w-full flex-col overflow-hidden rounded-xl border border-border bg-background text-sm shadow-sm\",\n className,\n )}\n >\n <SessionInspectorHeader session={hierarchy.current} />\n <div\n role=\"toolbar\"\n aria-label=\"Session content controls\"\n className=\"flex shrink-0 justify-start border-b border-border px-density-2 py-density-2\"\n >\n <SessionHierarchyPicker\n collection={collection}\n state={hierarchy}\n {...(renderSessionActions ? { renderSessionActions } : {})}\n />\n </div>\n <div\n role=\"tablist\"\n aria-label=\"Session detail view\"\n className=\"flex shrink-0 overflow-x-auto border-b border-border px-density-2\"\n >\n {TABS.map((item) => {\n const badge = tabBadge(item.id, hierarchy.current);\n return (\n <TabButton\n key={item.id}\n active={tab === item.id}\n onClick={() => setTab(item.id)}\n label={tabLabel(\n item.id,\n item.label,\n item.id === \"costs\" ? hierarchy.filtered : hierarchy.current,\n )}\n icon={item.icon}\n variant=\"underline\"\n {...(badge.count === undefined ? {} : { count: badge.count })}\n {...(badge.color ? { countColor: badge.color } : {})}\n className=\"shrink-0 py-density-2 [&_svg]:text-muted-foreground\"\n />\n );\n })}\n </div>\n <div className=\"grid min-h-0 flex-1 overflow-y-auto lg:grid-cols-[minmax(0,1fr)_18rem] lg:overflow-hidden\">\n <main className=\"flex min-h-[28rem] min-w-0 flex-col lg:min-h-0\">\n <div\n className={cn(\n \"min-h-0 flex-1\",\n tab === \"transcript\"\n ? \"overflow-hidden\"\n : \"overflow-auto p-density-4\",\n )}\n >\n {tab === \"transcript\" ? (\n <SessionTranscript\n session={hierarchy.filtered}\n viewerProps={{\n ...transcriptProps,\n className: transcriptClassName,\n }}\n />\n ) : (\n <SessionInspectorPanel\n tab={tab}\n detail={panelDetail}\n session={hierarchy.current}\n {...(onPlanChange ? { onPlanChange } : {})}\n {...(onResolveApproval ? { onResolveApproval } : {})}\n />\n )}\n </div>\n {composer ? (\n <div className=\"shrink-0 border-t border-border p-density-3\">\n {composer}\n </div>\n ) : null}\n </main>\n <SessionInspectorSidebar session={hierarchy.current} />\n </div>\n </div>\n );\n}\n\nfunction LegacySessionInspector({\n session,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n composer,\n}: Pick<\n SessionInspectorProps,\n \"className\" | \"defaultTab\" | \"transcriptProps\" | \"composer\"\n> & {\n session: SessionInput;\n}) {\n const [tab, setTab] = useState<SessionInspectorTab>(defaultTab);\n const transcriptClassName = cn(\"h-full\", transcriptProps?.className);\n return (\n <div\n className={cn(\n \"flex h-full min-h-0 w-full max-w-full flex-col overflow-hidden rounded-xl border border-border bg-background text-sm shadow-sm\",\n className,\n )}\n >\n <div\n role=\"tablist\"\n aria-label=\"Session detail view\"\n className=\"flex shrink-0 overflow-x-auto border-b border-border px-density-2\"\n >\n {TABS.map((item) => (\n <TabButton\n key={item.id}\n active={tab === item.id}\n onClick={() => setTab(item.id)}\n label={item.label}\n icon={item.icon}\n variant=\"underline\"\n className=\"shrink-0 py-density-2 [&_svg]:text-muted-foreground\"\n />\n ))}\n </div>\n <div className=\"flex min-h-0 flex-1 flex-col overflow-hidden\">\n <div className=\"min-h-0 flex-1 overflow-hidden\">\n {tab === \"transcript\" ? (\n <SessionViewer\n session={session}\n scrollable\n showRowMetadata\n {...transcriptProps}\n className={transcriptClassName}\n />\n ) : (\n <SessionInspectorPanel\n tab={tab}\n detail={undefined}\n session={session}\n />\n )}\n </div>\n {composer ? (\n <div className=\"shrink-0 border-t border-border p-density-3\">\n {composer}\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n\n/** The tab's count badge and, for a pending-approvals badge, an amber\n * override so an unresolved approval reads as urgent rather than blending\n * into the neutral resolved-count badge every other tab uses. */\nfunction tabBadge(\n tab: SessionInspectorTab,\n session?: UnifiedSessionInput,\n): { count?: number; color?: string } {\n switch (tab) {\n case \"files\":\n return {\n count:\n (session?.files?.read?.length ?? 0) +\n (session?.files?.written?.length ?? 0),\n };\n case \"approvals\": {\n const pending = pendingApprovalRequests(session?.requests).length;\n if (pending) return { count: pending, color: \"bg-amber-500\" };\n return {\n count:\n (session?.approvals?.approved ?? 0) +\n (session?.approvals?.denied ?? 0),\n };\n }\n default:\n return {};\n }\n}\n\nfunction singleSessionCollection(\n session: UnifiedSessionInput,\n): SessionCollectionInput {\n const id = session.id || \"session\";\n return {\n kind: \"session-collection\",\n id,\n currentSessionId: id,\n sessions: [{ id, session }],\n };\n}\n\nfunction tabLabel(\n tab: SessionInspectorTab,\n label: string,\n session?: UnifiedSessionInput,\n) {\n if (tab !== \"costs\") return label;\n const total = costTotal(session?.cost);\n return total ? `${label} ${formatCost(total)}` : label;\n}\n\nfunction asUnifiedSession(\n session: SessionInput,\n): UnifiedSessionInput | undefined {\n if (typeof session !== \"object\" || session === null || Array.isArray(session))\n return undefined;\n return session as UnifiedSessionInput;\n}\n"],"names":[],"mappings":"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"}
@@ -29,19 +29,6 @@ function SimpleList({
29
29
  ] }, row.key)) })
30
30
  ] });
31
31
  }
32
- function kv(label, value) {
33
- return {
34
- key: String(label),
35
- label,
36
- value: value === void 0 || value === null || value === "" ? muted("-") : value,
37
- hidden: value === void 0 || value === null || value === ""
38
- };
39
- }
40
- function muted(value) {
41
- return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: value });
42
- }
43
32
  exports.EmptyState = EmptyState;
44
33
  exports.SimpleList = SimpleList;
45
- exports.kv = kv;
46
- exports.muted = muted;
47
34
  //# sourceMappingURL=SessionInspector.panel-parts.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"SessionInspector.panel-parts.cjs","sources":["../../../src/data/ai/SessionInspector.panel-parts.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport type { KeyValueListItem } from \"../KeyValueList\";\n\n/** Small display primitives shared by the SessionInspector detail panels\n * (costs, metadata, approvals, …) — kept in their own module so panel files\n * can depend on them without importing each other. */\n\nexport function EmptyState({\n children,\n compact = false,\n}: {\n children: ReactNode;\n compact?: boolean;\n}) {\n return (\n <div\n className={cn(\n \"rounded-md border border-dashed border-border text-sm text-muted-foreground\",\n compact ? \"p-density-3\" : \"p-density-6 text-center\"\n )}\n >\n {children}\n </div>\n );\n}\n\nexport function SimpleList({\n title,\n rows,\n}: {\n title: string;\n rows: Array<{ key: string; title?: ReactNode; detail?: ReactNode }>;\n}) {\n return (\n <section>\n <h3 className=\"mb-density-2 text-xs font-semibold uppercase text-muted-foreground\">\n {title}\n </h3>\n <ul className=\"divide-y divide-border rounded-md border border-border\">\n {rows.map((row) => (\n <li key={row.key} className=\"px-density-3 py-density-2\">\n <div className=\"text-sm font-medium\">{row.title || row.key}</div>\n {row.detail ? (\n <div className=\"mt-0.5 text-xs text-muted-foreground\">\n {row.detail}\n </div>\n ) : null}\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\nexport function kv(\n label: ReactNode,\n value: ReactNode | undefined | null\n): KeyValueListItem {\n return {\n key: String(label),\n label,\n value:\n value === undefined || value === null || value === \"\"\n ? muted(\"-\")\n : value,\n hidden: value === undefined || value === null || value === \"\",\n };\n}\n\nexport function muted(value: ReactNode) {\n return <span className=\"text-muted-foreground\">{value}</span>;\n}\n"],"names":["jsx","cn","jsxs"],"mappings":";;;;AAQO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA,UAAU;AACZ,GAGG;AACD,SACEA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWC,MAAAA;AAAAA,QACT;AAAA,QACA,UAAU,gBAAgB;AAAA,MAAA;AAAA,MAG3B;AAAA,IAAA;AAAA,EAAA;AAGP;AAEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AACF,GAGG;AACD,yCACG,WAAA,EACC,UAAA;AAAA,IAAAD,2BAAAA,IAAC,MAAA,EAAG,WAAU,sEACX,UAAA,OACH;AAAA,IACAA,2BAAAA,IAAC,MAAA,EAAG,WAAU,0DACX,UAAA,KAAK,IAAI,CAAC,QACTE,2BAAAA,KAAC,MAAA,EAAiB,WAAU,6BAC1B,UAAA;AAAA,MAAAF,+BAAC,SAAI,WAAU,uBAAuB,UAAA,IAAI,SAAS,IAAI,KAAI;AAAA,MAC1D,IAAI,SACHA,+BAAC,OAAA,EAAI,WAAU,wCACZ,UAAA,IAAI,QACP,IACE;AAAA,IAAA,KANG,IAAI,GAOb,CACD,EAAA,CACH;AAAA,EAAA,GACF;AAEJ;AAEO,SAAS,GACd,OACA,OACkB;AAClB,SAAO;AAAA,IACL,KAAK,OAAO,KAAK;AAAA,IACjB;AAAA,IACA,OACE,UAAU,UAAa,UAAU,QAAQ,UAAU,KAC/C,MAAM,GAAG,IACT;AAAA,IACN,QAAQ,UAAU,UAAa,UAAU,QAAQ,UAAU;AAAA,EAAA;AAE/D;AAEO,SAAS,MAAM,OAAkB;AACtC,SAAOA,2BAAAA,IAAC,QAAA,EAAK,WAAU,yBAAyB,UAAA,OAAM;AACxD;;;;;"}
1
+ {"version":3,"file":"SessionInspector.panel-parts.cjs","sources":["../../../src/data/ai/SessionInspector.panel-parts.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\n\n/** Small display components shared by the SessionInspector detail panels\n * (costs, metadata, approvals, …) — kept in their own module so panel files\n * can depend on them without importing each other. The value builders they are\n * used with live in SessionInspector.panel-values, which exports no components\n * so that neither module loses fast refresh to the other. */\n\nexport function EmptyState({\n children,\n compact = false,\n}: {\n children: ReactNode;\n compact?: boolean;\n}) {\n return (\n <div\n className={cn(\n \"rounded-md border border-dashed border-border text-sm text-muted-foreground\",\n compact ? \"p-density-3\" : \"p-density-6 text-center\"\n )}\n >\n {children}\n </div>\n );\n}\n\nexport function SimpleList({\n title,\n rows,\n}: {\n title: string;\n rows: Array<{ key: string; title?: ReactNode; detail?: ReactNode }>;\n}) {\n return (\n <section>\n <h3 className=\"mb-density-2 text-xs font-semibold uppercase text-muted-foreground\">\n {title}\n </h3>\n <ul className=\"divide-y divide-border rounded-md border border-border\">\n {rows.map((row) => (\n <li key={row.key} className=\"px-density-3 py-density-2\">\n <div className=\"text-sm font-medium\">{row.title || row.key}</div>\n {row.detail ? (\n <div className=\"mt-0.5 text-xs text-muted-foreground\">\n {row.detail}\n </div>\n ) : null}\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\n"],"names":["jsx","cn","jsxs"],"mappings":";;;;AASO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA,UAAU;AACZ,GAGG;AACD,SACEA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWC,MAAAA;AAAAA,QACT;AAAA,QACA,UAAU,gBAAgB;AAAA,MAAA;AAAA,MAG3B;AAAA,IAAA;AAAA,EAAA;AAGP;AAEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AACF,GAGG;AACD,yCACG,WAAA,EACC,UAAA;AAAA,IAAAD,2BAAAA,IAAC,MAAA,EAAG,WAAU,sEACX,UAAA,OACH;AAAA,IACAA,2BAAAA,IAAC,MAAA,EAAG,WAAU,0DACX,UAAA,KAAK,IAAI,CAAC,QACTE,2BAAAA,KAAC,MAAA,EAAiB,WAAU,6BAC1B,UAAA;AAAA,MAAAF,+BAAC,SAAI,WAAU,uBAAuB,UAAA,IAAI,SAAS,IAAI,KAAI;AAAA,MAC1D,IAAI,SACHA,+BAAC,OAAA,EAAI,WAAU,wCACZ,UAAA,IAAI,QACP,IACE;AAAA,IAAA,KANG,IAAI,GAOb,CACD,EAAA,CACH;AAAA,EAAA,GACF;AAEJ;;;"}
@@ -1,8 +1,9 @@
1
1
  import { ReactNode } from 'react';
2
- import { KeyValueListItem } from '../KeyValueList';
3
- /** Small display primitives shared by the SessionInspector detail panels
2
+ /** Small display components shared by the SessionInspector detail panels
4
3
  * (costs, metadata, approvals, …) — kept in their own module so panel files
5
- * can depend on them without importing each other. */
4
+ * can depend on them without importing each other. The value builders they are
5
+ * used with live in SessionInspector.panel-values, which exports no components
6
+ * so that neither module loses fast refresh to the other. */
6
7
  export declare function EmptyState({ children, compact, }: {
7
8
  children: ReactNode;
8
9
  compact?: boolean;
@@ -15,6 +16,4 @@ export declare function SimpleList({ title, rows, }: {
15
16
  detail?: ReactNode;
16
17
  }>;
17
18
  }): import("react").JSX.Element;
18
- export declare function kv(label: ReactNode, value: ReactNode | undefined | null): KeyValueListItem;
19
- export declare function muted(value: ReactNode): import("react").JSX.Element;
20
19
  //# sourceMappingURL=SessionInspector.panel-parts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SessionInspector.panel-parts.d.ts","sourceRoot":"","sources":["../../../src/data/ai/SessionInspector.panel-parts.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD;;uDAEuD;AAEvD,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,OAAe,GAChB,EAAE;IACD,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,+BAWA;AAED,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,IAAI,GACL,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,SAAS,CAAC;QAAC,MAAM,CAAC,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;CACrE,+BAoBA;AAED,wBAAgB,EAAE,CAChB,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,IAAI,GAClC,gBAAgB,CAUlB;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,SAAS,+BAErC"}
1
+ {"version":3,"file":"SessionInspector.panel-parts.d.ts","sourceRoot":"","sources":["../../../src/data/ai/SessionInspector.panel-parts.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC;;;;8DAI8D;AAE9D,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,OAAe,GAChB,EAAE;IACD,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,+BAWA;AAED,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,IAAI,GACL,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,SAAS,CAAC;QAAC,MAAM,CAAC,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;CACrE,+BAoBA"}
@@ -27,21 +27,8 @@ function SimpleList({
27
27
  ] }, row.key)) })
28
28
  ] });
29
29
  }
30
- function kv(label, value) {
31
- return {
32
- key: String(label),
33
- label,
34
- value: value === void 0 || value === null || value === "" ? muted("-") : value,
35
- hidden: value === void 0 || value === null || value === ""
36
- };
37
- }
38
- function muted(value) {
39
- return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: value });
40
- }
41
30
  export {
42
31
  EmptyState,
43
- SimpleList,
44
- kv,
45
- muted
32
+ SimpleList
46
33
  };
47
34
  //# sourceMappingURL=SessionInspector.panel-parts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SessionInspector.panel-parts.js","sources":["../../../src/data/ai/SessionInspector.panel-parts.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport type { KeyValueListItem } from \"../KeyValueList\";\n\n/** Small display primitives shared by the SessionInspector detail panels\n * (costs, metadata, approvals, …) — kept in their own module so panel files\n * can depend on them without importing each other. */\n\nexport function EmptyState({\n children,\n compact = false,\n}: {\n children: ReactNode;\n compact?: boolean;\n}) {\n return (\n <div\n className={cn(\n \"rounded-md border border-dashed border-border text-sm text-muted-foreground\",\n compact ? \"p-density-3\" : \"p-density-6 text-center\"\n )}\n >\n {children}\n </div>\n );\n}\n\nexport function SimpleList({\n title,\n rows,\n}: {\n title: string;\n rows: Array<{ key: string; title?: ReactNode; detail?: ReactNode }>;\n}) {\n return (\n <section>\n <h3 className=\"mb-density-2 text-xs font-semibold uppercase text-muted-foreground\">\n {title}\n </h3>\n <ul className=\"divide-y divide-border rounded-md border border-border\">\n {rows.map((row) => (\n <li key={row.key} className=\"px-density-3 py-density-2\">\n <div className=\"text-sm font-medium\">{row.title || row.key}</div>\n {row.detail ? (\n <div className=\"mt-0.5 text-xs text-muted-foreground\">\n {row.detail}\n </div>\n ) : null}\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\nexport function kv(\n label: ReactNode,\n value: ReactNode | undefined | null\n): KeyValueListItem {\n return {\n key: String(label),\n label,\n value:\n value === undefined || value === null || value === \"\"\n ? muted(\"-\")\n : value,\n hidden: value === undefined || value === null || value === \"\",\n };\n}\n\nexport function muted(value: ReactNode) {\n return <span className=\"text-muted-foreground\">{value}</span>;\n}\n"],"names":[],"mappings":";;AAQO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA,UAAU;AACZ,GAGG;AACD,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,UAAU,gBAAgB;AAAA,MAAA;AAAA,MAG3B;AAAA,IAAA;AAAA,EAAA;AAGP;AAEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AACF,GAGG;AACD,8BACG,WAAA,EACC,UAAA;AAAA,IAAA,oBAAC,MAAA,EAAG,WAAU,sEACX,UAAA,OACH;AAAA,IACA,oBAAC,MAAA,EAAG,WAAU,0DACX,UAAA,KAAK,IAAI,CAAC,QACT,qBAAC,MAAA,EAAiB,WAAU,6BAC1B,UAAA;AAAA,MAAA,oBAAC,SAAI,WAAU,uBAAuB,UAAA,IAAI,SAAS,IAAI,KAAI;AAAA,MAC1D,IAAI,SACH,oBAAC,OAAA,EAAI,WAAU,wCACZ,UAAA,IAAI,QACP,IACE;AAAA,IAAA,KANG,IAAI,GAOb,CACD,EAAA,CACH;AAAA,EAAA,GACF;AAEJ;AAEO,SAAS,GACd,OACA,OACkB;AAClB,SAAO;AAAA,IACL,KAAK,OAAO,KAAK;AAAA,IACjB;AAAA,IACA,OACE,UAAU,UAAa,UAAU,QAAQ,UAAU,KAC/C,MAAM,GAAG,IACT;AAAA,IACN,QAAQ,UAAU,UAAa,UAAU,QAAQ,UAAU;AAAA,EAAA;AAE/D;AAEO,SAAS,MAAM,OAAkB;AACtC,SAAO,oBAAC,QAAA,EAAK,WAAU,yBAAyB,UAAA,OAAM;AACxD;"}
1
+ {"version":3,"file":"SessionInspector.panel-parts.js","sources":["../../../src/data/ai/SessionInspector.panel-parts.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\n\n/** Small display components shared by the SessionInspector detail panels\n * (costs, metadata, approvals, …) — kept in their own module so panel files\n * can depend on them without importing each other. The value builders they are\n * used with live in SessionInspector.panel-values, which exports no components\n * so that neither module loses fast refresh to the other. */\n\nexport function EmptyState({\n children,\n compact = false,\n}: {\n children: ReactNode;\n compact?: boolean;\n}) {\n return (\n <div\n className={cn(\n \"rounded-md border border-dashed border-border text-sm text-muted-foreground\",\n compact ? \"p-density-3\" : \"p-density-6 text-center\"\n )}\n >\n {children}\n </div>\n );\n}\n\nexport function SimpleList({\n title,\n rows,\n}: {\n title: string;\n rows: Array<{ key: string; title?: ReactNode; detail?: ReactNode }>;\n}) {\n return (\n <section>\n <h3 className=\"mb-density-2 text-xs font-semibold uppercase text-muted-foreground\">\n {title}\n </h3>\n <ul className=\"divide-y divide-border rounded-md border border-border\">\n {rows.map((row) => (\n <li key={row.key} className=\"px-density-3 py-density-2\">\n <div className=\"text-sm font-medium\">{row.title || row.key}</div>\n {row.detail ? (\n <div className=\"mt-0.5 text-xs text-muted-foreground\">\n {row.detail}\n </div>\n ) : null}\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\n"],"names":[],"mappings":";;AASO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA,UAAU;AACZ,GAGG;AACD,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,UAAU,gBAAgB;AAAA,MAAA;AAAA,MAG3B;AAAA,IAAA;AAAA,EAAA;AAGP;AAEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AACF,GAGG;AACD,8BACG,WAAA,EACC,UAAA;AAAA,IAAA,oBAAC,MAAA,EAAG,WAAU,sEACX,UAAA,OACH;AAAA,IACA,oBAAC,MAAA,EAAG,WAAU,0DACX,UAAA,KAAK,IAAI,CAAC,QACT,qBAAC,MAAA,EAAiB,WAAU,6BAC1B,UAAA;AAAA,MAAA,oBAAC,SAAI,WAAU,uBAAuB,UAAA,IAAI,SAAS,IAAI,KAAI;AAAA,MAC1D,IAAI,SACH,oBAAC,OAAA,EAAI,WAAU,wCACZ,UAAA,IAAI,QACP,IACE;AAAA,IAAA,KANG,IAAI,GAOb,CACD,EAAA,CACH;AAAA,EAAA,GACF;AAEJ;"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ function muted(value) {
5
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: value });
6
+ }
7
+ function kv(label, value) {
8
+ const absent = value === void 0 || value === null || value === "";
9
+ return {
10
+ key: String(label),
11
+ label,
12
+ value: absent ? muted("-") : value,
13
+ hidden: absent
14
+ };
15
+ }
16
+ exports.kv = kv;
17
+ exports.muted = muted;
18
+ //# sourceMappingURL=SessionInspector.panel-values.cjs.map