@shipfox/client-agent 0.2.0

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 (182) hide show
  1. package/.storybook/main.ts +1 -0
  2. package/.storybook/preview.css +4 -0
  3. package/.storybook/preview.tsx +56 -0
  4. package/.turbo/turbo-build.log +2 -0
  5. package/.turbo/turbo-type$colon$emit.log +1 -0
  6. package/.turbo/turbo-type.log +1 -0
  7. package/CHANGELOG.md +93 -0
  8. package/LICENSE +21 -0
  9. package/dist/components/add-custom-provider-card.d.ts +4 -0
  10. package/dist/components/add-custom-provider-card.d.ts.map +1 -0
  11. package/dist/components/add-custom-provider-card.js +41 -0
  12. package/dist/components/add-custom-provider-card.js.map +1 -0
  13. package/dist/components/agent-workflow-example.d.ts +11 -0
  14. package/dist/components/agent-workflow-example.d.ts.map +1 -0
  15. package/dist/components/agent-workflow-example.js +38 -0
  16. package/dist/components/agent-workflow-example.js.map +1 -0
  17. package/dist/components/available-provider-card.d.ts +6 -0
  18. package/dist/components/available-provider-card.d.ts.map +1 -0
  19. package/dist/components/available-provider-card.js +41 -0
  20. package/dist/components/available-provider-card.js.map +1 -0
  21. package/dist/components/available-providers-grid.d.ts +10 -0
  22. package/dist/components/available-providers-grid.d.ts.map +1 -0
  23. package/dist/components/available-providers-grid.js +89 -0
  24. package/dist/components/available-providers-grid.js.map +1 -0
  25. package/dist/components/change-default-model-form.d.ts +9 -0
  26. package/dist/components/change-default-model-form.d.ts.map +1 -0
  27. package/dist/components/change-default-model-form.js +98 -0
  28. package/dist/components/change-default-model-form.js.map +1 -0
  29. package/dist/components/custom-model-provider-api-options.d.ts +7 -0
  30. package/dist/components/custom-model-provider-api-options.d.ts.map +1 -0
  31. package/dist/components/custom-model-provider-api-options.js +23 -0
  32. package/dist/components/custom-model-provider-api-options.js.map +1 -0
  33. package/dist/components/custom-model-provider-form.d.ts +8 -0
  34. package/dist/components/custom-model-provider-form.d.ts.map +1 -0
  35. package/dist/components/custom-model-provider-form.js +667 -0
  36. package/dist/components/custom-model-provider-form.js.map +1 -0
  37. package/dist/components/custom-model-provider-form.stories.d.ts +20 -0
  38. package/dist/components/custom-model-provider-form.stories.d.ts.map +1 -0
  39. package/dist/components/custom-model-provider-form.stories.js +104 -0
  40. package/dist/components/custom-model-provider-form.stories.js.map +1 -0
  41. package/dist/components/custom-model-provider-payload.d.ts +39 -0
  42. package/dist/components/custom-model-provider-payload.d.ts.map +1 -0
  43. package/dist/components/custom-model-provider-payload.js +203 -0
  44. package/dist/components/custom-model-provider-payload.js.map +1 -0
  45. package/dist/components/custom-model-provider-slug.d.ts +3 -0
  46. package/dist/components/custom-model-provider-slug.d.ts.map +1 -0
  47. package/dist/components/custom-model-provider-slug.js +14 -0
  48. package/dist/components/custom-model-provider-slug.js.map +1 -0
  49. package/dist/components/default-model-field.d.ts +16 -0
  50. package/dist/components/default-model-field.d.ts.map +1 -0
  51. package/dist/components/default-model-field.js +60 -0
  52. package/dist/components/default-model-field.js.map +1 -0
  53. package/dist/components/form-errors.d.ts +11 -0
  54. package/dist/components/form-errors.d.ts.map +1 -0
  55. package/dist/components/form-errors.js +101 -0
  56. package/dist/components/form-errors.js.map +1 -0
  57. package/dist/components/harness-availability.d.ts +8 -0
  58. package/dist/components/harness-availability.d.ts.map +1 -0
  59. package/dist/components/harness-availability.js +16 -0
  60. package/dist/components/harness-availability.js.map +1 -0
  61. package/dist/components/harnesses-section.d.ts +4 -0
  62. package/dist/components/harnesses-section.d.ts.map +1 -0
  63. package/dist/components/harnesses-section.js +249 -0
  64. package/dist/components/harnesses-section.js.map +1 -0
  65. package/dist/components/harnesses-section.stories.d.ts +25 -0
  66. package/dist/components/harnesses-section.stories.d.ts.map +1 -0
  67. package/dist/components/harnesses-section.stories.js +138 -0
  68. package/dist/components/harnesses-section.stories.js.map +1 -0
  69. package/dist/components/model-provider-usage-modal.d.ts +11 -0
  70. package/dist/components/model-provider-usage-modal.d.ts.map +1 -0
  71. package/dist/components/model-provider-usage-modal.js +349 -0
  72. package/dist/components/model-provider-usage-modal.js.map +1 -0
  73. package/dist/components/model-provider-usage-modal.stories.d.ts +21 -0
  74. package/dist/components/model-provider-usage-modal.stories.d.ts.map +1 -0
  75. package/dist/components/model-provider-usage-modal.stories.js +115 -0
  76. package/dist/components/model-provider-usage-modal.stories.js.map +1 -0
  77. package/dist/components/model-provider-usage-target.d.ts +14 -0
  78. package/dist/components/model-provider-usage-target.d.ts.map +1 -0
  79. package/dist/components/model-provider-usage-target.js +20 -0
  80. package/dist/components/model-provider-usage-target.js.map +1 -0
  81. package/dist/components/model-providers-section.d.ts +4 -0
  82. package/dist/components/model-providers-section.d.ts.map +1 -0
  83. package/dist/components/model-providers-section.js +668 -0
  84. package/dist/components/model-providers-section.js.map +1 -0
  85. package/dist/components/model-providers-section.stories.d.ts +32 -0
  86. package/dist/components/model-providers-section.stories.d.ts.map +1 -0
  87. package/dist/components/model-providers-section.stories.js +442 -0
  88. package/dist/components/model-providers-section.stories.js.map +1 -0
  89. package/dist/components/provider-search.d.ts +4 -0
  90. package/dist/components/provider-search.d.ts.map +1 -0
  91. package/dist/components/provider-search.js +13 -0
  92. package/dist/components/provider-search.js.map +1 -0
  93. package/dist/components/supported-model-provider-catalog-entry.d.ts +8 -0
  94. package/dist/components/supported-model-provider-catalog-entry.d.ts.map +1 -0
  95. package/dist/components/supported-model-provider-catalog-entry.js +9 -0
  96. package/dist/components/supported-model-provider-catalog-entry.js.map +1 -0
  97. package/dist/components/test-and-save-form.d.ts +10 -0
  98. package/dist/components/test-and-save-form.d.ts.map +1 -0
  99. package/dist/components/test-and-save-form.js +138 -0
  100. package/dist/components/test-and-save-form.js.map +1 -0
  101. package/dist/feature.d.ts +9 -0
  102. package/dist/feature.d.ts.map +1 -0
  103. package/dist/feature.js +13 -0
  104. package/dist/feature.js.map +1 -0
  105. package/dist/hooks/api/model-providers.d.ts +334 -0
  106. package/dist/hooks/api/model-providers.d.ts.map +1 -0
  107. package/dist/hooks/api/model-providers.js +190 -0
  108. package/dist/hooks/api/model-providers.js.map +1 -0
  109. package/dist/index.d.ts +9 -0
  110. package/dist/index.d.ts.map +1 -0
  111. package/dist/index.js +10 -0
  112. package/dist/index.js.map +1 -0
  113. package/dist/pages/model-provider-onboarding-page.d.ts +6 -0
  114. package/dist/pages/model-provider-onboarding-page.d.ts.map +1 -0
  115. package/dist/pages/model-provider-onboarding-page.js +295 -0
  116. package/dist/pages/model-provider-onboarding-page.js.map +1 -0
  117. package/dist/pages/model-provider-onboarding-page.stories.d.ts +27 -0
  118. package/dist/pages/model-provider-onboarding-page.stories.d.ts.map +1 -0
  119. package/dist/pages/model-provider-onboarding-page.stories.js +368 -0
  120. package/dist/pages/model-provider-onboarding-page.stories.js.map +1 -0
  121. package/dist/routes/model-provider.d.ts +5 -0
  122. package/dist/routes/model-provider.d.ts.map +1 -0
  123. package/dist/routes/model-provider.js +28 -0
  124. package/dist/routes/model-provider.js.map +1 -0
  125. package/dist/state/model-provider-onboarding.d.ts +3 -0
  126. package/dist/state/model-provider-onboarding.d.ts.map +1 -0
  127. package/dist/state/model-provider-onboarding.js +28 -0
  128. package/dist/state/model-provider-onboarding.js.map +1 -0
  129. package/dist/tsconfig.test.tsbuildinfo +1 -0
  130. package/package.json +114 -0
  131. package/src/components/add-custom-provider-card.tsx +32 -0
  132. package/src/components/agent-workflow-example.test.ts +74 -0
  133. package/src/components/agent-workflow-example.ts +55 -0
  134. package/src/components/available-provider-card.tsx +39 -0
  135. package/src/components/available-providers-grid.test.tsx +55 -0
  136. package/src/components/available-providers-grid.tsx +106 -0
  137. package/src/components/change-default-model-form.tsx +104 -0
  138. package/src/components/custom-model-provider-api-options.test.ts +18 -0
  139. package/src/components/custom-model-provider-api-options.ts +12 -0
  140. package/src/components/custom-model-provider-form.stories.tsx +91 -0
  141. package/src/components/custom-model-provider-form.tsx +710 -0
  142. package/src/components/custom-model-provider-payload.test.ts +170 -0
  143. package/src/components/custom-model-provider-payload.ts +264 -0
  144. package/src/components/custom-model-provider-slug.test.ts +40 -0
  145. package/src/components/custom-model-provider-slug.ts +23 -0
  146. package/src/components/default-model-field.tsx +85 -0
  147. package/src/components/form-errors.test.ts +159 -0
  148. package/src/components/form-errors.ts +102 -0
  149. package/src/components/harness-availability.test.ts +45 -0
  150. package/src/components/harness-availability.ts +35 -0
  151. package/src/components/harnesses-section.stories.tsx +129 -0
  152. package/src/components/harnesses-section.test.tsx +188 -0
  153. package/src/components/harnesses-section.tsx +245 -0
  154. package/src/components/model-provider-usage-modal.stories.tsx +106 -0
  155. package/src/components/model-provider-usage-modal.test.tsx +210 -0
  156. package/src/components/model-provider-usage-modal.tsx +326 -0
  157. package/src/components/model-provider-usage-target.ts +36 -0
  158. package/src/components/model-providers-section.stories.tsx +345 -0
  159. package/src/components/model-providers-section.test.tsx +831 -0
  160. package/src/components/model-providers-section.tsx +645 -0
  161. package/src/components/provider-search.test.ts +45 -0
  162. package/src/components/provider-search.ts +18 -0
  163. package/src/components/supported-model-provider-catalog-entry.ts +19 -0
  164. package/src/components/test-and-save-form.tsx +166 -0
  165. package/src/feature.ts +12 -0
  166. package/src/hooks/api/model-providers.test.ts +167 -0
  167. package/src/hooks/api/model-providers.ts +281 -0
  168. package/src/index.ts +8 -0
  169. package/src/pages/model-provider-onboarding-page.stories.tsx +284 -0
  170. package/src/pages/model-provider-onboarding-page.test.tsx +368 -0
  171. package/src/pages/model-provider-onboarding-page.tsx +290 -0
  172. package/src/routes/model-provider.tsx +20 -0
  173. package/src/state/model-provider-onboarding.test.ts +55 -0
  174. package/src/state/model-provider-onboarding.ts +34 -0
  175. package/test/fixtures/model-providers.ts +111 -0
  176. package/test/setup.ts +3 -0
  177. package/tsconfig.build.json +9 -0
  178. package/tsconfig.build.tsbuildinfo +1 -0
  179. package/tsconfig.json +3 -0
  180. package/tsconfig.test.json +8 -0
  181. package/vercel.json +8 -0
  182. package/vitest.config.ts +72 -0
