@cartanova/qgrid-cli 2.7.3 → 2.7.5

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 (42) hide show
  1. package/bundle/dist/application/queries.generated.js +2 -1
  2. package/bundle/dist/application/request-log/json-schema-type-text.js +58 -2
  3. package/bundle/dist/application/request-log/request-log.model.js +44 -3
  4. package/bundle/dist/application/request-log/request-log.types.js +10 -4
  5. package/bundle/src/application/queries.generated.ts +3 -0
  6. package/bundle/src/application/request-log/json-schema-type-text.test.ts +115 -1
  7. package/bundle/src/application/request-log/json-schema-type-text.ts +91 -0
  8. package/bundle/src/application/request-log/request-log.model.test.ts +166 -0
  9. package/bundle/src/application/request-log/request-log.model.ts +52 -6
  10. package/bundle/src/application/request-log/request-log.types.ts +11 -2
  11. package/bundle/src/application/sonamu.generated.http +6 -2
  12. package/bundle/web-dist/client/assets/index-CwSSXuZv.js +106 -0
  13. package/bundle/web-dist/client/assets/index-D9xE_tO7.css +1 -0
  14. package/bundle/web-dist/client/assets/logs-BrAu0koY.js +1 -0
  15. package/bundle/web-dist/client/assets/{monit-BngOoU4n.js → monit-D6JEk7n7.js} +1 -1
  16. package/bundle/web-dist/client/assets/{routes-BnQE0rPF.js → routes-Dvu63qre.js} +1 -1
  17. package/bundle/web-dist/client/assets/{services.generated-CSW8bhCP.js → services.generated-CA7oRRYY.js} +4 -4
  18. package/bundle/web-dist/client/assets/settings-mwDGFwUi.js +1 -0
  19. package/bundle/web-dist/client/assets/show-BFGjYsWb.js +2 -0
  20. package/bundle/web-dist/client/assets/{tokens-LHoEigmF.js → tokens-D-P__jYk.js} +1 -1
  21. package/bundle/web-dist/client/assets/{use-oauth-login-flow-YyU4TDzU.js → use-oauth-login-flow-CJpoJD26.js} +1 -1
  22. package/bundle/web-dist/client/index.html +3 -3
  23. package/bundle/web-dist/server/assets/{lazyRouteComponent-0y-znAfz.js → lazyRouteComponent-tS-rTksX.js} +2 -2
  24. package/bundle/web-dist/server/assets/{logs-CJBbHM3_.js → logs-ttf79emP.js} +3 -14
  25. package/bundle/web-dist/server/assets/{monit-8WAsPETB.js → monit-CJBUH0l6.js} +2 -2
  26. package/bundle/web-dist/server/assets/{plus-9das21ju.js → plus-BuSuoeon.js} +1 -1
  27. package/bundle/web-dist/server/assets/{react-dom-zmEq8BVp.js → react-dom-7_SqhNWR.js} +1 -1
  28. package/bundle/web-dist/server/assets/{routes-B6bX3o41.js → routes-z79f1sOM.js} +3 -3
  29. package/bundle/web-dist/server/assets/{services.generated-DyPeBI00.js → services.generated-B5UkNmgc.js} +20 -38
  30. package/bundle/web-dist/server/assets/{settings-D1u5WdpP.js → settings-nCv71sax.js} +2 -2
  31. package/bundle/web-dist/server/assets/{show-Cr7vwR0l.js → show-CLrA4ZQ-.js} +158 -37
  32. package/bundle/web-dist/server/assets/{tokens-BumM0gnH.js → tokens-BwlkZELV.js} +3 -3
  33. package/bundle/web-dist/server/assets/{use-oauth-login-flow-DmsHGOlx.js → use-oauth-login-flow-B2QllVMi.js} +1 -1
  34. package/bundle/web-dist/server/entry-server.generated.js +10 -11
  35. package/package.json +3 -2
  36. package/skills/qgrid/references/request-log-run-lifecycle.md +9 -1
  37. package/skills/qgrid/references/sonamu-api-web-flow.md +3 -1
  38. package/bundle/web-dist/client/assets/index-BldeEvAK.css +0 -1
  39. package/bundle/web-dist/client/assets/index-QxWJK2qE.js +0 -106
  40. package/bundle/web-dist/client/assets/logs-DaNYzis5.js +0 -1
  41. package/bundle/web-dist/client/assets/settings-CPeAjsL3.js +0 -1
  42. package/bundle/web-dist/client/assets/show-DUOfuZj1.js +0 -2
