@stigmer/react 3.1.2 → 3.1.4

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 (285) hide show
  1. package/composer/SessionComposer.d.ts +37 -5
  2. package/composer/SessionComposer.d.ts.map +1 -1
  3. package/composer/SessionComposer.js +13 -5
  4. package/composer/SessionComposer.js.map +1 -1
  5. package/execution/ArtifactApplyButton.d.ts +25 -0
  6. package/execution/ArtifactApplyButton.d.ts.map +1 -0
  7. package/execution/ArtifactApplyButton.js +21 -0
  8. package/execution/ArtifactApplyButton.js.map +1 -0
  9. package/execution/ArtifactContentBody.d.ts +36 -0
  10. package/execution/ArtifactContentBody.d.ts.map +1 -0
  11. package/execution/ArtifactContentBody.js +62 -0
  12. package/execution/ArtifactContentBody.js.map +1 -0
  13. package/execution/ArtifactDocument.d.ts +48 -0
  14. package/execution/ArtifactDocument.d.ts.map +1 -0
  15. package/execution/ArtifactDocument.js +89 -0
  16. package/execution/ArtifactDocument.js.map +1 -0
  17. package/execution/ArtifactPreviewModal.d.ts +9 -9
  18. package/execution/ArtifactPreviewModal.d.ts.map +1 -1
  19. package/execution/ArtifactPreviewModal.js +18 -145
  20. package/execution/ArtifactPreviewModal.js.map +1 -1
  21. package/execution/ArtifactRow.d.ts +49 -0
  22. package/execution/ArtifactRow.d.ts.map +1 -0
  23. package/execution/ArtifactRow.js +56 -0
  24. package/execution/ArtifactRow.js.map +1 -0
  25. package/execution/ArtifactsWidget.d.ts +6 -9
  26. package/execution/ArtifactsWidget.d.ts.map +1 -1
  27. package/execution/ArtifactsWidget.js +15 -19
  28. package/execution/ArtifactsWidget.js.map +1 -1
  29. package/execution/FileChangeProgressBar.d.ts +47 -0
  30. package/execution/FileChangeProgressBar.d.ts.map +1 -0
  31. package/execution/FileChangeProgressBar.js +49 -0
  32. package/execution/FileChangeProgressBar.js.map +1 -0
  33. package/execution/FileChangesView.d.ts.map +1 -1
  34. package/execution/FileChangesView.js +19 -4
  35. package/execution/FileChangesView.js.map +1 -1
  36. package/execution/FileReviewAtoms.d.ts +27 -0
  37. package/execution/FileReviewAtoms.d.ts.map +1 -0
  38. package/execution/FileReviewAtoms.js +64 -0
  39. package/execution/FileReviewAtoms.js.map +1 -0
  40. package/execution/FileReviewCard.d.ts +2 -2
  41. package/execution/FileReviewCard.d.ts.map +1 -1
  42. package/execution/FileReviewCard.js +32 -62
  43. package/execution/FileReviewCard.js.map +1 -1
  44. package/execution/MessageEntry.d.ts +0 -9
  45. package/execution/MessageEntry.d.ts.map +1 -1
  46. package/execution/MessageEntry.js +1 -11
  47. package/execution/MessageEntry.js.map +1 -1
  48. package/execution/MessageThread.d.ts +3 -4
  49. package/execution/MessageThread.d.ts.map +1 -1
  50. package/execution/MessageThread.js +25 -11
  51. package/execution/MessageThread.js.map +1 -1
  52. package/execution/PlanArtifactCard.d.ts +16 -10
  53. package/execution/PlanArtifactCard.d.ts.map +1 -1
  54. package/execution/PlanArtifactCard.js +31 -7
  55. package/execution/PlanArtifactCard.js.map +1 -1
  56. package/execution/PlanCompletionCard.d.ts +4 -4
  57. package/execution/PlanCompletionCard.d.ts.map +1 -1
  58. package/execution/PlanCompletionCard.js +4 -4
  59. package/execution/PlanCompletionCard.js.map +1 -1
  60. package/execution/PlanStreamingCard.d.ts +7 -2
  61. package/execution/PlanStreamingCard.d.ts.map +1 -1
  62. package/execution/PlanStreamingCard.js +11 -6
  63. package/execution/PlanStreamingCard.js.map +1 -1
  64. package/execution/index.d.ts +12 -2
  65. package/execution/index.d.ts.map +1 -1
  66. package/execution/index.js +6 -1
  67. package/execution/index.js.map +1 -1
  68. package/execution/use-build-from-plan-hotkey.d.ts +1 -1
  69. package/execution/use-build-from-plan-hotkey.js +1 -1
  70. package/execution/useArtifactContent.d.ts +6 -1
  71. package/execution/useArtifactContent.d.ts.map +1 -1
  72. package/execution/useArtifactContent.js +7 -2
  73. package/execution/useArtifactContent.js.map +1 -1
  74. package/execution/useArtifactCopy.d.ts +51 -0
  75. package/execution/useArtifactCopy.d.ts.map +1 -0
  76. package/execution/useArtifactCopy.js +75 -0
  77. package/execution/useArtifactCopy.js.map +1 -0
  78. package/execution/useArtifactDownload.d.ts.map +1 -1
  79. package/execution/useArtifactDownload.js +17 -5
  80. package/execution/useArtifactDownload.js.map +1 -1
  81. package/execution/useArtifactInspection.d.ts +85 -0
  82. package/execution/useArtifactInspection.d.ts.map +1 -0
  83. package/execution/useArtifactInspection.js +143 -0
  84. package/execution/useArtifactInspection.js.map +1 -0
  85. package/execution/useCreateAgentExecution.d.ts +16 -3
  86. package/execution/useCreateAgentExecution.d.ts.map +1 -1
  87. package/execution/useCreateAgentExecution.js +1 -0
  88. package/execution/useCreateAgentExecution.js.map +1 -1
  89. package/index.d.ts +4 -4
  90. package/index.d.ts.map +1 -1
  91. package/index.js +3 -3
  92. package/index.js.map +1 -1
  93. package/internal/MermaidDiagram.d.ts +47 -0
  94. package/internal/MermaidDiagram.d.ts.map +1 -0
  95. package/internal/MermaidDiagram.js +118 -0
  96. package/internal/MermaidDiagram.js.map +1 -0
  97. package/internal/file-tree/FileTreeNode.d.ts.map +1 -1
  98. package/internal/file-tree/FileTreeNode.js +2 -2
  99. package/internal/file-tree/FileTreeNode.js.map +1 -1
  100. package/internal/markdown-components.d.ts.map +1 -1
  101. package/internal/markdown-components.js +34 -0
  102. package/internal/markdown-components.js.map +1 -1
  103. package/internal/mermaid-loader.d.ts +26 -0
  104. package/internal/mermaid-loader.d.ts.map +1 -0
  105. package/internal/mermaid-loader.js +34 -0
  106. package/internal/mermaid-loader.js.map +1 -0
  107. package/internal/mermaid-theme-css.d.ts +41 -0
  108. package/internal/mermaid-theme-css.d.ts.map +1 -0
  109. package/internal/mermaid-theme-css.js +179 -0
  110. package/internal/mermaid-theme-css.js.map +1 -0
  111. package/internal/slug.d.ts +9 -5
  112. package/internal/slug.d.ts.map +1 -1
  113. package/internal/slug.js +10 -6
  114. package/internal/slug.js.map +1 -1
  115. package/library/detect-plan-artifact.d.ts +27 -9
  116. package/library/detect-plan-artifact.d.ts.map +1 -1
  117. package/library/detect-plan-artifact.js +26 -6
  118. package/library/detect-plan-artifact.js.map +1 -1
  119. package/library/index.d.ts +1 -1
  120. package/library/index.d.ts.map +1 -1
  121. package/library/index.js +1 -1
  122. package/library/index.js.map +1 -1
  123. package/package.json +5 -4
  124. package/session/PlanEditor.js +1 -1
  125. package/session/PlanEditor.js.map +1 -1
  126. package/session/SessionViewer.d.ts.map +1 -1
  127. package/session/SessionViewer.js +122 -30
  128. package/session/SessionViewer.js.map +1 -1
  129. package/session/artifact-document.d.ts +13 -0
  130. package/session/artifact-document.d.ts.map +1 -0
  131. package/session/artifact-document.js +22 -0
  132. package/session/artifact-document.js.map +1 -0
  133. package/session/facets/ArtifactsTab.d.ts +30 -4
  134. package/session/facets/ArtifactsTab.d.ts.map +1 -1
  135. package/session/facets/ArtifactsTab.js +32 -10
  136. package/session/facets/ArtifactsTab.js.map +1 -1
  137. package/session/index.d.ts +2 -1
  138. package/session/index.d.ts.map +1 -1
  139. package/session/index.js +4 -1
  140. package/session/index.js.map +1 -1
  141. package/session/plan-document.d.ts +14 -2
  142. package/session/plan-document.d.ts.map +1 -1
  143. package/session/plan-document.js +14 -3
  144. package/session/plan-document.js.map +1 -1
  145. package/session/usePlanDraft.d.ts +1 -1
  146. package/session/useSessionArtifacts.d.ts +17 -0
  147. package/session/useSessionArtifacts.d.ts.map +1 -1
  148. package/session/useSessionArtifacts.js +16 -5
  149. package/session/useSessionArtifacts.js.map +1 -1
  150. package/session/useSessionConversation.d.ts +26 -3
  151. package/session/useSessionConversation.d.ts.map +1 -1
  152. package/session/useSessionConversation.js +51 -6
  153. package/session/useSessionConversation.js.map +1 -1
  154. package/session/useSessionPageFlow.d.ts.map +1 -1
  155. package/session/useSessionPageFlow.js +1 -0
  156. package/session/useSessionPageFlow.js.map +1 -1
  157. package/session/useSessionPanel.d.ts +20 -0
  158. package/session/useSessionPanel.d.ts.map +1 -1
  159. package/session/useSessionPanel.js +13 -0
  160. package/session/useSessionPanel.js.map +1 -1
  161. package/session/useSessionRailViews.d.ts +13 -1
  162. package/session/useSessionRailViews.d.ts.map +1 -1
  163. package/session/useSessionRailViews.js +5 -3
  164. package/session/useSessionRailViews.js.map +1 -1
  165. package/src/composer/SessionComposer.tsx +76 -7
  166. package/src/composer/__tests__/SessionComposer-editing.test.tsx +128 -0
  167. package/src/execution/ArtifactApplyButton.tsx +79 -0
  168. package/src/execution/ArtifactContentBody.tsx +255 -0
  169. package/src/execution/ArtifactDocument.tsx +344 -0
  170. package/src/execution/ArtifactPreviewModal.tsx +49 -415
  171. package/src/execution/ArtifactRow.tsx +165 -0
  172. package/src/execution/ArtifactsWidget.tsx +24 -33
  173. package/src/execution/FileChangeProgressBar.tsx +121 -0
  174. package/src/execution/FileChangesView.tsx +18 -4
  175. package/src/execution/FileReviewAtoms.tsx +89 -0
  176. package/src/execution/FileReviewCard.tsx +57 -90
  177. package/src/execution/MessageEntry.tsx +0 -62
  178. package/src/execution/MessageThread.tsx +29 -15
  179. package/src/execution/PlanArtifactCard.tsx +130 -52
  180. package/src/execution/PlanCompletionCard.tsx +5 -5
  181. package/src/execution/PlanStreamingCard.tsx +15 -11
  182. package/src/execution/__tests__/ArtifactContentBody.test.tsx +131 -0
  183. package/src/execution/__tests__/ArtifactDocument.test.tsx +100 -0
  184. package/src/execution/__tests__/ArtifactPreviewModal.test.tsx +6 -6
  185. package/src/execution/__tests__/ArtifactRow.test.tsx +139 -0
  186. package/src/execution/__tests__/ArtifactsWidget.test.tsx +78 -0
  187. package/src/execution/__tests__/FileChangeProgressBar.test.tsx +125 -0
  188. package/src/execution/__tests__/FileReviewCard.test.tsx +66 -7
  189. package/src/execution/__tests__/MessageThread.test.tsx +1 -1
  190. package/src/execution/__tests__/PlanArtifactCard.test.tsx +52 -18
  191. package/src/execution/__tests__/PlanCompletionCard.test.tsx +2 -2
  192. package/src/execution/__tests__/PlanStreamingCard.test.tsx +11 -4
  193. package/src/execution/__tests__/buildThreadItems-plan-completion.test.ts +104 -8
  194. package/src/execution/__tests__/message-entry.test.tsx +56 -39
  195. package/src/execution/__tests__/useArtifactCopy.test.tsx +90 -0
  196. package/src/execution/__tests__/useArtifactDownload.test.tsx +2 -0
  197. package/src/execution/__tests__/useArtifactInspection.test.tsx +151 -0
  198. package/src/execution/__tests__/useCreateAgentExecution.test.tsx +35 -0
  199. package/src/execution/index.ts +20 -2
  200. package/src/execution/use-build-from-plan-hotkey.ts +1 -1
  201. package/src/execution/useArtifactContent.ts +7 -0
  202. package/src/execution/useArtifactCopy.ts +109 -0
  203. package/src/execution/useArtifactDownload.ts +17 -5
  204. package/src/execution/useArtifactInspection.ts +252 -0
  205. package/src/execution/useCreateAgentExecution.ts +17 -3
  206. package/src/index.ts +17 -2
  207. package/src/internal/MermaidDiagram.tsx +164 -0
  208. package/src/internal/__tests__/a11y/mermaid-theme.a11y.test.tsx +122 -0
  209. package/src/internal/__tests__/markdown-components.test.tsx +93 -1
  210. package/src/internal/__tests__/mermaid-diagram.test.tsx +282 -0
  211. package/src/internal/file-tree/FileTreeNode.tsx +13 -2
  212. package/src/internal/markdown-components.tsx +36 -1
  213. package/src/internal/mermaid-loader.ts +44 -0
  214. package/src/internal/mermaid-theme-css.ts +178 -0
  215. package/src/internal/slug.ts +10 -6
  216. package/src/library/__tests__/detect-plan-artifact.test.ts +21 -0
  217. package/src/library/detect-plan-artifact.ts +32 -10
  218. package/src/library/index.ts +2 -0
  219. package/src/session/PlanEditor.tsx +1 -1
  220. package/src/session/SessionViewer.tsx +227 -51
  221. package/src/session/__tests__/PlanEditor.test.tsx +4 -4
  222. package/src/session/__tests__/PlanStreamingDocument.test.tsx +1 -1
  223. package/src/session/__tests__/SessionViewer-artifactTabs.test.tsx +210 -0
  224. package/src/session/__tests__/SessionViewer-editResubmit.test.tsx +233 -0
  225. package/src/session/__tests__/SessionViewer-fileReviewDock.test.tsx +57 -0
  226. package/src/session/__tests__/useSessionArtifacts.test.ts +57 -0
  227. package/src/session/__tests__/useSessionConversation.test.tsx +216 -1
  228. package/src/session/__tests__/useSessionPanel.test.ts +70 -1
  229. package/src/session/artifact-document.ts +23 -0
  230. package/src/session/facets/ArtifactsTab.tsx +66 -18
  231. package/src/session/facets/__tests__/ArtifactsTab.test.tsx +111 -47
  232. package/src/session/index.ts +5 -1
  233. package/src/session/plan-document.ts +14 -3
  234. package/src/session/usePlanDraft.ts +1 -1
  235. package/src/session/useSessionArtifacts.ts +16 -5
  236. package/src/session/useSessionConversation.ts +80 -10
  237. package/src/session/useSessionPageFlow.ts +1 -0
  238. package/src/session/useSessionPanel.ts +41 -0
  239. package/src/session/useSessionRailViews.tsx +21 -1
  240. package/src/workspace/EditorTabs.tsx +38 -9
  241. package/src/workspace/ExplorerTree.tsx +10 -4
  242. package/src/workspace/FileViewer.tsx +27 -6
  243. package/src/workspace/WorkspaceContentSearch.tsx +44 -20
  244. package/src/workspace/WorkspaceEditor.tsx +19 -16
  245. package/src/workspace/WorkspaceFileSearch.tsx +51 -28
  246. package/src/workspace/WorkspaceSurface.tsx +106 -48
  247. package/src/workspace/__tests__/EditorTabs.test.tsx +4 -2
  248. package/src/workspace/__tests__/ExplorerTree.test.tsx +52 -0
  249. package/src/workspace/__tests__/FileViewer.test.tsx +18 -0
  250. package/src/workspace/__tests__/WorkspaceContentSearch.test.tsx +38 -5
  251. package/src/workspace/__tests__/WorkspaceEditor-initialPanel.test.tsx +19 -0
  252. package/src/workspace/__tests__/WorkspaceFileSearch.test.tsx +27 -6
  253. package/src/workspace/__tests__/WorkspaceSurface.test.tsx +70 -0
  254. package/src/workspace/__tests__/a11y/harness.tsx +140 -0
  255. package/src/workspace/__tests__/a11y/mock-capabilities.ts +138 -0
  256. package/src/workspace/__tests__/a11y/workspace-editor.a11y.test.tsx +65 -0
  257. package/src/workspace/__tests__/a11y/workspace-explorer-search.a11y.test.tsx +112 -0
  258. package/src/workspace/__tests__/a11y/workspace-viewer-tabs.a11y.test.tsx +69 -0
  259. package/styles.css +1 -1
  260. package/workspace/EditorTabs.d.ts +21 -3
  261. package/workspace/EditorTabs.d.ts.map +1 -1
  262. package/workspace/EditorTabs.js +18 -6
  263. package/workspace/EditorTabs.js.map +1 -1
  264. package/workspace/ExplorerTree.js +8 -4
  265. package/workspace/ExplorerTree.js.map +1 -1
  266. package/workspace/FileViewer.d.ts.map +1 -1
  267. package/workspace/FileViewer.js +19 -8
  268. package/workspace/FileViewer.js.map +1 -1
  269. package/workspace/WorkspaceContentSearch.d.ts.map +1 -1
  270. package/workspace/WorkspaceContentSearch.js +23 -2
  271. package/workspace/WorkspaceContentSearch.js.map +1 -1
  272. package/workspace/WorkspaceEditor.d.ts.map +1 -1
  273. package/workspace/WorkspaceEditor.js +8 -10
  274. package/workspace/WorkspaceEditor.js.map +1 -1
  275. package/workspace/WorkspaceFileSearch.d.ts.map +1 -1
  276. package/workspace/WorkspaceFileSearch.js +23 -3
  277. package/workspace/WorkspaceFileSearch.js.map +1 -1
  278. package/workspace/WorkspaceSurface.d.ts.map +1 -1
  279. package/workspace/WorkspaceSurface.js +54 -18
  280. package/workspace/WorkspaceSurface.js.map +1 -1
  281. package/execution/ArtifactCard.d.ts +0 -81
  282. package/execution/ArtifactCard.d.ts.map +0 -1
  283. package/execution/ArtifactCard.js +0 -130
  284. package/execution/ArtifactCard.js.map +0 -1
  285. package/src/execution/ArtifactCard.tsx +0 -320