@@ -0,0 +1 @@
1
+ export {default} from '../../.storybook/main.ts';
@@ -0,0 +1,4 @@
1
+ @import "@shipfox/react-ui/index.css";
2
+
3
+ @source "../src";
4
+ @source "../../../shared/react/ui/src";
@@ -0,0 +1,56 @@
1
+ import './preview.css';
2
+ import {ThemeProvider} from '@shipfox/react-ui/theme';
3
+ import type {Decorator, Preview} from '@storybook/react';
4
+
5
+ if (typeof document !== 'undefined' && document.fonts) {
6
+ void Promise.all([
7
+ document.fonts.load("16px 'Inter'"),
8
+ document.fonts.load("italic 16px 'Inter'"),
9
+ document.fonts.load("16px 'Commit Mono'"),
10
+ document.fonts.load("bold 16px 'Commit Mono'"),
11
+ ]);
12
+ }
13
+
14
+ const withTheme: Decorator = (Story, context) => {
15
+ const theme = context.globals.theme;
16
+ return (
17
+ <ThemeProvider key={theme} defaultTheme={theme} storageKey={`shipfox-theme-${theme}`}>
18
+ <Story />
19
+ </ThemeProvider>
20
+ );
21
+ };
22
+
23
+ const preview: Preview = {
24
+ decorators: [withTheme],
25
+ parameters: {
26
+ argos: {
27
+ // Dual-theme coverage lives in @shipfox/react-ui (the theming source of truth);
28
+ // feature packages capture only the primary dark theme to limit Argos spend.
29
+ modes: {
30
+ dark: {theme: 'dark'},
31
+ },
32
+ fitToContent: false,
33
+ },
34
+ options: {
35
+ storySort: {method: 'alphabetical'},
36
+ },
37
+ },
38
+ globalTypes: {
39
+ theme: {
40
+ name: 'Theme',
41
+ description: 'Global theme for components',
42
+ defaultValue: 'dark',
43
+ toolbar: {
44
+ icon: 'sun',
45
+ items: [
46
+ {value: 'light', icon: 'sun', title: 'Light'},
47
+ {value: 'dark', icon: 'moon', title: 'Dark'},
48
+ {value: 'system', icon: 'info', title: 'System'},
49
+ ],
50
+ showName: true,
51
+ },
52
+ },
53
+ },
54
+ };
55
+
56
+ export default preview;
@@ -0,0 +1,2 @@
1
+ $ shipfox-swc
2
+ Successfully compiled: 30 files with swc (49.55ms)
@@ -0,0 +1 @@
1
+ $ shipfox-tsc-emit
@@ -0,0 +1 @@
1
+ $ shipfox-tsc-check
package/CHANGELOG.md ADDED
@@ -0,0 +1,93 @@
1
+ # @shipfox/client-agent
2
+
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3d064b8: Publishes the client runtime closure with shell, feature, route, Vite, and testing contracts.
8
+ - 6bc2e45: Adds the composable upstream client shell, feature catalog, and route manifests for every client feature.
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies [3d064b8]
13
+ - Updated dependencies [6bc2e45]
14
+ - @shipfox/client-api@0.2.0
15
+ - @shipfox/client-shell@0.2.0
16
+ - @shipfox/client-ui@0.2.0
17
+
18
+ ## 0.1.2
19
+
20
+ ### Patch Changes
21
+
22
+ - Updated dependencies [c18d624]
23
+ - @shipfox/react-ui@0.3.1
24
+ - @shipfox/client-ui@0.1.2
25
+ - @shipfox/api-agent-dto@3.0.0
26
+
27
+ ## 0.1.1
28
+
29
+ ### Patch Changes
30
+
31
+ - Updated dependencies [1b0d344]
32
+ - @shipfox/api-agent-dto@2.0.0
33
+ - @shipfox/client-ui@0.1.1
34
+ - @shipfox/client-api@0.0.1
35
+ - @shipfox/react-ui@0.3.0
36
+
37
+ ## 0.1.0
38
+
39
+ ### Minor Changes
40
+
41
+ - 067a260: Adds workspace model provider settings for configuring, testing, defaulting, and deleting provider credentials.
42
+ - 1b9d909: Add a workflow example usage modal for configured model providers, with model selection, ready-to-copy workflow YAML, model id browsing, and automatic opening after first configuration.
43
+
44
+ ### Patch Changes
45
+
46
+ - Updated dependencies [067a260]
47
+ - Updated dependencies [43d7996]
48
+ - Updated dependencies [14e0bea]
49
+ - Updated dependencies [9018f0b]
50
+ - Updated dependencies [7fdfd72]
51
+ - Updated dependencies [2a3193f]
52
+ - Updated dependencies [de54da2]
53
+ - Updated dependencies [7ca4c65]
54
+ - Updated dependencies [f104ff2]
55
+ - Updated dependencies [7341569]
56
+ - Updated dependencies [5bcdbf4]
57
+ - Updated dependencies [e4c6abf]
58
+ - Updated dependencies [aca162b]
59
+ - Updated dependencies [5d0676a]
60
+ - Updated dependencies [a35c2dc]
61
+ - Updated dependencies [58f7aef]
62
+ - Updated dependencies [5264a22]
63
+ - Updated dependencies [9674879]
64
+ - Updated dependencies [225c9a5]
65
+ - Updated dependencies [24f131b]
66
+ - Updated dependencies [bb2a7bc]
67
+ - Updated dependencies [5eb06d0]
68
+ - Updated dependencies [4e13e5f]
69
+ - Updated dependencies [e92150d]
70
+ - Updated dependencies [8037501]
71
+ - Updated dependencies [0fb6018]
72
+ - Updated dependencies [c27a1ed]
73
+ - Updated dependencies [b8e49ff]
74
+ - Updated dependencies [8037501]
75
+ - Updated dependencies [6c0da64]
76
+ - Updated dependencies [07f8ff8]
77
+ - Updated dependencies [e457582]
78
+ - Updated dependencies [8b5c905]
79
+ - Updated dependencies [f849131]
80
+ - Updated dependencies [94bdcc5]
81
+ - Updated dependencies [a34c8ea]
82
+ - Updated dependencies [27770eb]
83
+ - Updated dependencies [8ac4bf4]
84
+ - Updated dependencies [3a0be6b]
85
+ - Updated dependencies [282e66a]
86
+ - Updated dependencies [d42baf4]
87
+ - Updated dependencies [8037501]
88
+ - Updated dependencies [54bb8a3]
89
+ - Updated dependencies [f711e18]
90
+ - @shipfox/api-agent-dto@0.1.0
91
+ - @shipfox/react-ui@0.3.0
92
+ - @shipfox/client-api@0.0.1
93
+ - @shipfox/client-ui@0.1.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shipfox
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ export declare function AddCustomProviderCard({ onConfigure }: {
2
+ onConfigure: () => void;
3
+ }): import("react").JSX.Element;
4
+ //# sourceMappingURL=add-custom-provider-card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-custom-provider-card.d.ts","sourceRoot":"","sources":["../../src/components/add-custom-provider-card.tsx"],"names":[],"mappings":"AAOA,wBAAgB,qBAAqB,CAAC,EAAC,WAAW,EAAC,EAAE;IAAC,WAAW,EAAE,MAAM,IAAI,CAAA;CAAC,+BAwB7E"}
@@ -0,0 +1,41 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Icon } from '@shipfox/react-ui/icon';
3
+ import { Text } from '@shipfox/react-ui/typography';
4
+ import { cn } from '@shipfox/react-ui/utils';
5
+ const SURFACE_CLASS = 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';
6
+ export function AddCustomProviderCard({ onConfigure }) {
7
+ return /*#__PURE__*/ _jsx("li", {
8
+ children: /*#__PURE__*/ _jsx("button", {
9
+ type: "button",
10
+ className: cn('group block h-full w-full cursor-pointer p-16 text-left outline-none transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus', SURFACE_CLASS),
11
+ "aria-label": "Configure custom provider",
12
+ onClick: onConfigure,
13
+ children: /*#__PURE__*/ _jsxs("div", {
14
+ className: "flex min-w-0 items-center justify-between gap-12",
15
+ children: [
16
+ /*#__PURE__*/ _jsx(Text, {
17
+ size: "md",
18
+ bold: true,
19
+ className: "min-w-0 truncate",
20
+ children: "Custom"
21
+ }),
22
+ /*#__PURE__*/ _jsxs("div", {
23
+ className: "flex shrink-0 items-center gap-4 text-foreground-neutral-muted transition-colors group-hover:text-foreground-highlight-interactive",
24
+ children: [
25
+ /*#__PURE__*/ _jsx(Text, {
26
+ size: "sm",
27
+ children: "Configure"
28
+ }),
29
+ /*#__PURE__*/ _jsx(Icon, {
30
+ name: "chevronRight",
31
+ className: "size-16"
32
+ })
33
+ ]
34
+ })
35
+ ]
36
+ })
37
+ })
38
+ });
39
+ }
40
+
41
+ //# sourceMappingURL=add-custom-provider-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/add-custom-provider-card.tsx"],"sourcesContent":["import {Icon} from '@shipfox/react-ui/icon';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\n\nconst SURFACE_CLASS =\n 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';\n\nexport function AddCustomProviderCard({onConfigure}: {onConfigure: () => void}) {\n return (\n <li>\n <button\n type=\"button\"\n className={cn(\n 'group block h-full w-full cursor-pointer p-16 text-left outline-none transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus',\n SURFACE_CLASS,\n )}\n aria-label=\"Configure custom provider\"\n onClick={onConfigure}\n >\n <div className=\"flex min-w-0 items-center justify-between gap-12\">\n <Text size=\"md\" bold className=\"min-w-0 truncate\">\n Custom\n </Text>\n <div className=\"flex shrink-0 items-center gap-4 text-foreground-neutral-muted transition-colors group-hover:text-foreground-highlight-interactive\">\n <Text size=\"sm\">Configure</Text>\n <Icon name=\"chevronRight\" className=\"size-16\" />\n </div>\n </div>\n </button>\n </li>\n );\n}\n"],"names":["Icon","Text","cn","SURFACE_CLASS","AddCustomProviderCard","onConfigure","li","button","type","className","aria-label","onClick","div","size","bold","name"],"mappings":";AAAA,SAAQA,IAAI,QAAO,yBAAyB;AAC5C,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,EAAE,QAAO,0BAA0B;AAE3C,MAAMC,gBACJ;AAEF,OAAO,SAASC,sBAAsB,EAACC,WAAW,EAA4B;IAC5E,qBACE,KAACC;kBACC,cAAA,KAACC;YACCC,MAAK;YACLC,WAAWP,GACT,yKACAC;YAEFO,cAAW;YACXC,SAASN;sBAET,cAAA,MAACO;gBAAIH,WAAU;;kCACb,KAACR;wBAAKY,MAAK;wBAAKC,IAAI;wBAACL,WAAU;kCAAmB;;kCAGlD,MAACG;wBAAIH,WAAU;;0CACb,KAACR;gCAAKY,MAAK;0CAAK;;0CAChB,KAACb;gCAAKe,MAAK;gCAAeN,WAAU;;;;;;;;AAMhD"}
@@ -0,0 +1,11 @@
1
+ import type { CodeBlockHighlightedLineRange } from '@shipfox/react-ui/code-block';
2
+ export interface AgentWorkflowExample {
3
+ code: string;
4
+ highlightedLineRange: CodeBlockHighlightedLineRange;
5
+ }
6
+ export declare function buildAgentWorkflowExample({ harness, providerId, model, }: {
7
+ harness: string;
8
+ providerId: string;
9
+ model: string;
10
+ }): AgentWorkflowExample;
11
+ //# sourceMappingURL=agent-workflow-example.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-workflow-example.d.ts","sourceRoot":"","sources":["../../src/components/agent-workflow-example.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,6BAA6B,EAAC,MAAM,8BAA8B,CAAC;AAKhF,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB,EAAE,6BAA6B,CAAC;CACrD;AAED,wBAAgB,yBAAyB,CAAC,EACxC,OAAO,EACP,UAAU,EACV,KAAK,GACN,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,oBAAoB,CA2BvB"}
@@ -0,0 +1,38 @@
1
+ const YAML_SAFE_PLAIN_SCALAR_RE = /^[A-Za-z][A-Za-z0-9._/-]*$/;
2
+ const YAML_AMBIGUOUS_PLAIN_SCALAR_RE = /^(?:false|n|no|null|off|on|true|y|yes)$/i;
3
+ export function buildAgentWorkflowExample({ harness, providerId, model }) {
4
+ const lines = [
5
+ 'name: Agent',
6
+ 'triggers:',
7
+ ' on_demand:',
8
+ ' source: manual',
9
+ ' event: fire',
10
+ 'jobs:',
11
+ ' agent:',
12
+ ' runner: ubuntu-latest',
13
+ ' steps:',
14
+ ' - name: implement',
15
+ ` harness: ${formatYamlPlainOrSingleQuotedScalar(harness)}`,
16
+ ` provider: ${formatYamlPlainOrSingleQuotedScalar(providerId)}`,
17
+ ` model: ${formatYamlPlainOrSingleQuotedScalar(model)}`,
18
+ ' prompt: Describe the change you want the agent to make.'
19
+ ];
20
+ const harnessLineIndex = lines.findIndex((line)=>line.trimStart().startsWith('harness:'));
21
+ const modelLineIndex = lines.findIndex((line)=>line.trimStart().startsWith('model:'));
22
+ return {
23
+ code: lines.join('\n'),
24
+ highlightedLineRange: {
25
+ startLine: harnessLineIndex + 1,
26
+ endLine: modelLineIndex + 1
27
+ }
28
+ };
29
+ }
30
+ function formatYamlPlainOrSingleQuotedScalar(value) {
31
+ if (!requiresYamlSingleQuotes(value)) return value;
32
+ return `'${value.replaceAll("'", "''")}'`;
33
+ }
34
+ function requiresYamlSingleQuotes(value) {
35
+ return !YAML_SAFE_PLAIN_SCALAR_RE.test(value) || YAML_AMBIGUOUS_PLAIN_SCALAR_RE.test(value);
36
+ }
37
+
38
+ //# sourceMappingURL=agent-workflow-example.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/agent-workflow-example.ts"],"sourcesContent":["import type {CodeBlockHighlightedLineRange} from '@shipfox/react-ui/code-block';\n\nconst YAML_SAFE_PLAIN_SCALAR_RE = /^[A-Za-z][A-Za-z0-9._/-]*$/;\nconst YAML_AMBIGUOUS_PLAIN_SCALAR_RE = /^(?:false|n|no|null|off|on|true|y|yes)$/i;\n\nexport interface AgentWorkflowExample {\n code: string;\n highlightedLineRange: CodeBlockHighlightedLineRange;\n}\n\nexport function buildAgentWorkflowExample({\n harness,\n providerId,\n model,\n}: {\n harness: string;\n providerId: string;\n model: string;\n}): AgentWorkflowExample {\n const lines = [\n 'name: Agent',\n 'triggers:',\n ' on_demand:',\n ' source: manual',\n ' event: fire',\n 'jobs:',\n ' agent:',\n ' runner: ubuntu-latest',\n ' steps:',\n ' - name: implement',\n ` harness: ${formatYamlPlainOrSingleQuotedScalar(harness)}`,\n ` provider: ${formatYamlPlainOrSingleQuotedScalar(providerId)}`,\n ` model: ${formatYamlPlainOrSingleQuotedScalar(model)}`,\n ' prompt: Describe the change you want the agent to make.',\n ];\n const harnessLineIndex = lines.findIndex((line) => line.trimStart().startsWith('harness:'));\n const modelLineIndex = lines.findIndex((line) => line.trimStart().startsWith('model:'));\n\n return {\n code: lines.join('\\n'),\n highlightedLineRange: {\n startLine: harnessLineIndex + 1,\n endLine: modelLineIndex + 1,\n },\n };\n}\n\nfunction formatYamlPlainOrSingleQuotedScalar(value: string): string {\n if (!requiresYamlSingleQuotes(value)) return value;\n return `'${value.replaceAll(\"'\", \"''\")}'`;\n}\n\nfunction requiresYamlSingleQuotes(value: string): boolean {\n return !YAML_SAFE_PLAIN_SCALAR_RE.test(value) || YAML_AMBIGUOUS_PLAIN_SCALAR_RE.test(value);\n}\n"],"names":["YAML_SAFE_PLAIN_SCALAR_RE","YAML_AMBIGUOUS_PLAIN_SCALAR_RE","buildAgentWorkflowExample","harness","providerId","model","lines","formatYamlPlainOrSingleQuotedScalar","harnessLineIndex","findIndex","line","trimStart","startsWith","modelLineIndex","code","join","highlightedLineRange","startLine","endLine","value","requiresYamlSingleQuotes","replaceAll","test"],"mappings":"AAEA,MAAMA,4BAA4B;AAClC,MAAMC,iCAAiC;AAOvC,OAAO,SAASC,0BAA0B,EACxCC,OAAO,EACPC,UAAU,EACVC,KAAK,EAKN;IACC,MAAMC,QAAQ;QACZ;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,CAAC,iBAAiB,EAAEC,oCAAoCJ,UAAU;QAClE,CAAC,kBAAkB,EAAEI,oCAAoCH,aAAa;QACtE,CAAC,eAAe,EAAEG,oCAAoCF,QAAQ;QAC9D;KACD;IACD,MAAMG,mBAAmBF,MAAMG,SAAS,CAAC,CAACC,OAASA,KAAKC,SAAS,GAAGC,UAAU,CAAC;IAC/E,MAAMC,iBAAiBP,MAAMG,SAAS,CAAC,CAACC,OAASA,KAAKC,SAAS,GAAGC,UAAU,CAAC;IAE7E,OAAO;QACLE,MAAMR,MAAMS,IAAI,CAAC;QACjBC,sBAAsB;YACpBC,WAAWT,mBAAmB;YAC9BU,SAASL,iBAAiB;QAC5B;IACF;AACF;AAEA,SAASN,oCAAoCY,KAAa;IACxD,IAAI,CAACC,yBAAyBD,QAAQ,OAAOA;IAC7C,OAAO,CAAC,CAAC,EAAEA,MAAME,UAAU,CAAC,KAAK,MAAM,CAAC,CAAC;AAC3C;AAEA,SAASD,yBAAyBD,KAAa;IAC7C,OAAO,CAACnB,0BAA0BsB,IAAI,CAACH,UAAUlB,+BAA+BqB,IAAI,CAACH;AACvF"}
@@ -0,0 +1,6 @@
1
+ import type { ModelProviderCatalogEntryDto } from '@shipfox/api-agent-dto';
2
+ export declare function AvailableProviderCard({ entry, onConfigure, }: {
3
+ entry: ModelProviderCatalogEntryDto;
4
+ onConfigure: () => void;
5
+ }): import("react").JSX.Element;
6
+ //# sourceMappingURL=available-provider-card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"available-provider-card.d.ts","sourceRoot":"","sources":["../../src/components/available-provider-card.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,4BAA4B,EAAC,MAAM,wBAAwB,CAAC;AAQzE,wBAAgB,qBAAqB,CAAC,EACpC,KAAK,EACL,WAAW,GACZ,EAAE;IACD,KAAK,EAAE,4BAA4B,CAAC;IACpC,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,+BAwBA"}
@@ -0,0 +1,41 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Icon } from '@shipfox/react-ui/icon';
3
+ import { Text } from '@shipfox/react-ui/typography';
4
+ import { cn } from '@shipfox/react-ui/utils';
5
+ const SURFACE_CLASS = 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';
6
+ export function AvailableProviderCard({ entry, onConfigure }) {
7
+ return /*#__PURE__*/ _jsx("li", {
8
+ children: /*#__PURE__*/ _jsx("button", {
9
+ type: "button",
10
+ className: cn('group block w-full cursor-pointer p-16 text-left outline-none transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus', SURFACE_CLASS),
11
+ "aria-label": `Configure ${entry.label}`,
12
+ onClick: onConfigure,
13
+ children: /*#__PURE__*/ _jsxs("div", {
14
+ className: "flex min-w-0 items-center justify-between gap-12",
15
+ children: [
16
+ /*#__PURE__*/ _jsx(Text, {
17
+ size: "md",
18
+ bold: true,
19
+ className: "min-w-0 truncate",
20
+ children: entry.label
21
+ }),
22
+ /*#__PURE__*/ _jsxs("div", {
23
+ className: "flex shrink-0 items-center gap-4 text-foreground-neutral-muted transition-colors group-hover:text-foreground-highlight-interactive",
24
+ children: [
25
+ /*#__PURE__*/ _jsx(Text, {
26
+ size: "sm",
27
+ children: "Configure"
28
+ }),
29
+ /*#__PURE__*/ _jsx(Icon, {
30
+ name: "chevronRight",
31
+ className: "size-16"
32
+ })
33
+ ]
34
+ })
35
+ ]
36
+ })
37
+ })
38
+ });
39
+ }
40
+
41
+ //# sourceMappingURL=available-provider-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/available-provider-card.tsx"],"sourcesContent":["import type {ModelProviderCatalogEntryDto} from '@shipfox/api-agent-dto';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\n\nconst SURFACE_CLASS =\n 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';\n\nexport function AvailableProviderCard({\n entry,\n onConfigure,\n}: {\n entry: ModelProviderCatalogEntryDto;\n onConfigure: () => void;\n}) {\n return (\n <li>\n <button\n type=\"button\"\n className={cn(\n 'group block w-full cursor-pointer p-16 text-left outline-none transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus',\n SURFACE_CLASS,\n )}\n aria-label={`Configure ${entry.label}`}\n onClick={onConfigure}\n >\n <div className=\"flex min-w-0 items-center justify-between gap-12\">\n <Text size=\"md\" bold className=\"min-w-0 truncate\">\n {entry.label}\n </Text>\n <div className=\"flex shrink-0 items-center gap-4 text-foreground-neutral-muted transition-colors group-hover:text-foreground-highlight-interactive\">\n <Text size=\"sm\">Configure</Text>\n <Icon name=\"chevronRight\" className=\"size-16\" />\n </div>\n </div>\n </button>\n </li>\n );\n}\n"],"names":["Icon","Text","cn","SURFACE_CLASS","AvailableProviderCard","entry","onConfigure","li","button","type","className","aria-label","label","onClick","div","size","bold","name"],"mappings":";AACA,SAAQA,IAAI,QAAO,yBAAyB;AAC5C,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,EAAE,QAAO,0BAA0B;AAE3C,MAAMC,gBACJ;AAEF,OAAO,SAASC,sBAAsB,EACpCC,KAAK,EACLC,WAAW,EAIZ;IACC,qBACE,KAACC;kBACC,cAAA,KAACC;YACCC,MAAK;YACLC,WAAWR,GACT,kKACAC;YAEFQ,cAAY,CAAC,UAAU,EAAEN,MAAMO,KAAK,EAAE;YACtCC,SAASP;sBAET,cAAA,MAACQ;gBAAIJ,WAAU;;kCACb,KAACT;wBAAKc,MAAK;wBAAKC,IAAI;wBAACN,WAAU;kCAC5BL,MAAMO,KAAK;;kCAEd,MAACE;wBAAIJ,WAAU;;0CACb,KAACT;gCAAKc,MAAK;0CAAK;;0CAChB,KAACf;gCAAKiB,MAAK;gCAAeP,WAAU;;;;;;;;AAMhD"}
@@ -0,0 +1,10 @@
1
+ import type { ModelProviderCatalogEntryDto } from '@shipfox/api-agent-dto';
2
+ import type { ReactNode } from 'react';
3
+ export declare const PROVIDER_GRID_CLASS = "grid grid-cols-2 gap-12 max-[760px]:grid-cols-1";
4
+ export declare function AvailableProvidersGrid<TEntry extends ModelProviderCatalogEntryDto>({ entries, onSelect, trailingCard, trailingCardMatchesSearch, }: {
5
+ entries: TEntry[];
6
+ onSelect: (entry: TEntry) => void;
7
+ trailingCard?: ReactNode | undefined;
8
+ trailingCardMatchesSearch?: ((query: string) => boolean) | undefined;
9
+ }): import("react").JSX.Element;
10
+ //# sourceMappingURL=available-providers-grid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"available-providers-grid.d.ts","sourceRoot":"","sources":["../../src/components/available-providers-grid.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,4BAA4B,EAAC,MAAM,wBAAwB,CAAC;AAKzE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAKrC,eAAO,MAAM,mBAAmB,oDAAoD,CAAC;AAKrF,wBAAgB,sBAAsB,CAAC,MAAM,SAAS,4BAA4B,EAAE,EAClF,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,yBAAsC,GACvC,EAAE;IACD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,YAAY,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IACrC,yBAAyB,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,SAAS,CAAC;CACtE,+BAuDA"}
@@ -0,0 +1,89 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from '@shipfox/react-ui/button';
3
+ import { EmptyState } from '@shipfox/react-ui/empty-state';
4
+ import { Icon } from '@shipfox/react-ui/icon';
5
+ import { Input } from '@shipfox/react-ui/input';
6
+ import { useMemo, useRef, useState } from 'react';
7
+ import { AvailableProviderCard } from './available-provider-card.js';
8
+ import { providerMatchesSearch } from './provider-search.js';
9
+ export const PROVIDER_GRID_CLASS = 'grid grid-cols-2 gap-12 max-[760px]:grid-cols-1';
10
+ const SEARCH_VISIBILITY_THRESHOLD = 8;
11
+ const MAX_ECHOED_QUERY_LENGTH = 40;
12
+ export function AvailableProvidersGrid({ entries, onSelect, trailingCard, trailingCardMatchesSearch = ()=>true }) {
13
+ const [search, setSearch] = useState('');
14
+ const inputRef = useRef(null);
15
+ const trimmedSearch = search.trim();
16
+ const filteredEntries = useMemo(()=>entries.filter((entry)=>providerMatchesSearch(entry, search)), [
17
+ entries,
18
+ search
19
+ ]);
20
+ const trailingCardVisible = trailingCard !== undefined && trailingCardMatchesSearch(search);
21
+ const visibleCount = filteredEntries.length + (trailingCardVisible ? 1 : 0);
22
+ const showSearch = entries.length > SEARCH_VISIBILITY_THRESHOLD || trimmedSearch !== '';
23
+ const providerListLabel = trimmedSearch !== '' ? 'Available providers matching search' : 'Available providers';
24
+ const resultCountText = trimmedSearch === '' ? '' : providerResultCountText(filteredEntries.length, trimmedSearch);
25
+ function clearSearch() {
26
+ setSearch('');
27
+ inputRef.current?.focus();
28
+ }
29
+ return /*#__PURE__*/ _jsxs("div", {
30
+ className: "flex flex-col gap-12",
31
+ children: [
32
+ showSearch ? /*#__PURE__*/ _jsx(Input, {
33
+ ref: inputRef,
34
+ type: "search",
35
+ "aria-label": "Search providers",
36
+ placeholder: "Search providers...",
37
+ value: search,
38
+ iconLeft: /*#__PURE__*/ _jsx(Icon, {
39
+ name: "searchLine",
40
+ className: "size-16 text-foreground-neutral-muted"
41
+ }),
42
+ onChange: (event)=>setSearch(event.target.value)
43
+ }) : null,
44
+ visibleCount > 0 ? /*#__PURE__*/ _jsxs("ul", {
45
+ className: PROVIDER_GRID_CLASS,
46
+ "aria-label": providerListLabel,
47
+ children: [
48
+ filteredEntries.map((entry)=>/*#__PURE__*/ _jsx(AvailableProviderCard, {
49
+ entry: entry,
50
+ onConfigure: ()=>onSelect(entry)
51
+ }, entry.id)),
52
+ trailingCardVisible ? trailingCard : null
53
+ ]
54
+ }) : /*#__PURE__*/ _jsx(NoProviderSearchResults, {
55
+ search: trimmedSearch,
56
+ onClear: clearSearch
57
+ }),
58
+ /*#__PURE__*/ _jsx("p", {
59
+ role: "status",
60
+ "aria-live": "polite",
61
+ className: "sr-only",
62
+ children: resultCountText
63
+ })
64
+ ]
65
+ });
66
+ }
67
+ function NoProviderSearchResults({ search, onClear }) {
68
+ return /*#__PURE__*/ _jsx(EmptyState, {
69
+ icon: "searchLine",
70
+ title: `No providers match "${truncateQuery(search)}"`,
71
+ description: "Try a different search, or clear it to see all providers.",
72
+ action: /*#__PURE__*/ _jsx(Button, {
73
+ size: "sm",
74
+ variant: "secondary",
75
+ onClick: onClear,
76
+ children: "Clear search"
77
+ })
78
+ });
79
+ }
80
+ function truncateQuery(query) {
81
+ if (query.length <= MAX_ECHOED_QUERY_LENGTH) return query;
82
+ return `${query.slice(0, MAX_ECHOED_QUERY_LENGTH - 3)}...`;
83
+ }
84
+ function providerResultCountText(count, query) {
85
+ if (count === 1) return `1 provider matches "${query}"`;
86
+ return `${count} providers match "${query}"`;
87
+ }
88
+
89
+ //# sourceMappingURL=available-providers-grid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/available-providers-grid.tsx"],"sourcesContent":["import type {ModelProviderCatalogEntryDto} from '@shipfox/api-agent-dto';\nimport {Button} from '@shipfox/react-ui/button';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {Input} from '@shipfox/react-ui/input';\nimport type {ReactNode} from 'react';\nimport {useMemo, useRef, useState} from 'react';\nimport {AvailableProviderCard} from './available-provider-card.js';\nimport {providerMatchesSearch} from './provider-search.js';\n\nexport const PROVIDER_GRID_CLASS = 'grid grid-cols-2 gap-12 max-[760px]:grid-cols-1';\n\nconst SEARCH_VISIBILITY_THRESHOLD = 8;\nconst MAX_ECHOED_QUERY_LENGTH = 40;\n\nexport function AvailableProvidersGrid<TEntry extends ModelProviderCatalogEntryDto>({\n entries,\n onSelect,\n trailingCard,\n trailingCardMatchesSearch = () => true,\n}: {\n entries: TEntry[];\n onSelect: (entry: TEntry) => void;\n trailingCard?: ReactNode | undefined;\n trailingCardMatchesSearch?: ((query: string) => boolean) | undefined;\n}) {\n const [search, setSearch] = useState('');\n const inputRef = useRef<HTMLInputElement | null>(null);\n const trimmedSearch = search.trim();\n const filteredEntries = useMemo(\n () => entries.filter((entry) => providerMatchesSearch(entry, search)),\n [entries, search],\n );\n const trailingCardVisible = trailingCard !== undefined && trailingCardMatchesSearch(search);\n const visibleCount = filteredEntries.length + (trailingCardVisible ? 1 : 0);\n const showSearch = entries.length > SEARCH_VISIBILITY_THRESHOLD || trimmedSearch !== '';\n const providerListLabel =\n trimmedSearch !== '' ? 'Available providers matching search' : 'Available providers';\n const resultCountText =\n trimmedSearch === '' ? '' : providerResultCountText(filteredEntries.length, trimmedSearch);\n\n function clearSearch() {\n setSearch('');\n inputRef.current?.focus();\n }\n\n return (\n <div className=\"flex flex-col gap-12\">\n {showSearch ? (\n <Input\n ref={inputRef}\n type=\"search\"\n aria-label=\"Search providers\"\n placeholder=\"Search providers...\"\n value={search}\n iconLeft={<Icon name=\"searchLine\" className=\"size-16 text-foreground-neutral-muted\" />}\n onChange={(event) => setSearch(event.target.value)}\n />\n ) : null}\n\n {visibleCount > 0 ? (\n <ul className={PROVIDER_GRID_CLASS} aria-label={providerListLabel}>\n {filteredEntries.map((entry) => (\n <AvailableProviderCard\n key={entry.id}\n entry={entry}\n onConfigure={() => onSelect(entry)}\n />\n ))}\n {trailingCardVisible ? trailingCard : null}\n </ul>\n ) : (\n <NoProviderSearchResults search={trimmedSearch} onClear={clearSearch} />\n )}\n\n <p role=\"status\" aria-live=\"polite\" className=\"sr-only\">\n {resultCountText}\n </p>\n </div>\n );\n}\n\nfunction NoProviderSearchResults({search, onClear}: {search: string; onClear: () => void}) {\n return (\n <EmptyState\n icon=\"searchLine\"\n title={`No providers match \"${truncateQuery(search)}\"`}\n description=\"Try a different search, or clear it to see all providers.\"\n action={\n <Button size=\"sm\" variant=\"secondary\" onClick={onClear}>\n Clear search\n </Button>\n }\n />\n );\n}\n\nfunction truncateQuery(query: string): string {\n if (query.length <= MAX_ECHOED_QUERY_LENGTH) return query;\n return `${query.slice(0, MAX_ECHOED_QUERY_LENGTH - 3)}...`;\n}\n\nfunction providerResultCountText(count: number, query: string): string {\n if (count === 1) return `1 provider matches \"${query}\"`;\n return `${count} providers match \"${query}\"`;\n}\n"],"names":["Button","EmptyState","Icon","Input","useMemo","useRef","useState","AvailableProviderCard","providerMatchesSearch","PROVIDER_GRID_CLASS","SEARCH_VISIBILITY_THRESHOLD","MAX_ECHOED_QUERY_LENGTH","AvailableProvidersGrid","entries","onSelect","trailingCard","trailingCardMatchesSearch","search","setSearch","inputRef","trimmedSearch","trim","filteredEntries","filter","entry","trailingCardVisible","undefined","visibleCount","length","showSearch","providerListLabel","resultCountText","providerResultCountText","clearSearch","current","focus","div","className","ref","type","aria-label","placeholder","value","iconLeft","name","onChange","event","target","ul","map","onConfigure","id","NoProviderSearchResults","onClear","p","role","aria-live","icon","title","truncateQuery","description","action","size","variant","onClick","query","slice","count"],"mappings":";AACA,SAAQA,MAAM,QAAO,2BAA2B;AAChD,SAAQC,UAAU,QAAO,gCAAgC;AACzD,SAAQC,IAAI,QAAO,yBAAyB;AAC5C,SAAQC,KAAK,QAAO,0BAA0B;AAE9C,SAAQC,OAAO,EAAEC,MAAM,EAAEC,QAAQ,QAAO,QAAQ;AAChD,SAAQC,qBAAqB,QAAO,+BAA+B;AACnE,SAAQC,qBAAqB,QAAO,uBAAuB;AAE3D,OAAO,MAAMC,sBAAsB,kDAAkD;AAErF,MAAMC,8BAA8B;AACpC,MAAMC,0BAA0B;AAEhC,OAAO,SAASC,uBAAoE,EAClFC,OAAO,EACPC,QAAQ,EACRC,YAAY,EACZC,4BAA4B,IAAM,IAAI,EAMvC;IACC,MAAM,CAACC,QAAQC,UAAU,GAAGZ,SAAS;IACrC,MAAMa,WAAWd,OAAgC;IACjD,MAAMe,gBAAgBH,OAAOI,IAAI;IACjC,MAAMC,kBAAkBlB,QACtB,IAAMS,QAAQU,MAAM,CAAC,CAACC,QAAUhB,sBAAsBgB,OAAOP,UAC7D;QAACJ;QAASI;KAAO;IAEnB,MAAMQ,sBAAsBV,iBAAiBW,aAAaV,0BAA0BC;IACpF,MAAMU,eAAeL,gBAAgBM,MAAM,GAAIH,CAAAA,sBAAsB,IAAI,CAAA;IACzE,MAAMI,aAAahB,QAAQe,MAAM,GAAGlB,+BAA+BU,kBAAkB;IACrF,MAAMU,oBACJV,kBAAkB,KAAK,wCAAwC;IACjE,MAAMW,kBACJX,kBAAkB,KAAK,KAAKY,wBAAwBV,gBAAgBM,MAAM,EAAER;IAE9E,SAASa;QACPf,UAAU;QACVC,SAASe,OAAO,EAAEC;IACpB;IAEA,qBACE,MAACC;QAAIC,WAAU;;YACZR,2BACC,KAAC1B;gBACCmC,KAAKnB;gBACLoB,MAAK;gBACLC,cAAW;gBACXC,aAAY;gBACZC,OAAOzB;gBACP0B,wBAAU,KAACzC;oBAAK0C,MAAK;oBAAaP,WAAU;;gBAC5CQ,UAAU,CAACC,QAAU5B,UAAU4B,MAAMC,MAAM,CAACL,KAAK;iBAEjD;YAEHf,eAAe,kBACd,MAACqB;gBAAGX,WAAW5B;gBAAqB+B,cAAYV;;oBAC7CR,gBAAgB2B,GAAG,CAAC,CAACzB,sBACpB,KAACjB;4BAECiB,OAAOA;4BACP0B,aAAa,IAAMpC,SAASU;2BAFvBA,MAAM2B,EAAE;oBAKhB1B,sBAAsBV,eAAe;;+BAGxC,KAACqC;gBAAwBnC,QAAQG;gBAAeiC,SAASpB;;0BAG3D,KAACqB;gBAAEC,MAAK;gBAASC,aAAU;gBAASnB,WAAU;0BAC3CN;;;;AAIT;AAEA,SAASqB,wBAAwB,EAACnC,MAAM,EAAEoC,OAAO,EAAwC;IACvF,qBACE,KAACpD;QACCwD,MAAK;QACLC,OAAO,CAAC,oBAAoB,EAAEC,cAAc1C,QAAQ,CAAC,CAAC;QACtD2C,aAAY;QACZC,sBACE,KAAC7D;YAAO8D,MAAK;YAAKC,SAAQ;YAAYC,SAASX;sBAAS;;;AAMhE;AAEA,SAASM,cAAcM,KAAa;IAClC,IAAIA,MAAMrC,MAAM,IAAIjB,yBAAyB,OAAOsD;IACpD,OAAO,GAAGA,MAAMC,KAAK,CAAC,GAAGvD,0BAA0B,GAAG,GAAG,CAAC;AAC5D;AAEA,SAASqB,wBAAwBmC,KAAa,EAAEF,KAAa;IAC3D,IAAIE,UAAU,GAAG,OAAO,CAAC,oBAAoB,EAAEF,MAAM,CAAC,CAAC;IACvD,OAAO,GAAGE,MAAM,kBAAkB,EAAEF,MAAM,CAAC,CAAC;AAC9C"}
@@ -0,0 +1,9 @@
1
+ import type { ModelProviderConfigDto } from '@shipfox/api-agent-dto';
2
+ import type { SupportedModelProviderCatalogEntry } from './supported-model-provider-catalog-entry.js';
3
+ export declare function ChangeDefaultModelForm({ workspaceId, entry, config, onSaved, }: {
4
+ workspaceId: string;
5
+ entry: SupportedModelProviderCatalogEntry;
6
+ config: ModelProviderConfigDto;
7
+ onSaved: () => void;
8
+ }): import("react").JSX.Element;
9
+ //# sourceMappingURL=change-default-model-form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"change-default-model-form.d.ts","sourceRoot":"","sources":["../../src/components/change-default-model-form.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,wBAAwB,CAAC;AAenE,OAAO,KAAK,EAAC,kCAAkC,EAAC,MAAM,6CAA6C,CAAC;AAIpG,wBAAgB,sBAAsB,CAAC,EACrC,WAAW,EACX,KAAK,EACL,MAAM,EACN,OAAO,GACR,EAAE;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,kCAAkC,CAAC;IAC1C,MAAM,EAAE,sBAAsB,CAAC;IAC/B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,+BA0EA"}
@@ -0,0 +1,98 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Button } from '@shipfox/react-ui/button';
3
+ import { Callout } from '@shipfox/react-ui/callout';
4
+ import { fieldError } from '@shipfox/react-ui/form-field';
5
+ import { ModalBody, ModalFooter } from '@shipfox/react-ui/modal';
6
+ import { Text } from '@shipfox/react-ui/typography';
7
+ import { useForm } from '@tanstack/react-form';
8
+ import { useState } from 'react';
9
+ import { useUpdateModelProviderDefaultModelMutation } from '#hooks/api/model-providers.js';
10
+ import { DefaultModelField, defaultModelFormValue, selectedModelForModelPayload } from './default-model-field.js';
11
+ import { modelProviderConfigErrorToFormError } from './form-errors.js';
12
+ const CHANGE_DEFAULT_MODEL_FORM_ID = 'model-provider-change-default-model-form';
13
+ export function ChangeDefaultModelForm({ workspaceId, entry, config, onSaved }) {
14
+ const updateDefaultModel = useUpdateModelProviderDefaultModelMutation();
15
+ const [formError, setFormError] = useState();
16
+ const form = useForm({
17
+ defaultValues: {
18
+ default_model: defaultModelFormValue(config.default_model)
19
+ },
20
+ onSubmit: async ({ value })=>{
21
+ setFormError(undefined);
22
+ try {
23
+ await updateDefaultModel.mutateAsync({
24
+ workspaceId,
25
+ providerId: entry.id,
26
+ body: {
27
+ default_model: selectedModelForModelPayload(value.default_model)
28
+ }
29
+ });
30
+ onSaved();
31
+ } catch (error) {
32
+ const mapped = modelProviderConfigErrorToFormError(error);
33
+ setFormError(mapped.message);
34
+ }
35
+ }
36
+ });
37
+ return /*#__PURE__*/ _jsxs(_Fragment, {
38
+ children: [
39
+ /*#__PURE__*/ _jsxs(ModalBody, {
40
+ className: "gap-16",
41
+ children: [
42
+ /*#__PURE__*/ _jsx("form", {
43
+ id: CHANGE_DEFAULT_MODEL_FORM_ID,
44
+ className: "flex w-full flex-col gap-14",
45
+ noValidate: true,
46
+ onSubmit: (event)=>{
47
+ event.preventDefault();
48
+ event.stopPropagation();
49
+ void form.handleSubmit();
50
+ },
51
+ children: /*#__PURE__*/ _jsx(form.Field, {
52
+ name: "default_model",
53
+ validators: {
54
+ onBlur: ({ value })=>value.trim() ? undefined : 'Default model is required.',
55
+ onSubmit: ({ value })=>value.trim() ? undefined : 'Default model is required.'
56
+ },
57
+ children: (field)=>/*#__PURE__*/ _jsx(DefaultModelField, {
58
+ entry: entry,
59
+ value: field.state.value,
60
+ error: fieldError(field),
61
+ onChange: (event)=>field.handleChange(event.target.value),
62
+ onBlur: field.handleBlur
63
+ })
64
+ })
65
+ }),
66
+ formError ? /*#__PURE__*/ _jsx(Callout, {
67
+ role: "alert",
68
+ type: "error",
69
+ children: /*#__PURE__*/ _jsxs("div", {
70
+ className: "flex flex-col gap-8",
71
+ children: [
72
+ /*#__PURE__*/ _jsx(Text, {
73
+ size: "sm",
74
+ bold: true,
75
+ children: "Could not save default model"
76
+ }),
77
+ /*#__PURE__*/ _jsx(Text, {
78
+ size: "sm",
79
+ children: formError
80
+ })
81
+ ]
82
+ })
83
+ }) : null
84
+ ]
85
+ }),
86
+ /*#__PURE__*/ _jsx(ModalFooter, {
87
+ children: /*#__PURE__*/ _jsx(Button, {
88
+ type: "submit",
89
+ form: CHANGE_DEFAULT_MODEL_FORM_ID,
90
+ isLoading: updateDefaultModel.isPending,
91
+ children: "Save model"
92
+ })
93
+ })
94
+ ]
95
+ });
96
+ }
97
+
98
+ //# sourceMappingURL=change-default-model-form.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/change-default-model-form.tsx"],"sourcesContent":["import type {ModelProviderConfigDto} from '@shipfox/api-agent-dto';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {fieldError} from '@shipfox/react-ui/form-field';\nimport {ModalBody, ModalFooter} from '@shipfox/react-ui/modal';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useForm} from '@tanstack/react-form';\nimport {useState} from 'react';\nimport {useUpdateModelProviderDefaultModelMutation} from '#hooks/api/model-providers.js';\nimport {\n DefaultModelField,\n defaultModelFormValue,\n selectedModelForModelPayload,\n} from './default-model-field.js';\nimport {modelProviderConfigErrorToFormError} from './form-errors.js';\nimport type {SupportedModelProviderCatalogEntry} from './supported-model-provider-catalog-entry.js';\n\nconst CHANGE_DEFAULT_MODEL_FORM_ID = 'model-provider-change-default-model-form';\n\nexport function ChangeDefaultModelForm({\n workspaceId,\n entry,\n config,\n onSaved,\n}: {\n workspaceId: string;\n entry: SupportedModelProviderCatalogEntry;\n config: ModelProviderConfigDto;\n onSaved: () => void;\n}) {\n const updateDefaultModel = useUpdateModelProviderDefaultModelMutation();\n const [formError, setFormError] = useState<string | undefined>();\n const form = useForm({\n defaultValues: {default_model: defaultModelFormValue(config.default_model)},\n onSubmit: async ({value}) => {\n setFormError(undefined);\n try {\n await updateDefaultModel.mutateAsync({\n workspaceId,\n providerId: entry.id,\n body: {default_model: selectedModelForModelPayload(value.default_model)},\n });\n onSaved();\n } catch (error) {\n const mapped = modelProviderConfigErrorToFormError(error);\n setFormError(mapped.message);\n }\n },\n });\n\n return (\n <>\n <ModalBody className=\"gap-16\">\n <form\n id={CHANGE_DEFAULT_MODEL_FORM_ID}\n className=\"flex w-full flex-col gap-14\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n void form.handleSubmit();\n }}\n >\n <form.Field\n name=\"default_model\"\n validators={{\n onBlur: ({value}) => (value.trim() ? undefined : 'Default model is required.'),\n onSubmit: ({value}) => (value.trim() ? undefined : 'Default model is required.'),\n }}\n >\n {(field) => (\n <DefaultModelField\n entry={entry}\n value={field.state.value}\n error={fieldError(field)}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={field.handleBlur}\n />\n )}\n </form.Field>\n </form>\n {formError ? (\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex flex-col gap-8\">\n <Text size=\"sm\" bold>\n Could not save default model\n </Text>\n <Text size=\"sm\">{formError}</Text>\n </div>\n </Callout>\n ) : null}\n </ModalBody>\n <ModalFooter>\n <Button\n type=\"submit\"\n form={CHANGE_DEFAULT_MODEL_FORM_ID}\n isLoading={updateDefaultModel.isPending}\n >\n Save model\n </Button>\n </ModalFooter>\n </>\n );\n}\n"],"names":["Button","Callout","fieldError","ModalBody","ModalFooter","Text","useForm","useState","useUpdateModelProviderDefaultModelMutation","DefaultModelField","defaultModelFormValue","selectedModelForModelPayload","modelProviderConfigErrorToFormError","CHANGE_DEFAULT_MODEL_FORM_ID","ChangeDefaultModelForm","workspaceId","entry","config","onSaved","updateDefaultModel","formError","setFormError","form","defaultValues","default_model","onSubmit","value","undefined","mutateAsync","providerId","id","body","error","mapped","message","className","noValidate","event","preventDefault","stopPropagation","handleSubmit","Field","name","validators","onBlur","trim","field","state","onChange","handleChange","target","handleBlur","role","type","div","size","bold","isLoading","isPending"],"mappings":";AACA,SAAQA,MAAM,QAAO,2BAA2B;AAChD,SAAQC,OAAO,QAAO,4BAA4B;AAClD,SAAQC,UAAU,QAAO,+BAA+B;AACxD,SAAQC,SAAS,EAAEC,WAAW,QAAO,0BAA0B;AAC/D,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,OAAO,QAAO,uBAAuB;AAC7C,SAAQC,QAAQ,QAAO,QAAQ;AAC/B,SAAQC,0CAA0C,QAAO,gCAAgC;AACzF,SACEC,iBAAiB,EACjBC,qBAAqB,EACrBC,4BAA4B,QACvB,2BAA2B;AAClC,SAAQC,mCAAmC,QAAO,mBAAmB;AAGrE,MAAMC,+BAA+B;AAErC,OAAO,SAASC,uBAAuB,EACrCC,WAAW,EACXC,KAAK,EACLC,MAAM,EACNC,OAAO,EAMR;IACC,MAAMC,qBAAqBX;IAC3B,MAAM,CAACY,WAAWC,aAAa,GAAGd;IAClC,MAAMe,OAAOhB,QAAQ;QACnBiB,eAAe;YAACC,eAAed,sBAAsBO,OAAOO,aAAa;QAAC;QAC1EC,UAAU,OAAO,EAACC,KAAK,EAAC;YACtBL,aAAaM;YACb,IAAI;gBACF,MAAMR,mBAAmBS,WAAW,CAAC;oBACnCb;oBACAc,YAAYb,MAAMc,EAAE;oBACpBC,MAAM;wBAACP,eAAeb,6BAA6Be,MAAMF,aAAa;oBAAC;gBACzE;gBACAN;YACF,EAAE,OAAOc,OAAO;gBACd,MAAMC,SAASrB,oCAAoCoB;gBACnDX,aAAaY,OAAOC,OAAO;YAC7B;QACF;IACF;IAEA,qBACE;;0BACE,MAAC/B;gBAAUgC,WAAU;;kCACnB,KAACb;wBACCQ,IAAIjB;wBACJsB,WAAU;wBACVC,UAAU;wBACVX,UAAU,CAACY;4BACTA,MAAMC,cAAc;4BACpBD,MAAME,eAAe;4BACrB,KAAKjB,KAAKkB,YAAY;wBACxB;kCAEA,cAAA,KAAClB,KAAKmB,KAAK;4BACTC,MAAK;4BACLC,YAAY;gCACVC,QAAQ,CAAC,EAAClB,KAAK,EAAC,GAAMA,MAAMmB,IAAI,KAAKlB,YAAY;gCACjDF,UAAU,CAAC,EAACC,KAAK,EAAC,GAAMA,MAAMmB,IAAI,KAAKlB,YAAY;4BACrD;sCAEC,CAACmB,sBACA,KAACrC;oCACCO,OAAOA;oCACPU,OAAOoB,MAAMC,KAAK,CAACrB,KAAK;oCACxBM,OAAO9B,WAAW4C;oCAClBE,UAAU,CAACX,QAAUS,MAAMG,YAAY,CAACZ,MAAMa,MAAM,CAACxB,KAAK;oCAC1DkB,QAAQE,MAAMK,UAAU;;;;oBAK/B/B,0BACC,KAACnB;wBAAQmD,MAAK;wBAAQC,MAAK;kCACzB,cAAA,MAACC;4BAAInB,WAAU;;8CACb,KAAC9B;oCAAKkD,MAAK;oCAAKC,IAAI;8CAAC;;8CAGrB,KAACnD;oCAAKkD,MAAK;8CAAMnC;;;;yBAGnB;;;0BAEN,KAAChB;0BACC,cAAA,KAACJ;oBACCqD,MAAK;oBACL/B,MAAMT;oBACN4C,WAAWtC,mBAAmBuC,SAAS;8BACxC;;;;;AAMT"}