@@ -1,5 +1,5 @@
1
- import { H as __toESM, S as require_react, i as RequestLogStepService, r as RequestLogService, x as require_jsx_runtime, z as __commonJSMin } from "./services.generated-DyPeBI00.js";
2
- import { a as Link } from "./lazyRouteComponent-0y-znAfz.js";
1
+ import { R as __commonJSMin, V as __toESM, _ as useQuery, b as require_jsx_runtime, i as RequestLogStepService, r as RequestLogService, x as require_react } from "./services.generated-B5UkNmgc.js";
2
+ import { a as Link } from "./lazyRouteComponent-tS-rTksX.js";
3
3
  import { c as remarkGfm, l as Markdown, o as lucideX, t as Route } from "../entry-server.generated.js";
4
4
  import { n as formatMicroUsd, t as cacheHitRate } from "./cost-CSH_t17I.js";
5
5
  //#region ../../node_modules/.pnpm/@babel+runtime@7.29.2/node_modules/@babel/runtime/helpers/extends.js
@@ -2060,16 +2060,29 @@ function FormattedContent({ text, markdown }) {
2060
2060
  children: JSON.stringify(parsed.value, null, 2)
2061
2061
  })] });
2062
2062
  }
2063
- function Section({ title, defaultOpen = true, children }) {
2063
+ function Section({ title, defaultOpen = true, headerMetadata, onOpenChange, children }) {
2064
+ const [open, setOpen] = (0, import_react.useState)(defaultOpen);
2064
2065
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", {
2065
- open: defaultOpen,
2066
+ open,
2066
2067
  className: "group panel overflow-hidden",
2068
+ onToggle: (event) => {
2069
+ const nextOpen = event.currentTarget.open;
2070
+ setOpen(nextOpen);
2071
+ onOpenChange?.(nextOpen);
2072
+ },
2067
2073
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("summary", {
2068
- className: "panel-header flex items-center gap-1.5 cursor-pointer select-none list-none px-4 py-2.5",
2069
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(lucideChevronDown, { className: "size-3.5 text-sand-400 transition-transform group-open:rotate-0 -rotate-90" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2070
- className: "text-[11px] uppercase tracking-wider text-sand-500 font-medium",
2071
- children: title
2072
- })]
2074
+ className: "panel-header flex min-w-0 items-center gap-1.5 whitespace-nowrap cursor-pointer select-none list-none px-4 py-2.5",
2075
+ children: [
2076
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(lucideChevronDown, { className: "size-3.5 shrink-0 text-sand-400 transition-transform group-open:rotate-0 -rotate-90" }),
2077
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2078
+ className: "shrink-0 text-[11px] uppercase tracking-wider text-sand-500 font-medium",
2079
+ children: title
2080
+ }),
2081
+ headerMetadata && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2082
+ className: "flex min-w-0 flex-1 items-center gap-1.5 overflow-hidden whitespace-nowrap text-[11px] normal-case text-sand-400",
2083
+ children: headerMetadata
2084
+ })
2085
+ ]
2073
2086
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
2074
2087
  className: "p-4",
2075
2088
  children
@@ -2647,29 +2660,124 @@ function HistorySection({ history }) {
2647
2660
  })
2648
2661
  });
2649
2662
  }