@@ -1,320 +0,0 @@
1
- "use client";
2
-
3
- import type { ExecutionArtifact } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/artifact_pb";
4
- import { ExecutionArtifactKind } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
5
- import { cn } from "@stigmer/theme";
6
- import { useArtifactContent } from "./useArtifactContent.js";
7
- import { useArtifactDownload } from "./useArtifactDownload.js";
8
- import { isTextArtifact, formatArtifactSize } from "./artifact-utils.js";
9
- import { useDetectStigmerResource } from "../library/useDetectStigmerResource.js";
10
- import { useDetectSkillPackage } from "../library/useDetectSkillPackage.js";
11
-
12
- /**
13
- * Artifacts larger than this threshold skip the content fetch used for
14
- * resource detection. Stigmer resource YAML files are typically under
15
- * 10 KB — 256 KB is generous without risking large payloads for log
16
- * files or binary-adjacent text content.
17
- */
18
- const MAX_DETECTION_SIZE = 256 * 1024;
19
-
20
- /** Props for {@link ArtifactCard}. */
21
- export interface ArtifactCardProps {
22
- /** The execution artifact to render. */
23
- readonly artifact: ExecutionArtifact;
24
- /** ID of the execution that produced this artifact — used for content fetching. */
25
- readonly executionId: string;
26
- /**
27
- * Organization slug — used for skill package detection which fetches
28
- * `SKILL.md` frontmatter via the artifact content RPC.
29
- */
30
- readonly org: string;
31
- /**
32
- * Called when the user clicks "Preview". The consumer is responsible
33
- * for rendering a preview UI (e.g., {@link ArtifactPreviewModal}).
34
- *
35
- * When omitted, the Preview action is not rendered.
36
- */
37
- readonly onPreview?: (artifact: ExecutionArtifact) => void;
38
- /**
39
- * When `true`, another artifact in the list shares the same display
40
- * `name` but has a different `sandbox_path`. The card renders the
41
- * parent directory from `sandbox_path` as a muted subtitle for
42
- * disambiguation.
43
- *
44
- * Set by {@link ArtifactsWidget} via {@link useSessionArtifacts}.
45
- * Defaults to `false`.
46
- */
47
- readonly hasNameCollision?: boolean;
48
- /** Additional CSS classes for the root element. */
49
- readonly className?: string;
50
- }
51
-
52
- /**
53
- * Renders a single execution artifact as a compact summary card with
54
- * automatic Stigmer resource detection and a download link.
55
- *
56
- * The card's role is **signal and navigate**: it tells the user what
57
- * the artifact is (file/directory, size, detected resource type) and
58
- * provides two actions — Preview and Download. The Apply/Push CTA
59
- * lives exclusively in {@link ArtifactPreviewModal} so the user must
60
- * review content before acting (review-before-apply pattern).
61
- *
62
- * Internally orchestrates the detection pipeline:
63
- *
64
- * - **FILE artifacts**: Fetches text content via {@link useArtifactContent},
65
- * then detects Agent/McpServer YAML via {@link useDetectStigmerResource}.
66
- * Only text files under 256 KB are fetched for detection.
67
- *
68
- * - **DIRECTORY artifacts**: Detects skill packages via
69
- * {@link useDetectSkillPackage} (checks for `SKILL.md` in the ZIP
70
- * archive entries).
71
- *
72
- * Detection results are surfaced as a type badge ("Agent detected",
73
- * "Skill · N files"). Non-Stigmer artifacts render with file info
74
- * and a download link only — no error messages or "not detected"
75
- * indicators (detection is silent).
76
- *
77
- * @example
78
- * ```tsx
79
- * const { artifacts } = useExecutionArtifacts(execution);
80
- *
81
- * {artifacts.map((artifact) => (
82
- * <ArtifactCard
83
- * key={artifact.storageKey}
84
- * artifact={artifact}
85
- * executionId={execution.metadata!.id}
86
- * org={activeOrg}
87
- * onPreview={(a) => setPreviewArtifact(a)}
88
- * />
89
- * ))}
90
- * ```
91
- *
92
- * @see {@link ArtifactPreviewModal} — full preview with Apply/Push CTA
93
- * @see {@link ArtifactsWidget} — container that composes cards + modal
94
- * @see {@link useExecutionArtifacts} — extracts artifact metadata from an execution
95
- * @see {@link useArtifactContent} — content-fetching hook (headless alternative)
96
- * @see {@link useDetectStigmerResource} — YAML resource detection (headless)
97
- * @see {@link useDetectSkillPackage} — skill package detection (headless)
98
- */
99
- export function ArtifactCard({
100
- artifact,
101
- executionId,
102
- org,
103
- onPreview,
104
- hasNameCollision = false,
105
- className,
106
- }: ArtifactCardProps) {
107
- // ---------------------------------------------------------------------------
108
- // Detection orchestration
109
- // ---------------------------------------------------------------------------
110
-
111
- const isDirectory = artifact.kind === ExecutionArtifactKind.DIRECTORY;
112
- const canDetectYaml =
113
- !isDirectory &&
114
- isTextArtifact(artifact) &&
115
- Number(artifact.sizeBytes) < MAX_DETECTION_SIZE;
116
-
117
- const { content, isLoading: isContentLoading } = useArtifactContent(
118
- canDetectYaml ? executionId : null,
119
- canDetectYaml ? artifact.storageKey : null,
120
- undefined,
121
- artifact.contentHash || undefined,
122
- );
123
-
124
- const yamlDetection = useDetectStigmerResource(
125
- canDetectYaml ? content : null,
126
- );
127
-
128
- const { detection: skillDetection, isLoading: isSkillLoading } =
129
- useDetectSkillPackage(
130
- isDirectory ? artifact : null,
131
- isDirectory ? executionId : null,
132
- );
133
-
134
- // ---------------------------------------------------------------------------
135
- // Derived detection state
136
- // ---------------------------------------------------------------------------
137
-
138
- const isDetected = yamlDetection.detected || skillDetection.detected;
139
- const isDetecting =
140
- (canDetectYaml && isContentLoading) || (isDirectory && isSkillLoading);
141
-
142
- let detectionLabel: string | null = null;
143
- if (yamlDetection.detected) {
144
- detectionLabel = `${yamlDetection.displayName} detected`;
145
- } else if (skillDetection.detected) {
146
- const count = skillDetection.fileCount;
147
- detectionLabel = `Skill \u00B7 ${count} ${count === 1 ? "file" : "files"}`;
148
- }
149
-
150
- const canPreview = !!onPreview && (isTextArtifact(artifact) || isDirectory);
151
-
152
- const { download, isDownloading } = useArtifactDownload(executionId);
153
-
154
- const parentDir =
155
- hasNameCollision && artifact.sandboxPath
156
- ? parentDirectory(artifact.sandboxPath)
157
- : null;
158
-
159
- // ---------------------------------------------------------------------------
160
- // Render
161
- // ---------------------------------------------------------------------------
162
-
163
- return (
164
- <div
165
- role="article"
166
- aria-label={artifact.name}
167
- className={cn("rounded-md border border-border p-3", className)}
168
- >
169
- {/* Header: icon + name + size */}
170
- <div className="flex items-start gap-2">
171
- <span className="mt-0.5 shrink-0 text-muted-foreground">
172
- {isDirectory ? <FolderIcon /> : <FileIcon />}
173
- </span>
174
- <div className="min-w-0 flex-1">
175
- <div className="truncate text-sm font-medium text-foreground">
176
- {artifact.name}
177
- {isDirectory && "/"}
178
- </div>
179
- {parentDir && (
180
- <div className="truncate text-xs text-muted-foreground">
181
- {parentDir}
182
- </div>
183
- )}
184
- <div className="text-xs tabular-nums text-muted-foreground">
185
- {formatArtifactSize(artifact.sizeBytes)}
186
- </div>
187
- </div>
188
- </div>
189
-
190
- {/* Detection badge */}
191
- {isDetecting && !isDetected && (
192
- <div
193
- className="mt-1.5 h-5 w-28 animate-pulse rounded-full bg-muted"
194
- aria-hidden="true"
195
- />
196
- )}
197
- {detectionLabel && (
198
- <span className="mt-1.5 inline-flex items-center rounded-full bg-primary-subtle px-2 py-0.5 text-xs font-medium text-primary">
199
- {detectionLabel}
200
- </span>
201
- )}
202
-
203
- {/* Secondary actions: Preview + Download */}
204
- <div className="mt-2 flex flex-wrap items-center gap-x-3 gap-y-1">
205
- {canPreview && (
206
- <button
207
- type="button"
208
- onClick={() => onPreview!(artifact)}
209
- className={cn(
210
- "text-xs font-medium text-primary transition-colors hover:text-primary-muted",
211
- FOCUS_RING_CLASSES,
212
- )}
213
- >
214
- Preview
215
- </button>
216
- )}
217
- <button
218
- type="button"
219
- onClick={() => download(artifact.storageKey, artifact.name)}
220
- disabled={isDownloading}
221
- className={cn(
222
- "inline-flex items-center gap-1 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground disabled:opacity-50",
223
- FOCUS_RING_CLASSES,
224
- )}
225
- >
226
- <DownloadIcon />
227
- {isDownloading ? "Preparing…" : isDirectory ? "Download ZIP" : "Download"}
228
- </button>
229
- </div>
230
-
231
- </div>
232
- );
233
- }
234
-
235
- // ---------------------------------------------------------------------------
236
- // Helpers
237
- // ---------------------------------------------------------------------------
238
-
239
- /**
240
- * Extracts a human-readable parent directory label from a sandbox path.
241
- * Given `/workspace/configs/agent.yaml` returns `configs/`.
242
- * Returns `null` when the path has no meaningful parent segment.
243
- */
244
- function parentDirectory(sandboxPath: string): string | null {
245
- const lastSlash = sandboxPath.lastIndexOf("/");
246
- if (lastSlash <= 0) return null;
247
- const parent = sandboxPath.slice(0, lastSlash);
248
- const segment = parent.slice(parent.lastIndexOf("/") + 1);
249
- return segment ? `${segment}/` : null;
250
- }
251
-
252
- // ---------------------------------------------------------------------------
253
- // Shared style constants
254
- // ---------------------------------------------------------------------------
255
-
256
- const FOCUS_RING_CLASSES =
257
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:rounded-sm";
258
-
259
- // ---------------------------------------------------------------------------
260
- // Inline SVG icons
261
- // ---------------------------------------------------------------------------
262
-
263
- function FileIcon() {
264
- return (
265
- <svg
266
- width="14"
267
- height="14"
268
- viewBox="0 0 14 14"
269
- fill="none"
270
- stroke="currentColor"
271
- strokeWidth="1.5"
272
- strokeLinecap="round"
273
- strokeLinejoin="round"
274
- aria-hidden="true"
275
- >
276
- <path d="M8 1H4C3.45 1 3 1.45 3 2V12C3 12.55 3.45 13 4 13H10C10.55 13 11 12.55 11 12V4L8 1Z" />
277
- <path d="M8 1V4H11" />
278
- </svg>
279
- );
280
- }
281
-
282
- function FolderIcon() {
283
- return (
284
- <svg
285
- width="14"
286
- height="14"
287
- viewBox="0 0 14 14"
288
- fill="none"
289
- stroke="currentColor"
290
- strokeWidth="1.5"
291
- strokeLinecap="round"
292
- strokeLinejoin="round"
293
- aria-hidden="true"
294
- >
295
- <path d="M13 11C13 11.55 12.55 12 12 12H2C1.45 12 1 11.55 1 11V3C1 2.45 1.45 2 2 2H5L7 4H12C12.55 4 13 4.45 13 5V11Z" />
296
- </svg>
297
- );
298
- }
299
-
300
- function DownloadIcon() {
301
- return (
302
- <svg
303
- width="10"
304
- height="10"
305
- viewBox="0 0 12 12"
306
- fill="none"
307
- stroke="currentColor"
308
- strokeWidth="1.5"
309
- strokeLinecap="round"
310
- strokeLinejoin="round"
311
- className="shrink-0"
312
- aria-hidden="true"
313
- >
314
- <path d="M6 1.5V8.5" />
315
- <path d="M3 6L6 9L9 6" />
316
- <path d="M2 10.5H10" />
317
- </svg>
318
- );
319
- }
320
-