2650
- function ToolsSection({ tools }) {
2663
+ var TOOL_NAME_PREVIEW_CHARACTERS = 60;
2664
+ var TOOL_NAME_COMPACT_PREVIEW_CHARACTERS = 30;
2665
+ var TOOL_NAME_MOBILE_PREVIEW_CHARACTERS = 18;
2666
+ function toolNamePreview(tools, maxCharacters = TOOL_NAME_PREVIEW_CHARACTERS) {
2667
+ const names = [];
2668
+ for (const tool of tools) {
2669
+ if ([...names, tool.name].join(", ").length > maxCharacters) break;
2670
+ names.push(tool.name);
2671
+ }
2672
+ return {
2673
+ names,
2674
+ omittedCount: tools.length - names.length
2675
+ };
2676
+ }
2677
+ function ToolsHeaderMetadata({ tools }) {
2678
+ const wide = toolNamePreview(tools);
2679
+ const compact = toolNamePreview(tools, TOOL_NAME_COMPACT_PREVIEW_CHARACTERS);
2680
+ const mobile = toolNamePreview(tools, TOOL_NAME_MOBILE_PREVIEW_CHARACTERS);
2681
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
2682
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2683
+ className: "shrink-0",
2684
+ children: "·"
2685
+ }),
2686
+ wide.names.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2687
+ className: "hidden shrink-0 xl:inline",
2688
+ children: wide.names.join(", ")
2689
+ }),
2690
+ wide.omittedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
2691
+ className: "hidden shrink-0 xl:inline",
2692
+ children: ["+", wide.omittedCount]
2693
+ }),
2694
+ compact.names.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2695
+ className: "hidden shrink-0 sm:inline xl:hidden",
2696
+ children: compact.names.join(", ")
2697
+ }),
2698
+ compact.omittedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
2699
+ className: "hidden shrink-0 sm:inline xl:hidden",
2700
+ children: ["+", compact.omittedCount]
2701
+ }),
2702
+ mobile.names.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2703
+ className: "shrink-0 sm:hidden",
2704
+ children: mobile.names.join(", ")
2705
+ }),
2706
+ mobile.omittedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
2707
+ className: "shrink-0 sm:hidden",
2708
+ children: ["+", mobile.omittedCount]
2709
+ })
2710
+ ] });
2711
+ }
2712
+ function ToolInputZod({ code, fullCode }) {
2713
+ const highlighted = (0, import_react.useMemo)(() => highlightTypeText(code), [code]);
2714
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", {
2715
+ "data-zod-parameter-shape": true,
2716
+ className: `max-h-64 overflow-auto rounded-md bg-sand-900 px-3 py-2.5 font-mono text-[11px] leading-relaxed whitespace-pre text-sand-200 ${fullCode ? "cursor-help outline-none focus-visible:ring-2 focus-visible:ring-sienna-300" : ""}`,
2717
+ tabIndex: fullCode ? 0 : void 0,
2718
+ title: fullCode,
2719
+ children: fullCode ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2720
+ "aria-hidden": "true",
2721
+ children: highlighted
2722
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2723
+ className: "sr-only",
2724
+ children: fullCode
2725
+ })] }) : highlighted
2726
+ });
2727
+ }
2728
+ function ToolCard({ tool }) {
2729
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
2730
+ className: "min-w-0 rounded-md border border-sand-100 bg-sand-50/70 p-3",
2731
+ children: [
2732
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
2733
+ className: "break-all font-mono text-[13px] font-semibold text-sand-900",
2734
+ children: tool.name
2735
+ }),
2736
+ tool.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
2737
+ className: "mt-2 text-[12px] leading-relaxed text-sand-700",
2738
+ children: tool.description
2739
+ }),
2740
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
2741
+ className: "mt-3",
2742
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
2743
+ className: "mb-1.5 text-[10px] font-medium uppercase tracking-wider text-sand-400",
2744
+ children: [
2745
+ "Parameters (",
2746
+ tool.parameterCount,
2747
+ ")"
2748
+ ]
2749
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToolInputZod, {
2750
+ code: tool.inputZod,
2751
+ fullCode: tool.fullInputZod
2752
+ })]
2753
+ })
2754
+ ]
2755
+ });
2756
+ }
2757
+ function ToolsPanel({ id, tools }) {
2758
+ const [open, setOpen] = (0, import_react.useState)(false);
2759
+ const query = useQuery({
2760
+ ...RequestLogService.toolsViewQueryOptions(id),
2761
+ enabled: open,
2762
+ staleTime: (currentQuery) => currentQuery.state.data && currentQuery.state.data.length > 0 ? Infinity : 0,
2763
+ refetchOnWindowFocus: false,
2764
+ refetchOnReconnect: false
2765
+ });
2766
+ const hasView = query.data !== void 0 && query.data.length > 0;
2651
2767
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Section, {
2652
2768
  title: `Tools (${tools.length})`,
2653
2769
  defaultOpen: false,
2654
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
2655
- className: "space-y-1.5",
2656
- children: tools.map((tool, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
2657
- className: "rounded-md px-3 py-2 bg-caution-400/10",
2658
- children: [
2659
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
2660
- className: "text-[10px] uppercase tracking-wider text-sand-500 font-medium mb-1",
2661
- children: ["fn: ", tool.name]
2662
- }),
2663
- tool.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
2664
- className: "text-[12px] text-sand-700 leading-relaxed",
2665
- children: tool.description
2666
- }),
2667
- tool.inputSchema !== void 0 && tool.inputSchema !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MonoPre, {
2668
- className: "mt-1",
2669
- children: JSON.stringify(tool.inputSchema, null, 2)
2670
- })
2671
- ]
2672
- }, `tool-${i}`))
2770
+ headerMetadata: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToolsHeaderMetadata, { tools }),
2771
+ onOpenChange: setOpen,
2772
+ children: query.isFetching && !hasView ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
2773
+ className: "text-[12px] text-sand-400",
2774
+ children: "Loading tool contracts…"
2775
+ }) : query.isError || !hasView ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
2776
+ className: "text-[12px] text-sand-400",
2777
+ children: "Tool contracts could not be loaded."
2778
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
2779
+ className: "space-y-2",
2780
+ children: query.data.map((tool, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToolCard, { tool }, `${tool.name}-${index}`))
2673
2781
  })
2674
2782
  });
2675
2783
  }
@@ -2754,14 +2862,14 @@ function ResponseTypePanel({ id }) {
2754
2862
  }
2755
2863
  function RequestDetail({ id }) {
2756
2864
  const { data, isLoading } = RequestLogService.useRequestLog("A", id);
2757
- const { data: stepsData } = RequestLogStepService.useRequestLogSteps("T", {
2865
+ const { data: stepsData, isLoading: isStepsLoading } = RequestLogStepService.useRequestLogSteps("T", {
2758
2866
  request_log_id: id,
2759
2867
  num: 0,
2760
2868
  page: 1,
2761
2869
  orderBy: "id-asc"
2762
2870
  });
2763
2871
  const stepTree = buildStepTree(stepsData?.rows ?? []);
2764
- if (isLoading) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
2872
+ if (isLoading || isStepsLoading) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
2765
2873
  className: "max-w-6xl mx-auto space-y-4",
2766
2874
  children: [
2767
2875
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-4 w-32 bg-sand-200 rounded animate-pulse" }),
@@ -2825,20 +2933,33 @@ function RequestDetail({ id }) {
2825
2933
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HeaderBar, { data }),
2826
2934
  data.error_message && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorPanel, { message: data.error_message }),
2827
2935
  hasHistory && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HistorySection, { history }),
2828
- hasTools && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToolsSection, { tools }),
2829
2936
  hasSteps ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
2830
2937
  className: "flex flex-col lg:flex-row gap-4 items-stretch lg:items-start",
2831
2938
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
2832
2939
  className: "order-1 lg:order-2 flex-1 min-w-0 space-y-4",
2833
- children: [responseTypePanel, /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StepTreeSection, {
2834
- steps: stepTree,
2835
- tokensPerSecEnabled
2836
- })]
2940
+ children: [
2941
+ responseTypePanel,
2942
+ hasTools && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToolsPanel, {
2943
+ id,
2944
+ tools
2945
+ }),
2946
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StepTreeSection, {
2947
+ steps: stepTree,
2948
+ tokensPerSecEnabled
2949
+ })
2950
+ ]
2837
2951
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
2838
2952
  className: "order-2 lg:order-1 flex-1 min-w-0",
2839
2953
  children: promptSections
2840
2954
  })]
2841
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [responseTypePanel, promptSections] }),
2955
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
2956
+ responseTypePanel,
2957
+ hasTools && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToolsPanel, {
2958
+ id,
2959
+ tools
2960
+ }),
2961
+ promptSections
2962
+ ] }),
2842
2963
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Section, {
2843
2964
  title: "Response",
2844
2965
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
@@ -1,7 +1,7 @@
1
- import { H as __toESM, S as require_react, b as useQueryClient, n as QgridService, o as TokenService, x as require_jsx_runtime } from "./services.generated-DyPeBI00.js";
1
+ import { V as __toESM, b as require_jsx_runtime, n as QgridService, o as TokenService, x as require_react, y as useQueryClient } from "./services.generated-B5UkNmgc.js";
2
2
  import { i as Q, u as lucideKeyRound } from "../entry-server.generated.js";
3
- import { n as OAuthCodeEntry, r as useUpdateTokenMutation, t as useOAuthLoginFlow } from "./use-oauth-login-flow-DmsHGOlx.js";
4
- import { t as lucidePlus } from "./plus-9das21ju.js";
3
+ import { n as OAuthCodeEntry, r as useUpdateTokenMutation, t as useOAuthLoginFlow } from "./use-oauth-login-flow-B2QllVMi.js";
4
+ import { t as lucidePlus } from "./plus-BuSuoeon.js";
5
5
  //#region src/components/qgrid/AddTokenModal.tsx
6
6
  var import_react = /* @__PURE__ */ __toESM(require_react(), 1);
7
7
  var import_jsx_runtime = require_jsx_runtime();
@@ -1,4 +1,4 @@
1
- import { H as __toESM, S as require_react, _ as useMutation, b as useQueryClient, n as QgridService, x as require_jsx_runtime } from "./services.generated-DyPeBI00.js";
1
+ import { V as __toESM, b as require_jsx_runtime, g as useMutation, n as QgridService, x as require_react, y as useQueryClient } from "./services.generated-B5UkNmgc.js";
2
2
  import { i as Q } from "../entry-server.generated.js";
3
3
  //#region src/services/token/use-update-token-mutation.ts
4
4
  function useUpdateTokenMutation() {
@@ -1,6 +1,6 @@
1
- import { A as hashQueryKeyByOptions, B as __exportAll, C as Mutation, D as notifyManager, E as onlineManager, F as resolveStaleTime, H as __toESM, I as skipToken, L as focusManager, M as matchQuery, N as noop$1, O as functionalUpdate, P as partialMatchKey, R as Subscribable, S as require_react, T as Query, V as __require, c as SD, d as _enum, f as boolean$1, h as string$2, j as matchMutation, k as hashKey, l as SUPPORTED_LOCALES, m as object, n as QgridService, p as number$1, u as setLocale, v as useQuery, w as infiniteQueryBehavior, x as require_jsx_runtime, y as QueryClientProvider, z as __commonJSMin } from "./assets/services.generated-DyPeBI00.js";
2
- import { A as decodePath, C as findRouteMatch, D as createLRUCache, E as processRouteTree, F as last, I as replaceEqualDeep, M as findLast, N as functionalUpdate$1, O as invariant, P as isPromise, S as findFlatMatch, T as processRouteMasks, _ as interpolatePath, a as Link$1, b as trimPath, c as usePrevious$1, d as useRouter, f as getRouterContext, g as cleanPath, h as isNotFound, i as createRootRouteWithContext, j as deepEqual$2, k as createControlledPromise, l as matchContext, m as rootRouteId, n as createFileRoute, p as warning, r as createLazyFileRoute, s as useLayoutEffect$3, t as lazyRouteComponent, u as useRouterState, v as joinPaths, w as findSingleMatch, x as trimPathRight, y as resolvePath } from "./assets/lazyRouteComponent-0y-znAfz.js";
3
- import { n as require_shim, t as require_react_dom } from "./assets/react-dom-zmEq8BVp.js";
1
+ import { A as matchMutation, B as __require, C as infiniteQueryBehavior, D as functionalUpdate, E as notifyManager, F as skipToken, I as focusManager, L as Subscribable, M as noop$1, N as partialMatchKey, O as hashKey, P as resolveStaleTime, R as __commonJSMin, S as Mutation, T as onlineManager, V as __toESM, _ as useQuery, b as require_jsx_runtime, c as SD, d as _enum, f as number$1, j as matchQuery, k as hashQueryKeyByOptions, l as SUPPORTED_LOCALES, m as string$2, n as QgridService, p as object, u as setLocale, v as QueryClientProvider, w as Query, x as require_react, z as __exportAll } from "./assets/services.generated-B5UkNmgc.js";
2
+ import { A as decodePath, C as findRouteMatch, D as createLRUCache, E as processRouteTree, F as last, I as replaceEqualDeep, M as findLast, N as functionalUpdate$1, O as invariant, P as isPromise, S as findFlatMatch, T as processRouteMasks, _ as interpolatePath, a as Link$1, b as trimPath, c as usePrevious$1, d as useRouter, f as getRouterContext, g as cleanPath, h as isNotFound, i as createRootRouteWithContext, j as deepEqual$2, k as createControlledPromise, l as matchContext, m as rootRouteId, n as createFileRoute, p as warning, r as createLazyFileRoute, s as useLayoutEffect$3, t as lazyRouteComponent, u as useRouterState, v as joinPaths, w as findSingleMatch, x as trimPathRight, y as resolvePath } from "./assets/lazyRouteComponent-tS-rTksX.js";
3
+ import { n as require_shim, t as require_react_dom } from "./assets/react-dom-7_SqhNWR.js";
4
4
  import minpath from "node:path";
5
5
  import minproc from "node:process";
6
6
  import { fileURLToPath as urlToPath } from "node:url";
@@ -46580,7 +46580,7 @@ function ChatWidget() {
46580
46580
  }
46581
46581
  //#endregion
46582
46582
  //#region src/components/Sidebar.tsx
46583
- var qgridVersion = "2.7.3";
46583
+ var qgridVersion = "2.7.5";
46584
46584
  function Sidebar({ className }) {
46585
46585
  const pathname = useRouterState({ select: (s) => s.location.pathname });
46586
46586
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", {
@@ -68465,15 +68465,15 @@ function RootComponent() {
68465
68465
  }
68466
68466
  //#endregion
68467
68467
  //#region src/routes/tokens.tsx
68468
- var $$splitComponentImporter$5 = () => import("./assets/tokens-BumM0gnH.js");
68468
+ var $$splitComponentImporter$5 = () => import("./assets/tokens-BwlkZELV.js");
68469
68469
  var Route$5 = createFileRoute("/tokens")({ component: lazyRouteComponent($$splitComponentImporter$5, "component") });
68470
68470
  //#endregion
68471
68471
  //#region src/routes/settings.tsx
68472
- var $$splitComponentImporter$4 = () => import("./assets/settings-D1u5WdpP.js");
68472
+ var $$splitComponentImporter$4 = () => import("./assets/settings-nCv71sax.js");
68473
68473
  var Route$4 = createFileRoute("/settings")({ component: lazyRouteComponent($$splitComponentImporter$4, "component") });
68474
68474
  //#endregion
68475
68475
  //#region src/routes/monit.tsx
68476
- var $$splitComponentImporter$3 = () => import("./assets/monit-8WAsPETB.js");
68476
+ var $$splitComponentImporter$3 = () => import("./assets/monit-CJBUH0l6.js");
68477
68477
  var monitSearchSchema = object({ level: _enum([
68478
68478
  "all",
68479
68479
  "warn",
@@ -68485,13 +68485,12 @@ var Route$3 = createFileRoute("/monit")({
68485
68485
  });
68486
68486
  //#endregion
68487
68487
  //#region src/routes/logs.tsx
68488
- var $$splitComponentImporter$2 = () => import("./assets/logs-CJBbHM3_.js");
68488
+ var $$splitComponentImporter$2 = () => import("./assets/logs-ttf79emP.js");
68489
68489
  var logsSearchSchema = object({
68490
68490
  token: string$2().optional(),
68491
68491
  project: string$2().optional(),
68492
68492
  model: string$2().optional(),
68493
68493
  sort: string$2().optional(),
68494
- broken: boolean$1().optional(),
68495
68494
  page: number$1().optional().default(1)
68496
68495
  });
68497
68496
  var Route$2 = createFileRoute("/logs")({
@@ -68500,11 +68499,11 @@ var Route$2 = createFileRoute("/logs")({
68500
68499
  });
68501
68500
  //#endregion
68502
68501
  //#region src/routes/index.tsx
68503
- var $$splitComponentImporter$1 = () => import("./assets/routes-B6bX3o41.js");
68502
+ var $$splitComponentImporter$1 = () => import("./assets/routes-z79f1sOM.js");
68504
68503
  var Route$1 = createFileRoute("/")({ component: lazyRouteComponent($$splitComponentImporter$1, "component") });
68505
68504
  //#endregion
68506
68505
  //#region src/routes/requests/show.tsx
68507
- var $$splitComponentImporter = () => import("./assets/show-Cr7vwR0l.js");
68506
+ var $$splitComponentImporter = () => import("./assets/show-CLrA4ZQ-.js");
68508
68507
  var showSearchSchema = object({ id: number$1() });
68509
68508
  var Route = createFileRoute("/requests/show")({
68510
68509
  validateSearch: showSearchSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cartanova/qgrid-cli",
3
- "version": "2.7.3",
3
+ "version": "2.7.5",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/cartanova-ai/qgrid"
@@ -21,6 +21,7 @@
21
21
  "@ai-sdk/provider": "^3.0.0",
22
22
  "@ai-sdk/provider-utils": "^4.0.0",
23
23
  "@anthropic-ai/sdk": "^0.81.0",
24
+ "@better-auth/core": "~1.6.0",
24
25
  "@better-auth/passkey": "~1.6.0",
25
26
  "@better-auth/sso": "~1.6.0",
26
27
  "@logtape/logtape": "2.0.0",
@@ -29,7 +30,7 @@
29
30
  "@oxc-project/runtime": "^0.79.0",
30
31
  "ai": "^6.0.1",
31
32
  "bcrypt": "^6.0.0",
32
- "better-auth": "^1.6.0",
33
+ "better-auth": "~1.6.0",
33
34
  "chalk": "^4.1.2",
34
35
  "commander": "^13.0.0",
35
36
  "date-fns": "^4.1.0",
@@ -88,10 +88,18 @@ Structured output requests (those carrying a `jsonSchema`) persist three related
88
88
 
89
89
  - `json_schema`: the raw JSON Schema text of the request contract. Stored at `createRun`, exposed only through the server-side `responseTypeTs` conversion API (compact `type` declaration + reconstructed zod expression); the detail subset does not carry the raw text.
90
90
  - `is_structured`: boolean written at `createRun` from `json_schema` presence. Exists so the list subset can distinguish structured vs plain rows without shipping schema text; it is denormalized, so any future path that writes `json_schema` must set it too.
91
- - `response_json_ok`: tri-state verdict written at the succeeded `finishRun`. `true`/`false` = structured response parsed/failed `JSON.parse`; `null` = non-structured request, error/aborted run, or a row written before the column existed. The list filter `response_json_broken` matches only explicit `false`.
91
+ - `response_json_ok`: tri-state verdict written at the succeeded `finishRun`. `true`/`false` = structured response parsed/failed `JSON.parse`; `null` = non-structured request, error/aborted run, or a row written before the column existed. The list keeps the `broken` badge for explicit `false` but exposes no dedicated filter.
92
92
 
93
93
  Reconstructed zod output cannot contain `refine`/`transform` logic — those are lost when the client serializes the schema. Rows written by servers older than 2.7.2 have all three fields empty/false/null.
94
94
 
95
+ ## Tool definition fields
96
+
97
+ Requests carrying tools persist `tools` as `QgridTool[]` — `{ name, description?, inputSchema }`, exactly what the SDK's `toQgridTool` extracts. There is no per-tool output contract: the AI SDK provider boundary (`LanguageModelV3FunctionTool`) defines only `type`, `name`, `description?`, `inputSchema`, `inputExamples?`, and `strict?`. `tool()`'s `outputSchema` validates execution results client-side and never crosses into a provider call, so exposing it would require changing the SDK call site, the wire, and persistence together.
98
+
99
+ `inputSchema` is `z.unknown()` on the wire, so an absent key or a `null` value passes validation even though the SDK always fills `{}`. The `toolsView` projection normalizes each entry to an empty schema rather than trusting the shape — one unusable entry must not blank the whole request's tool contract.
100
+
101
+ `toolsView` is a display projection, not a second source of truth: it returns `name`, `description`, `parameterCount`, a display-only compact zod shape, and a full zod shape only when enum shortening actually changed the text. Validation constraints (`pattern`, `format`, `minLength`, `maximum`) are dropped on purpose — the detail screen answers what a tool accepts, not how input is validated. Actual call arguments stay in the step rows, so the projection covers tools that were attached but never called.
102
+
95
103
  ## Legacy normalization
96
104
 
97
105
  `RequestLogModel` normalizes legacy Anthropic rows where stored `input_tokens` may not include cache read/write. Rows with `cost_source = NULL` are legacy and can be repriced from the current table; rows with a source retain their exact stored cost across price/promotion changes.
@@ -56,7 +56,9 @@ Provider-qualified ids widen `model_name` and `requested_model_name` from 50 to
56
56
 
57
57
  Image-generation request logs add `is_image_generation`, `image_cost_usd`, and `image_cost_method`. The list view displays driver plus image cost as the total cost cell; the detail view shows driver cost and image cost separately and renders generated image data URLs from response/tool-step content.
58
58
 
59
- Structured output visibility: the list has an `Fmt` column (`json` badge from `is_structured` vs `text`), a `broken` badge plus a `Broken JSON` checkbox filter driven by `response_json_ok = false`, and the detail page shows a dark Response Type panel (zod expression by default, `type` declaration via toggle) rendered server-side from the stored `json_schema`. Plain-text rows render no panel. Rows written by pre-2.7.2 servers show `text` and never match the broken filter.
59
+ Structured output visibility: the list has an `Fmt` column (`json` badge from `is_structured` vs `text`) and a `broken` badge driven by `response_json_ok = false`; there is no broken-JSON list filter. At review time, all 114,647 succeeded structured rows had `response_json_ok = true` and zero false rows existed; the unindexed zero-result lookup scanned 1,286,016 rows and took about 3 seconds. Before reinstating the filter, validate the failure-signal semantics and index the predicate. The detail page shows a dark Response Type panel (zod expression by default, `type` declaration via toggle) rendered server-side from the stored `json_schema`. Plain-text rows render no panel. Rows written by pre-2.7.2 servers show `text`.
60
+
61
+ Tool contract visibility: the detail page renders a Tools panel between Response Type and Steps for requests whose `tools` is non-empty. It starts collapsed and its header shows the tool count plus a responsive, truncated name list built from the detail subset — collapsed views issue no extra query. Expanding fires `toolsView` once and caches it for that request id, since a stored tool contract never changes. Each card shows the name, the full description, the parameter count, and a compact display-only zod shape; enum values past the sixth collapse to `/* +N */`, with the full shape reachable through hover and keyboard focus. All JSON Schema conversion happens server-side — the web renders completed strings and holds no schema logic.
60
62
 
61
63
  The monit tab's vitals strip shows per-provider in-flight counts, an in-flight sparkline, token chips with quota gauges (fed by the dispatcher's 60-second rate-limits cache; `resetsAt` arrives as ms epoch), and a 1-hour per-provider request/error/cache-hit stats line polled separately every 30 seconds.
62
64