@vetala/vetala 0.1.0-beta

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.

Potentially problematic release.


This version of @vetala/vetala might be problematic. Click here for more details.

Files changed (271) hide show
  1. package/CONTRIBUTING.md +77 -0
  2. package/LICENSE +184 -0
  3. package/README.md +136 -0
  4. package/THIRD_PARTY_LICENSES.md +17 -0
  5. package/dist/src/agent.d.ts +30 -0
  6. package/dist/src/agent.js +216 -0
  7. package/dist/src/agent.js.map +1 -0
  8. package/dist/src/approvals.d.ts +18 -0
  9. package/dist/src/approvals.js +81 -0
  10. package/dist/src/approvals.js.map +1 -0
  11. package/dist/src/cli.d.ts +2 -0
  12. package/dist/src/cli.js +87 -0
  13. package/dist/src/cli.js.map +1 -0
  14. package/dist/src/config.d.ts +12 -0
  15. package/dist/src/config.js +183 -0
  16. package/dist/src/config.js.map +1 -0
  17. package/dist/src/context-memory.d.ts +7 -0
  18. package/dist/src/context-memory.js +96 -0
  19. package/dist/src/context-memory.js.map +1 -0
  20. package/dist/src/ink/command-suggestions.d.ts +7 -0
  21. package/dist/src/ink/command-suggestions.js +179 -0
  22. package/dist/src/ink/command-suggestions.js.map +1 -0
  23. package/dist/src/ink/ink-terminal-ui.d.ts +36 -0
  24. package/dist/src/ink/ink-terminal-ui.js +79 -0
  25. package/dist/src/ink/ink-terminal-ui.js.map +1 -0
  26. package/dist/src/ink/repl-app.d.ts +9 -0
  27. package/dist/src/ink/repl-app.js +789 -0
  28. package/dist/src/ink/repl-app.js.map +1 -0
  29. package/dist/src/ink/transcript-cards.d.ts +6 -0
  30. package/dist/src/ink/transcript-cards.js +24 -0
  31. package/dist/src/ink/transcript-cards.js.map +1 -0
  32. package/dist/src/path-policy.d.ts +11 -0
  33. package/dist/src/path-policy.js +67 -0
  34. package/dist/src/path-policy.js.map +1 -0
  35. package/dist/src/process-utils.d.ts +13 -0
  36. package/dist/src/process-utils.js +52 -0
  37. package/dist/src/process-utils.js.map +1 -0
  38. package/dist/src/repl.d.ts +9 -0
  39. package/dist/src/repl.js +13 -0
  40. package/dist/src/repl.js.map +1 -0
  41. package/dist/src/sarvam/client.d.ts +15 -0
  42. package/dist/src/sarvam/client.js +208 -0
  43. package/dist/src/sarvam/client.js.map +1 -0
  44. package/dist/src/sarvam/models.d.ts +2 -0
  45. package/dist/src/sarvam/models.js +7 -0
  46. package/dist/src/sarvam/models.js.map +1 -0
  47. package/dist/src/search-provider.d.ts +6 -0
  48. package/dist/src/search-provider.js +8 -0
  49. package/dist/src/search-provider.js.map +1 -0
  50. package/dist/src/session-store.d.ts +19 -0
  51. package/dist/src/session-store.js +318 -0
  52. package/dist/src/session-store.js.map +1 -0
  53. package/dist/src/skills/runtime.d.ts +26 -0
  54. package/dist/src/skills/runtime.js +317 -0
  55. package/dist/src/skills/runtime.js.map +1 -0
  56. package/dist/src/skills/types.d.ts +25 -0
  57. package/dist/src/skills/types.js +2 -0
  58. package/dist/src/skills/types.js.map +1 -0
  59. package/dist/src/terminal-ui.d.ts +29 -0
  60. package/dist/src/terminal-ui.js +236 -0
  61. package/dist/src/terminal-ui.js.map +1 -0
  62. package/dist/src/tools/filesystem.d.ts +2 -0
  63. package/dist/src/tools/filesystem.js +622 -0
  64. package/dist/src/tools/filesystem.js.map +1 -0
  65. package/dist/src/tools/git.d.ts +2 -0
  66. package/dist/src/tools/git.js +326 -0
  67. package/dist/src/tools/git.js.map +1 -0
  68. package/dist/src/tools/index.d.ts +6 -0
  69. package/dist/src/tools/index.js +21 -0
  70. package/dist/src/tools/index.js.map +1 -0
  71. package/dist/src/tools/registry.d.ts +15 -0
  72. package/dist/src/tools/registry.js +59 -0
  73. package/dist/src/tools/registry.js.map +1 -0
  74. package/dist/src/tools/shell.d.ts +2 -0
  75. package/dist/src/tools/shell.js +97 -0
  76. package/dist/src/tools/shell.js.map +1 -0
  77. package/dist/src/tools/skill.d.ts +3 -0
  78. package/dist/src/tools/skill.js +130 -0
  79. package/dist/src/tools/skill.js.map +1 -0
  80. package/dist/src/tools/web.d.ts +3 -0
  81. package/dist/src/tools/web.js +144 -0
  82. package/dist/src/tools/web.js.map +1 -0
  83. package/dist/src/types.d.ts +236 -0
  84. package/dist/src/types.js +2 -0
  85. package/dist/src/types.js.map +1 -0
  86. package/dist/src/workspace-trust.d.ts +3 -0
  87. package/dist/src/workspace-trust.js +31 -0
  88. package/dist/src/workspace-trust.js.map +1 -0
  89. package/dist/src/xdg.d.ts +9 -0
  90. package/dist/src/xdg.js +77 -0
  91. package/dist/src/xdg.js.map +1 -0
  92. package/package.json +57 -0
  93. package/skill/agents-md-generator/SKILL.md +75 -0
  94. package/skill/agents-md-generator/references/agents_md_template.md +160 -0
  95. package/skill/agents-md-generator/references/loc_measurement.md +67 -0
  96. package/skill/agents-md-generator/references/monorepo_detection.md +78 -0
  97. package/skill/agents-md-generator/references/monorepo_strategy.md +60 -0
  98. package/skill/agents-md-generator/references/read_only_commands.md +151 -0
  99. package/skill/agents-md-generator/references/update_strategy.md +160 -0
  100. package/skill/agents-md-generator/references/working_agreements.md +53 -0
  101. package/skill/biz-opportunity-scout/SKILL.md +53 -0
  102. package/skill/biz-opportunity-scout/references/competitive_analysis.md +84 -0
  103. package/skill/biz-opportunity-scout/references/market_sizing.md +68 -0
  104. package/skill/biz-opportunity-scout/references/pmf_indicators.md +94 -0
  105. package/skill/biz-opportunity-scout/references/report_template.md +243 -0
  106. package/skill/biz-opportunity-scout/references/unit_economics.md +97 -0
  107. package/skill/code-review/SKILL.md +86 -0
  108. package/skill/code-review/references/change_analysis.md +116 -0
  109. package/skill/code-review/references/git_operations.md +115 -0
  110. package/skill/code-review/references/impact_detection.md +149 -0
  111. package/skill/code-review/references/output_format.md +137 -0
  112. package/skill/code-review/references/severity_criteria.md +100 -0
  113. package/skill/code-security-audit/SKILL.md +123 -0
  114. package/skill/code-security-audit/references/audit_process.md +277 -0
  115. package/skill/code-security-audit/references/remediation_patterns.md +599 -0
  116. package/skill/code-security-audit/references/report_format.md +391 -0
  117. package/skill/code-security-audit/references/security_domains.md +830 -0
  118. package/skill/code-security-audit/references/vulnerability_patterns.md +813 -0
  119. package/skill/composition-patterns/SKILL.md +83 -0
  120. package/skill/composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
  121. package/skill/composition-patterns/rules/architecture-compound-components.md +112 -0
  122. package/skill/composition-patterns/rules/patterns-children-over-render-props.md +87 -0
  123. package/skill/composition-patterns/rules/patterns-explicit-variants.md +100 -0
  124. package/skill/composition-patterns/rules/react19-no-forwardref.md +42 -0
  125. package/skill/composition-patterns/rules/state-context-interface.md +191 -0
  126. package/skill/composition-patterns/rules/state-decouple-implementation.md +113 -0
  127. package/skill/composition-patterns/rules/state-lift-state.md +125 -0
  128. package/skill/deploy-to-vercel/SKILL.md +293 -0
  129. package/skill/deploy-to-vercel/resources/deploy-sandbox.sh +301 -0
  130. package/skill/deploy-to-vercel/resources/deploy.sh +301 -0
  131. package/skill/doc/SKILL_GUIDELINES.md +138 -0
  132. package/skill/git-workflow/SKILL.md +94 -0
  133. package/skill/git-workflow/references/advanced-git.md +632 -0
  134. package/skill/git-workflow/references/branching-strategies.md +344 -0
  135. package/skill/git-workflow/references/ci-cd-integration.md +683 -0
  136. package/skill/git-workflow/references/code-quality-tools.md +351 -0
  137. package/skill/git-workflow/references/commit-conventions.md +439 -0
  138. package/skill/git-workflow/references/github-releases.md +288 -0
  139. package/skill/git-workflow/references/pull-request-workflow.md +773 -0
  140. package/skill/git-workflow/scripts/verify-git-workflow.sh +263 -0
  141. package/skill/jetbrains-vmoptions/SKILL.md +51 -0
  142. package/skill/jetbrains-vmoptions/references/common-options.md +357 -0
  143. package/skill/jetbrains-vmoptions/references/gc-options.md +350 -0
  144. package/skill/jetbrains-vmoptions/references/memory-options.md +339 -0
  145. package/skill/jetbrains-vmoptions/references/prerequisite-check.md +65 -0
  146. package/skill/kysely-converter/SKILL.md +62 -0
  147. package/skill/kysely-converter/references/delete.md +323 -0
  148. package/skill/kysely-converter/references/insert.md +386 -0
  149. package/skill/kysely-converter/references/operators.md +331 -0
  150. package/skill/kysely-converter/references/select.md +1000 -0
  151. package/skill/kysely-converter/references/update.md +349 -0
  152. package/skill/kysely-converter/references/window_function.md +537 -0
  153. package/skill/react-best-practices/SKILL.md +131 -0
  154. package/skill/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  155. package/skill/react-best-practices/rules/advanced-init-once.md +42 -0
  156. package/skill/react-best-practices/rules/advanced-use-latest.md +39 -0
  157. package/skill/react-best-practices/rules/async-api-routes.md +38 -0
  158. package/skill/react-best-practices/rules/async-defer-await.md +80 -0
  159. package/skill/react-best-practices/rules/async-dependencies.md +51 -0
  160. package/skill/react-best-practices/rules/async-parallel.md +28 -0
  161. package/skill/react-best-practices/rules/async-suspense-boundaries.md +99 -0
  162. package/skill/react-best-practices/rules/bundle-barrel-imports.md +59 -0
  163. package/skill/react-best-practices/rules/bundle-conditional.md +31 -0
  164. package/skill/react-best-practices/rules/bundle-defer-third-party.md +49 -0
  165. package/skill/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  166. package/skill/react-best-practices/rules/bundle-preload.md +50 -0
  167. package/skill/react-best-practices/rules/client-event-listeners.md +74 -0
  168. package/skill/react-best-practices/rules/client-localstorage-schema.md +71 -0
  169. package/skill/react-best-practices/rules/client-passive-event-listeners.md +48 -0
  170. package/skill/react-best-practices/rules/client-swr-dedup.md +56 -0
  171. package/skill/react-best-practices/rules/js-batch-dom-css.md +107 -0
  172. package/skill/react-best-practices/rules/js-cache-function-results.md +80 -0
  173. package/skill/react-best-practices/rules/js-cache-property-access.md +28 -0
  174. package/skill/react-best-practices/rules/js-cache-storage.md +70 -0
  175. package/skill/react-best-practices/rules/js-combine-iterations.md +32 -0
  176. package/skill/react-best-practices/rules/js-early-exit.md +50 -0
  177. package/skill/react-best-practices/rules/js-hoist-regexp.md +45 -0
  178. package/skill/react-best-practices/rules/js-index-maps.md +37 -0
  179. package/skill/react-best-practices/rules/js-length-check-first.md +49 -0
  180. package/skill/react-best-practices/rules/js-min-max-loop.md +82 -0
  181. package/skill/react-best-practices/rules/js-set-map-lookups.md +24 -0
  182. package/skill/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  183. package/skill/react-best-practices/rules/rendering-activity.md +26 -0
  184. package/skill/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  185. package/skill/react-best-practices/rules/rendering-conditional-render.md +40 -0
  186. package/skill/react-best-practices/rules/rendering-content-visibility.md +38 -0
  187. package/skill/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  188. package/skill/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  189. package/skill/react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
  190. package/skill/react-best-practices/rules/rendering-svg-precision.md +28 -0
  191. package/skill/react-best-practices/rules/rendering-usetransition-loading.md +75 -0
  192. package/skill/react-best-practices/rules/rerender-defer-reads.md +39 -0
  193. package/skill/react-best-practices/rules/rerender-dependencies.md +45 -0
  194. package/skill/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  195. package/skill/react-best-practices/rules/rerender-derived-state.md +29 -0
  196. package/skill/react-best-practices/rules/rerender-functional-setstate.md +74 -0
  197. package/skill/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  198. package/skill/react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
  199. package/skill/react-best-practices/rules/rerender-memo.md +44 -0
  200. package/skill/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  201. package/skill/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  202. package/skill/react-best-practices/rules/rerender-transitions.md +40 -0
  203. package/skill/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  204. package/skill/react-best-practices/rules/server-after-nonblocking.md +73 -0
  205. package/skill/react-best-practices/rules/server-auth-actions.md +96 -0
  206. package/skill/react-best-practices/rules/server-cache-lru.md +41 -0
  207. package/skill/react-best-practices/rules/server-cache-react.md +76 -0
  208. package/skill/react-best-practices/rules/server-dedup-props.md +65 -0
  209. package/skill/react-best-practices/rules/server-hoist-static-io.md +142 -0
  210. package/skill/react-best-practices/rules/server-parallel-fetching.md +83 -0
  211. package/skill/react-best-practices/rules/server-serialization.md +38 -0
  212. package/skill/react-native-skills/SKILL.md +115 -0
  213. package/skill/react-native-skills/rules/animation-derived-value.md +53 -0
  214. package/skill/react-native-skills/rules/animation-gesture-detector-press.md +95 -0
  215. package/skill/react-native-skills/rules/animation-gpu-properties.md +65 -0
  216. package/skill/react-native-skills/rules/design-system-compound-components.md +66 -0
  217. package/skill/react-native-skills/rules/fonts-config-plugin.md +71 -0
  218. package/skill/react-native-skills/rules/imports-design-system-folder.md +68 -0
  219. package/skill/react-native-skills/rules/js-hoist-intl.md +61 -0
  220. package/skill/react-native-skills/rules/list-performance-callbacks.md +44 -0
  221. package/skill/react-native-skills/rules/list-performance-function-references.md +132 -0
  222. package/skill/react-native-skills/rules/list-performance-images.md +53 -0
  223. package/skill/react-native-skills/rules/list-performance-inline-objects.md +97 -0
  224. package/skill/react-native-skills/rules/list-performance-item-expensive.md +94 -0
  225. package/skill/react-native-skills/rules/list-performance-item-memo.md +82 -0
  226. package/skill/react-native-skills/rules/list-performance-item-types.md +104 -0
  227. package/skill/react-native-skills/rules/list-performance-virtualize.md +67 -0
  228. package/skill/react-native-skills/rules/monorepo-native-deps-in-app.md +46 -0
  229. package/skill/react-native-skills/rules/monorepo-single-dependency-versions.md +63 -0
  230. package/skill/react-native-skills/rules/navigation-native-navigators.md +188 -0
  231. package/skill/react-native-skills/rules/react-compiler-destructure-functions.md +50 -0
  232. package/skill/react-native-skills/rules/react-compiler-reanimated-shared-values.md +48 -0
  233. package/skill/react-native-skills/rules/react-state-dispatcher.md +91 -0
  234. package/skill/react-native-skills/rules/react-state-fallback.md +56 -0
  235. package/skill/react-native-skills/rules/react-state-minimize.md +65 -0
  236. package/skill/react-native-skills/rules/rendering-no-falsy-and.md +74 -0
  237. package/skill/react-native-skills/rules/rendering-text-in-text-component.md +36 -0
  238. package/skill/react-native-skills/rules/scroll-position-no-state.md +82 -0
  239. package/skill/react-native-skills/rules/state-ground-truth.md +80 -0
  240. package/skill/react-native-skills/rules/ui-expo-image.md +66 -0
  241. package/skill/react-native-skills/rules/ui-image-gallery.md +104 -0
  242. package/skill/react-native-skills/rules/ui-measure-views.md +78 -0
  243. package/skill/react-native-skills/rules/ui-menus.md +174 -0
  244. package/skill/react-native-skills/rules/ui-native-modals.md +77 -0
  245. package/skill/react-native-skills/rules/ui-pressable.md +61 -0
  246. package/skill/react-native-skills/rules/ui-safe-area-scroll.md +65 -0
  247. package/skill/react-native-skills/rules/ui-scrollview-content-inset.md +45 -0
  248. package/skill/react-native-skills/rules/ui-styling.md +87 -0
  249. package/skill/react-vite-guide/SKILL.md +101 -0
  250. package/skill/react-vite-guide/references/composition-patterns.md +709 -0
  251. package/skill/react-vite-guide/references/performance-optimization.md +1222 -0
  252. package/skill/react-vite-guide/references/vite-specific.md +385 -0
  253. package/skill/react-vite-guide/references/web-interface.md +146 -0
  254. package/skill/skill-maker/SKILL.md +52 -0
  255. package/skill/skill-maker/references/content_spec.md +67 -0
  256. package/skill/skill-maker/references/frontmatter_spec.md +96 -0
  257. package/skill/skill-maker/references/input_validation.md +90 -0
  258. package/skill/skill-maker/references/skill_structure.md +74 -0
  259. package/skill/system-prompt-creator/SKILL.md +50 -0
  260. package/skill/system-prompt-creator/references/data_format_selection.md +135 -0
  261. package/skill/system-prompt-creator/references/multi_prompt_architecture.md +386 -0
  262. package/skill/system-prompt-creator/references/prompt_structure.md +140 -0
  263. package/skill/system-prompt-creator/references/quality_criteria.md +83 -0
  264. package/skill/typst-creator/SKILL.md +51 -0
  265. package/skill/typst-creator/references/layout.md +401 -0
  266. package/skill/typst-creator/references/math.md +297 -0
  267. package/skill/typst-creator/references/scripting.md +237 -0
  268. package/skill/typst-creator/references/styling.md +217 -0
  269. package/skill/typst-creator/references/syntax.md +234 -0
  270. package/skill/web-design-guidelines/SKILL.md +35 -0
  271. package/terminal.png +0 -0
@@ -0,0 +1,789 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { Box, Text, useApp, useInput } from "ink";
4
+ import SelectInput from "ink-select-input";
5
+ import Spinner from "ink-spinner";
6
+ import TextInput from "ink-text-input";
7
+ import { Agent } from "../agent.js";
8
+ import { ApprovalManager } from "../approvals.js";
9
+ import { clearSavedAuth, loadConfig, saveChatDefaults, savePersistentAuth, withSessionAuth, withStoredAuth } from "../config.js";
10
+ import { PathPolicy } from "../path-policy.js";
11
+ import { SARVAM_MODELS } from "../sarvam/models.js";
12
+ import { SkillRuntime } from "../skills/runtime.js";
13
+ import { createToolRegistry } from "../tools/index.js";
14
+ import { InkTerminalUI } from "./ink-terminal-ui.js";
15
+ import { buildSlashSuggestions } from "./command-suggestions.js";
16
+ import { buildTranscriptCards } from "./transcript-cards.js";
17
+ export function ReplApp({ initialConfig, initialSession, store }) {
18
+ const { exit } = useApp();
19
+ const [config, setConfig] = useState(initialConfig);
20
+ const [session, setSession] = useState(() => cloneSession(initialSession));
21
+ const [trusted, setTrusted] = useState(false);
22
+ const [input, setInput] = useState("");
23
+ const [entries, setEntries] = useState([]);
24
+ const [assistantBuffer, setAssistantBuffer] = useState("");
25
+ const [activityLabel, setActivityLabel] = useState(null);
26
+ const [spinnerLabel, setSpinnerLabel] = useState(null);
27
+ const [status, setStatus] = useState("Ready");
28
+ const [pendingApproval, setPendingApproval] = useState(null);
29
+ const [modelPickerOpen, setModelPickerOpen] = useState(false);
30
+ const [pendingReasoningSetup, setPendingReasoningSetup] = useState(null);
31
+ const [pendingAuthInput, setPendingAuthInput] = useState(null);
32
+ const [pendingAuthRetention, setPendingAuthRetention] = useState(null);
33
+ const [availableSkills, setAvailableSkills] = useState([]);
34
+ const [paused, setPaused] = useState(false);
35
+ const [pendingExitConfirm, setPendingExitConfirm] = useState(false);
36
+ const assistantBufferRef = useRef("");
37
+ const nextEntryIdRef = useRef(0);
38
+ const sessionRef = useRef(session);
39
+ const uiRef = useRef(null);
40
+ const skillRuntimeRef = useRef(null);
41
+ sessionRef.current = session;
42
+ const pushEntry = (kind, text) => {
43
+ setEntries((current) => [
44
+ ...current,
45
+ {
46
+ id: String(nextEntryIdRef.current++),
47
+ kind,
48
+ text
49
+ }
50
+ ]);
51
+ };
52
+ const finalizeAssistant = () => {
53
+ const buffered = assistantBufferRef.current.trimEnd();
54
+ if (!buffered) {
55
+ assistantBufferRef.current = "";
56
+ setAssistantBuffer("");
57
+ return;
58
+ }
59
+ assistantBufferRef.current = "";
60
+ setAssistantBuffer("");
61
+ pushEntry("assistant", buffered);
62
+ };
63
+ if (!uiRef.current) {
64
+ uiRef.current = new InkTerminalUI({
65
+ appendAssistant: (text) => {
66
+ assistantBufferRef.current += text;
67
+ setAssistantBuffer(assistantBufferRef.current);
68
+ },
69
+ finalizeAssistant,
70
+ pushEntry,
71
+ setActivity: (label) => {
72
+ setActivityLabel(label);
73
+ },
74
+ setSpinner: (label) => {
75
+ setSpinnerLabel(label);
76
+ setStatus(label ?? "Ready");
77
+ }
78
+ });
79
+ }
80
+ const ui = uiRef.current;
81
+ if (!skillRuntimeRef.current) {
82
+ skillRuntimeRef.current = new SkillRuntime({
83
+ getSession: () => sessionRef.current,
84
+ sessionStore: store
85
+ });
86
+ }
87
+ const skills = skillRuntimeRef.current;
88
+ const busy = spinnerLabel !== null;
89
+ const transcriptCards = buildTranscriptCards(entries).slice(-8);
90
+ const liveCardId = transcriptCards.at(-1)?.id ?? null;
91
+ const visibleStatus = paused ? "Paused" : status;
92
+ const slashSuggestions = buildSlashSuggestions(input, availableSkills).slice(0, 8);
93
+ const showSlashSuggestions = Boolean(trusted &&
94
+ !busy &&
95
+ !paused &&
96
+ !pendingExitConfirm &&
97
+ !pendingApproval &&
98
+ !modelPickerOpen &&
99
+ !pendingReasoningSetup &&
100
+ !pendingAuthInput &&
101
+ !pendingAuthRetention &&
102
+ input.startsWith("/") &&
103
+ slashSuggestions.length > 0);
104
+ const createTools = () => createToolRegistry({
105
+ includeWebSearch: config.searchProviderName !== "disabled",
106
+ skillRuntime: skills
107
+ });
108
+ useEffect(() => {
109
+ let cancelled = false;
110
+ void skills
111
+ .listSkills()
112
+ .then((listed) => {
113
+ if (!cancelled) {
114
+ setAvailableSkills(listed);
115
+ }
116
+ })
117
+ .catch(() => {
118
+ if (!cancelled) {
119
+ setAvailableSkills([]);
120
+ }
121
+ });
122
+ return () => {
123
+ cancelled = true;
124
+ };
125
+ }, [skills]);
126
+ useInput((inputValue, key) => {
127
+ if (showSlashSuggestions && isTabInput(inputValue, key)) {
128
+ const firstSuggestion = slashSuggestions[0];
129
+ if (firstSuggestion) {
130
+ setInput(firstSuggestion.completion);
131
+ }
132
+ return;
133
+ }
134
+ if (isControlInput(inputValue, key, "d", "\u0004")) {
135
+ setPendingExitConfirm(true);
136
+ return;
137
+ }
138
+ if (!trusted) {
139
+ return;
140
+ }
141
+ if (isControlInput(inputValue, key, "c", "\u0003")) {
142
+ setPendingExitConfirm(false);
143
+ setPaused((current) => !current);
144
+ return;
145
+ }
146
+ });
147
+ const requestApprovalDecision = (request) => new Promise((resolve) => {
148
+ setActivityLabel("Waiting for approval.");
149
+ setPendingApproval({ request, resolve });
150
+ });
151
+ const syncSession = (nextSession) => {
152
+ const cloned = cloneSession(nextSession);
153
+ setSession(cloned);
154
+ return cloned;
155
+ };
156
+ const resetTranscript = () => {
157
+ assistantBufferRef.current = "";
158
+ setAssistantBuffer("");
159
+ setActivityLabel(null);
160
+ nextEntryIdRef.current = 0;
161
+ setEntries([]);
162
+ };
163
+ const mergeLoadedConfig = (loaded) => {
164
+ if (config.authSource === "session" && config.authValue) {
165
+ return {
166
+ ...loaded,
167
+ authMode: config.authMode,
168
+ authValue: config.authValue,
169
+ authFingerprint: config.authFingerprint,
170
+ authSource: "session"
171
+ };
172
+ }
173
+ return loaded;
174
+ };
175
+ const closeCommandModals = () => {
176
+ setModelPickerOpen(false);
177
+ setPendingReasoningSetup(null);
178
+ setPendingAuthInput(null);
179
+ setPendingAuthRetention(null);
180
+ };
181
+ const runPrompt = async (prompt) => {
182
+ const trimmed = prompt.trim();
183
+ if (!trimmed) {
184
+ return;
185
+ }
186
+ if (trimmed.startsWith("/")) {
187
+ await handleCommand(trimmed);
188
+ return;
189
+ }
190
+ setInput("");
191
+ setPendingExitConfirm(false);
192
+ setActivityLabel(null);
193
+ pushEntry("user", summarizeUserPrompt(trimmed));
194
+ setStatus("Running agent");
195
+ const approvals = new ApprovalManager(session, store, null, requestApprovalDecision);
196
+ const agent = new Agent({
197
+ config,
198
+ session,
199
+ sessionStore: store,
200
+ approvals,
201
+ pathPolicy: new PathPolicy(session.workspaceRoot, approvals),
202
+ skills,
203
+ tools: createTools(),
204
+ ui
205
+ });
206
+ try {
207
+ await agent.runTurn(trimmed, true);
208
+ syncSession(session);
209
+ setActivityLabel(null);
210
+ setStatus("Ready");
211
+ }
212
+ catch (error) {
213
+ finalizeAssistant();
214
+ setActivityLabel(null);
215
+ pushEntry("error", error instanceof Error ? error.message : String(error));
216
+ setStatus("Failed");
217
+ syncSession(session);
218
+ }
219
+ };
220
+ const handleCommand = async (commandLine) => {
221
+ const [command, ...args] = commandLine.slice(1).split(/\s+/);
222
+ setInput("");
223
+ setActivityLabel(null);
224
+ pushEntry("user", commandLine);
225
+ switch (command) {
226
+ case "help":
227
+ pushEntry("info", [
228
+ "/help",
229
+ "/model",
230
+ "/skill",
231
+ "/tools",
232
+ "/history",
233
+ "/resume <session-id>",
234
+ "/new",
235
+ "/approve",
236
+ "/config",
237
+ "/logout",
238
+ "/clear",
239
+ "/exit"
240
+ ].join("\n"));
241
+ return;
242
+ case "model":
243
+ if (args.length > 0) {
244
+ pushEntry("warn", "/model is interactive now. Use /model and select from the list.");
245
+ }
246
+ closeCommandModals();
247
+ setModelPickerOpen(true);
248
+ setStatus("Select a model");
249
+ return;
250
+ case "skill":
251
+ case "skills":
252
+ await handleSkillsCommand(args);
253
+ return;
254
+ case "tools":
255
+ pushEntry("info", createTools()
256
+ .list()
257
+ .map((tool) => `${tool.readOnly ? "ro" : "rw"} ${tool.name} - ${tool.description}`)
258
+ .join("\n"));
259
+ return;
260
+ case "history":
261
+ pushEntry("info", session.messages
262
+ .slice(-20)
263
+ .map((message) => {
264
+ const label = message.role.padEnd(9, " ");
265
+ const content = (message.content ?? "[tool call]").replace(/\s+/g, " ").slice(0, 140);
266
+ return `${label} ${content}`;
267
+ })
268
+ .join("\n") || "(empty session)");
269
+ return;
270
+ case "resume": {
271
+ const target = args[0];
272
+ if (!target) {
273
+ const sessions = await store.listSessions();
274
+ pushEntry("info", formatSessionList(sessions));
275
+ return;
276
+ }
277
+ const nextSession = await store.loadSession(target);
278
+ const nextCloned = syncSession(nextSession);
279
+ closeCommandModals();
280
+ resetTranscript();
281
+ setStatus(`Resumed ${nextCloned.id.slice(0, 8)}`);
282
+ return;
283
+ }
284
+ case "new": {
285
+ const nextSession = await store.createSession(session.workspaceRoot, session.model);
286
+ const nextCloned = syncSession(nextSession);
287
+ closeCommandModals();
288
+ resetTranscript();
289
+ setStatus(`Created ${nextCloned.id.slice(0, 8)}`);
290
+ return;
291
+ }
292
+ case "approve":
293
+ pushEntry("info", [
294
+ `web access: ${session.approvals.webAccess ? "granted" : "not granted"}`,
295
+ `path grants: ${session.approvals.outOfTreeRoots.join(", ") || "(none)"}`,
296
+ `session grants: ${session.approvals.sessionActionKeys.join(", ") || "(none)"}`
297
+ ].join("\n"));
298
+ return;
299
+ case "config":
300
+ ui.printConfig(config);
301
+ return;
302
+ case "logout": {
303
+ const previousAuthSource = config.authSource;
304
+ await clearSavedAuth();
305
+ closeCommandModals();
306
+ const reloaded = await loadConfig();
307
+ setConfig(reloaded);
308
+ if (reloaded.authSource === "env") {
309
+ pushEntry("warn", "Cleared local auth state, but environment credentials are still active for this process.");
310
+ }
311
+ else if (previousAuthSource === "stored" || previousAuthSource === "stored_hash") {
312
+ pushEntry("info", "Cleared the saved API key for future launches and removed current local auth.");
313
+ }
314
+ else if (previousAuthSource === "session") {
315
+ pushEntry("info", "Cleared the API key that was only active in this session.");
316
+ }
317
+ else {
318
+ pushEntry("info", "No saved API key remained after logout.");
319
+ }
320
+ setStatus("Logged out");
321
+ return;
322
+ }
323
+ case "clear":
324
+ closeCommandModals();
325
+ resetTranscript();
326
+ setStatus("Ready");
327
+ return;
328
+ case "exit":
329
+ setPendingExitConfirm(true);
330
+ return;
331
+ default:
332
+ pushEntry("warn", `Unknown command: /${command}`);
333
+ }
334
+ };
335
+ const handleSkillsCommand = async (args) => {
336
+ try {
337
+ const [subcommand, ...rest] = args;
338
+ if (!subcommand) {
339
+ const available = await skills.listSkills();
340
+ const pinned = new Set((await skills.pinnedSkills()).map((skill) => skill.name));
341
+ pushEntry("info", available.length > 0
342
+ ? available
343
+ .map((skill) => `${pinned.has(skill.name) ? "*" : "-"} ${skill.name} - ${skill.description || "(no description)"}`)
344
+ .join("\n")
345
+ : "(no skills available)");
346
+ return;
347
+ }
348
+ switch (subcommand) {
349
+ case "use":
350
+ case "pin": {
351
+ const name = rest[0];
352
+ if (!name) {
353
+ pushEntry("warn", "Usage: /skill use <name>");
354
+ return;
355
+ }
356
+ const skill = await skills.pinSkill(name);
357
+ syncSession(session);
358
+ pushEntry("info", `Pinned skill: ${skill.name}`);
359
+ return;
360
+ }
361
+ case "drop":
362
+ case "unpin": {
363
+ const name = rest[0];
364
+ if (!name) {
365
+ pushEntry("warn", "Usage: /skill drop <name>");
366
+ return;
367
+ }
368
+ const skill = await skills.unpinSkill(name);
369
+ syncSession(session);
370
+ pushEntry("info", `Unpinned skill: ${skill.name}`);
371
+ return;
372
+ }
373
+ case "clear": {
374
+ const cleared = await skills.clearPinnedSkills();
375
+ syncSession(session);
376
+ pushEntry("info", cleared > 0 ? `Cleared ${cleared} pinned skills.` : "No pinned skills were active.");
377
+ return;
378
+ }
379
+ case "show":
380
+ case "load": {
381
+ const name = rest[0];
382
+ if (!name) {
383
+ pushEntry("warn", "Usage: /skill show <name>");
384
+ return;
385
+ }
386
+ const skill = await skills.loadSkill(name);
387
+ pushEntry("info", skill.overview);
388
+ return;
389
+ }
390
+ case "read": {
391
+ const [name, ...pathParts] = rest;
392
+ if (!name) {
393
+ pushEntry("warn", "Usage: /skill read <name> [path]");
394
+ return;
395
+ }
396
+ const pathArg = pathParts.join(" ") || "SKILL.md";
397
+ const file = await skills.readSkillFile(name, pathArg);
398
+ pushEntry("info", file.content);
399
+ return;
400
+ }
401
+ default:
402
+ pushEntry("warn", "Usage: /skill [use|drop|clear|show|read]");
403
+ }
404
+ }
405
+ catch (error) {
406
+ pushEntry("error", error instanceof Error ? error.message : String(error));
407
+ }
408
+ };
409
+ const onTrustSelect = async (value) => {
410
+ if (value === "exit") {
411
+ exit();
412
+ return;
413
+ }
414
+ setTrusted(true);
415
+ setStatus("Ready");
416
+ };
417
+ const onApprovalSelect = async (value) => {
418
+ const promptState = pendingApproval;
419
+ if (!promptState) {
420
+ return;
421
+ }
422
+ setActivityLabel(null);
423
+ setPendingApproval(null);
424
+ promptState.resolve(value);
425
+ };
426
+ const onModelSelect = async (value) => {
427
+ if (value === "cancel") {
428
+ setModelPickerOpen(false);
429
+ setStatus("Ready");
430
+ return;
431
+ }
432
+ setModelPickerOpen(false);
433
+ setPendingReasoningSetup({
434
+ model: value,
435
+ reasoningEffort: config.reasoningEffort
436
+ });
437
+ setStatus(`Select reasoning effort for ${value}`);
438
+ };
439
+ const onReasoningSelect = async (value) => {
440
+ const current = pendingReasoningSetup;
441
+ if (!current) {
442
+ return;
443
+ }
444
+ if (value === "cancel") {
445
+ setPendingReasoningSetup(null);
446
+ setStatus("Ready");
447
+ return;
448
+ }
449
+ setPendingReasoningSetup(null);
450
+ const nextSettings = {
451
+ ...current,
452
+ reasoningEffort: value === "none" ? null : value
453
+ };
454
+ await store.updateModel(session, nextSettings.model);
455
+ await saveChatDefaults(nextSettings.model, nextSettings.reasoningEffort);
456
+ syncSession(session);
457
+ const loadedConfig = await loadConfig();
458
+ const nextConfig = mergeLoadedConfig(loadedConfig);
459
+ setConfig(nextConfig);
460
+ if (nextConfig.authSource === "missing" || nextConfig.authSource === "stored_hash") {
461
+ setPendingAuthInput({
462
+ ...nextSettings,
463
+ authMode: "subscription_key",
464
+ value: ""
465
+ });
466
+ setStatus(`Enter API key for ${nextSettings.model}`);
467
+ return;
468
+ }
469
+ pushEntry("info", formatModelSetupSummary(nextSettings, nextConfig));
470
+ setStatus("Ready");
471
+ };
472
+ const onAuthInputChange = (value) => {
473
+ setPendingAuthInput((current) => (current ? { ...current, value } : current));
474
+ };
475
+ const onAuthInputSubmit = async (value) => {
476
+ const current = pendingAuthInput;
477
+ if (!current) {
478
+ return;
479
+ }
480
+ const trimmed = value.trim();
481
+ if (!trimmed) {
482
+ setPendingAuthInput(null);
483
+ pushEntry("warn", "API key entry cancelled. Model settings were saved, but no usable Sarvam credential is active.");
484
+ setStatus("Ready");
485
+ return;
486
+ }
487
+ setPendingAuthInput(null);
488
+ setPendingAuthRetention({
489
+ ...current,
490
+ value: trimmed
491
+ });
492
+ setStatus("Choose how long to keep this API key");
493
+ };
494
+ const onAuthRetentionSelect = async (choice) => {
495
+ const current = pendingAuthRetention;
496
+ if (!current) {
497
+ return;
498
+ }
499
+ if (choice === "cancel") {
500
+ setPendingAuthRetention(null);
501
+ pushEntry("warn", "API key setup cancelled.");
502
+ setStatus("Ready");
503
+ return;
504
+ }
505
+ const loadedConfig = await loadConfig();
506
+ const nextConfig = choice === "persist"
507
+ ? withStoredAuth(loadedConfig, current.authMode, current.value)
508
+ : withSessionAuth(loadedConfig, current.authMode, current.value);
509
+ if (choice === "persist") {
510
+ await savePersistentAuth(current.authMode, current.value);
511
+ }
512
+ setConfig(nextConfig);
513
+ setPendingAuthRetention(null);
514
+ pushEntry("info", formatModelSetupSummary(current, nextConfig, choice));
515
+ if (choice === "persist" && loadedConfig.authSource === "env") {
516
+ pushEntry("warn", "Environment credentials are still set in this shell. They may take precedence on future launches.");
517
+ }
518
+ setStatus("Ready");
519
+ };
520
+ const onExitConfirmSelect = async (value) => {
521
+ if (value === "exit") {
522
+ exit();
523
+ return;
524
+ }
525
+ setPendingExitConfirm(false);
526
+ };
527
+ return (_jsx(Box, { flexDirection: "column", paddingX: 1, children: !trusted ? (_jsxs(_Fragment, { children: [_jsx(TrustScreen, { workspaceRoot: session.workspaceRoot, onSelect: onTrustSelect }), pendingExitConfirm ? _jsx(ExitConfirmBox, { onSelect: onExitConfirmSelect }) : null] })) : (_jsxs(_Fragment, { children: [_jsx(Dashboard, { config: config, session: session, status: visibleStatus }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [transcriptCards.length === 0 && !assistantBuffer && !spinnerLabel ? (_jsx(Box, { borderStyle: "round", borderColor: "gray", paddingX: 1, children: _jsx(Text, { color: "gray", children: "New transcript. Use /history if you want earlier session messages." }) })) : null, transcriptCards.map((card) => (_jsx(TranscriptCard, { card: card, assistantBuffer: card.id === liveCardId ? assistantBuffer : "", liveLabel: card.id === liveCardId ? activityLabel ?? spinnerLabel : null }, card.id))), transcriptCards.length === 0 && (assistantBuffer || activityLabel || spinnerLabel) ? (_jsx(LiveStatusCard, { assistantBuffer: assistantBuffer, liveLabel: activityLabel ?? spinnerLabel })) : null] }), pendingExitConfirm ? (_jsx(ExitConfirmBox, { onSelect: onExitConfirmSelect })) : paused ? (_jsx(PauseBox, {})) : pendingApproval ? (_jsx(ApprovalBox, { request: pendingApproval.request, onSelect: onApprovalSelect })) : modelPickerOpen ? (_jsx(ModelPicker, { currentModel: session.model, onSelect: onModelSelect })) : pendingReasoningSetup ? (_jsx(ReasoningEffortPicker, { currentValue: pendingReasoningSetup.reasoningEffort, model: pendingReasoningSetup.model, onSelect: onReasoningSelect })) : pendingAuthInput ? (_jsx(AuthInputBox, { state: pendingAuthInput, onChange: onAuthInputChange, onSubmit: onAuthInputSubmit })) : pendingAuthRetention ? (_jsx(AuthRetentionBox, { state: pendingAuthRetention, onSelect: onAuthRetentionSelect })) : (_jsxs(_Fragment, { children: [_jsx(InputBox, { busy: busy, value: input, onChange: setInput, onSubmit: runPrompt }), showSlashSuggestions ? _jsx(SlashSuggestionBox, { suggestions: slashSuggestions }) : null] })), _jsx(Footer, { config: config, status: visibleStatus, session: session })] })) }));
528
+ }
529
+ function Dashboard({ config, session, status }) {
530
+ const infoRows = [
531
+ { item: "model", value: session.model },
532
+ { item: "directory", value: session.workspaceRoot },
533
+ { item: "session", value: session.id.slice(0, 8) },
534
+ { item: "updated", value: formatTimestamp(session.updatedAt) }
535
+ ];
536
+ const stateRows = [
537
+ { item: "auth", value: describeAuth(config) },
538
+ { item: "reasoning", value: formatReasoningEffort(config.reasoningEffort) },
539
+ { item: "skills", value: describeSkills(session.pinnedSkills.length) },
540
+ { item: "sha256", value: config.authFingerprint?.slice(0, 12) ?? "(none)" },
541
+ { item: "context", value: describeContext(session.messages.length) }
542
+ ];
543
+ return (_jsxs(_Fragment, { children: [_jsxs(Box, { borderStyle: "round", borderColor: "yellow", paddingX: 1, flexDirection: "row", children: [_jsxs(Box, { flexDirection: "column", width: "60%", paddingRight: 2, children: [_jsx(Text, { color: "yellow", children: "Vetala" }), _jsx(Text, { bold: true, children: "Ready." }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: infoRows.map((row) => (_jsx(InfoRow, { item: row.item, value: row.value }, row.item))) })] }), _jsxs(Box, { flexDirection: "column", width: "40%", children: [_jsx(Text, { color: "yellow", children: "Tips" }), _jsx(Text, { children: "/help for commands" }), _jsx(Text, { children: "/model for model + reasoning" }), _jsx(Text, { children: "/skill to inspect local skills" }), _jsx(Text, { children: "/logout to clear local auth" }), _jsx(Text, { children: "Ctrl+C to pause" }), _jsx(Text, { children: "Ctrl+D to exit" }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "gray", children: ["status: ", status] }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "yellow", children: "Context" }) }), stateRows.map((row) => (_jsx(InfoRow, { item: row.item, value: row.value }, row.item)))] })] }), _jsx(Box, { marginTop: 1, borderStyle: "round", borderColor: "gray", paddingX: 1, children: _jsx(Text, { children: "Try \"explain this codebase\" or \"write a test for <filepath>\"" }) })] }));
544
+ }
545
+ function InfoRow({ item, value }) {
546
+ return (_jsxs(Box, { children: [_jsx(Box, { width: 12, children: _jsx(Text, { color: "gray", children: item }) }), _jsx(Text, { children: value })] }));
547
+ }
548
+ function TrustScreen({ workspaceRoot, onSelect }) {
549
+ return (_jsxs(Box, { borderStyle: "round", borderColor: "yellow", paddingX: 1, flexDirection: "column", children: [_jsx(Text, { color: "yellow", children: "Accessing workspace" }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { children: workspaceRoot }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Quick safety check: is this a project you created or one you trust? If not, review it before continuing." }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { children: "Vetala will be able to read, edit, and execute files here." }) })] }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: [
550
+ { label: "Yes, I trust this folder", value: "trust" },
551
+ { label: "No, exit", value: "exit" }
552
+ ], onSelect: (item) => void onSelect(item.value) }) })] }));
553
+ }
554
+ function ApprovalBox({ request, onSelect }) {
555
+ return (_jsxs(Box, { marginTop: 1, borderStyle: "round", borderColor: "magenta", paddingX: 1, flexDirection: "column", children: [_jsx(Text, { color: "magenta", children: "Approval required" }), request.label.split("\n").map((line) => (_jsx(Text, { children: line }, line))), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: [
556
+ { label: "Allow once", value: "once" },
557
+ { label: "Allow for session", value: "session" },
558
+ { label: "Deny", value: "deny" }
559
+ ], onSelect: (item) => void onSelect(item.value) }) })] }));
560
+ }
561
+ function ModelPicker({ currentModel, onSelect }) {
562
+ return (_jsxs(Box, { marginTop: 1, borderStyle: "round", borderColor: "green", paddingX: 1, flexDirection: "column", children: [_jsx(Text, { color: "green", children: "Select model" }), _jsxs(Text, { color: "gray", children: ["Current: ", currentModel] }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: [
563
+ ...SARVAM_MODELS.map((model) => ({
564
+ label: model === currentModel ? `${model} (current)` : model,
565
+ value: model
566
+ })),
567
+ { label: "Cancel", value: "cancel" }
568
+ ], onSelect: (item) => void onSelect(item.value) }) })] }));
569
+ }
570
+ function ReasoningEffortPicker({ currentValue, model, onSelect }) {
571
+ return (_jsxs(Box, { marginTop: 1, borderStyle: "round", borderColor: "green", paddingX: 1, flexDirection: "column", children: [_jsx(Text, { color: "green", children: "Select reasoning effort" }), _jsxs(Text, { color: "gray", children: ["Model: ", model, " \u00B7 Current: ", formatReasoningEffort(currentValue)] }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: [
572
+ { label: "None (null / let Sarvam decide)", value: "none" },
573
+ { label: "Low", value: "low" },
574
+ { label: "Medium", value: "medium" },
575
+ { label: "High", value: "high" },
576
+ { label: "Cancel", value: "cancel" }
577
+ ], onSelect: (item) => void onSelect(item.value) }) })] }));
578
+ }
579
+ function AuthInputBox({ state, onChange, onSubmit }) {
580
+ return (_jsxs(Box, { marginTop: 1, borderStyle: "round", borderColor: "green", paddingX: 1, flexDirection: "column", children: [_jsxs(Text, { color: "green", children: ["Enter API key for ", state.model] }), _jsx(Text, { color: "gray", children: "This will be used as Sarvam's `apiSubscriptionKey`. After you press Enter, choose whether Vetala keeps it for all sessions or only for this session." }), _jsxs(Text, { color: "gray", children: ["Reasoning: ", formatReasoningEffort(state.reasoningEffort)] }), _jsx(Text, { color: "gray", children: "Press Enter on an empty field to cancel." }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "cyan", children: "key " }), _jsx(TextInput, { mask: "*", highlightPastedText: false, value: state.value, onChange: onChange, onSubmit: (value) => void onSubmit(value) })] })] }));
581
+ }
582
+ function AuthRetentionBox({ state, onSelect }) {
583
+ return (_jsxs(Box, { marginTop: 1, borderStyle: "round", borderColor: "green", paddingX: 1, flexDirection: "column", children: [_jsxs(Text, { color: "green", children: ["Keep API key for ", state.model] }), _jsxs(Text, { color: "gray", children: ["Key preview: ", maskSecretPreview(state.value)] }), _jsxs(Text, { color: "gray", children: ["Reasoning: ", formatReasoningEffort(state.reasoningEffort)] }), _jsx(Text, { color: "gray", children: "Future-session mode stores the raw key locally until you run /logout." }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: _jsx(Text, { children: "Choose how long Vetala should keep this key:" }) }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: [
584
+ {
585
+ label: "Keep for all sessions until /logout",
586
+ value: "persist"
587
+ },
588
+ {
589
+ label: "This session only",
590
+ value: "session"
591
+ },
592
+ {
593
+ label: "Cancel",
594
+ value: "cancel"
595
+ }
596
+ ], onSelect: (item) => void onSelect(item.value) }) })] }));
597
+ }
598
+ function InputBox({ busy, value, onChange, onSubmit }) {
599
+ return (_jsxs(Box, { marginTop: 1, borderStyle: "round", borderColor: "white", paddingX: 1, children: [_jsx(Text, { color: "cyan", children: "\u276F " }), busy ? (_jsx(Text, { color: "gray", children: "Agent is busy. Wait for the current turn to finish." })) : (_jsx(TextInput, { highlightPastedText: false, value: value, onChange: onChange, onSubmit: (nextValue) => void onSubmit(nextValue) }))] }));
600
+ }
601
+ function SlashSuggestionBox({ suggestions }) {
602
+ return (_jsxs(Box, { marginTop: 1, borderStyle: "round", borderColor: "blue", paddingX: 1, flexDirection: "column", children: [_jsx(Text, { color: "blue", children: "Commands" }), _jsx(Text, { color: "gray", children: "Tab autocompletes the first match." }), suggestions.map((suggestion, index) => (_jsxs(Box, { children: [_jsx(Box, { width: "45%", children: _jsxs(Text, { color: index === 0 ? "cyan" : "white", children: [index === 0 ? "❯ " : " ", suggestion.label] }) }), _jsx(Text, { color: "gray", children: suggestion.detail })] }, suggestion.label)))] }));
603
+ }
604
+ function PauseBox() {
605
+ return (_jsxs(Box, { marginTop: 1, borderStyle: "round", borderColor: "yellow", paddingX: 1, flexDirection: "column", children: [_jsx(Text, { color: "yellow", children: "Paused" }), _jsx(Text, { children: "Press Ctrl+C again to resume." }), _jsx(Text, { children: "Press Ctrl+D if you want to exit." })] }));
606
+ }
607
+ function ExitConfirmBox({ onSelect }) {
608
+ return (_jsxs(Box, { marginTop: 1, borderStyle: "round", borderColor: "red", paddingX: 1, flexDirection: "column", children: [_jsx(Text, { color: "red", children: "Exit Vetala?" }), _jsx(Text, { color: "gray", children: "Current session state is already written to disk as it changes." }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: [
609
+ { label: "Exit", value: "exit" },
610
+ { label: "Stay", value: "stay" }
611
+ ], onSelect: (item) => void onSelect(item.value) }) })] }));
612
+ }
613
+ function Footer({ config, status, session }) {
614
+ return (_jsxs(Box, { marginTop: 1, justifyContent: "space-between", children: [_jsx(Text, { color: "gray", children: "/help for commands \u00B7 Ctrl+C pause \u00B7 Ctrl+D exit" }), _jsxs(Text, { color: "gray", children: [status, " \u00B7 ", describeAuth(config), " \u00B7 ", describeContext(session.messages.length)] })] }));
615
+ }
616
+ function TranscriptCard({ card, assistantBuffer, liveLabel }) {
617
+ const borderColor = transcriptCardBorder(card.entries);
618
+ return (_jsxs(Box, { marginBottom: 1, borderStyle: "round", borderColor: borderColor, paddingX: 1, flexDirection: "column", children: [card.entries.map((entry) => (_jsx(TranscriptSection, { entry: entry }, entry.id))), liveLabel ? _jsx(LiveActivitySection, { label: liveLabel }) : null, assistantBuffer ? (_jsx(TranscriptSection, { entry: { id: `${card.id}:stream`, kind: "assistant", text: assistantBuffer } })) : null] }));
619
+ }
620
+ function LiveStatusCard({ assistantBuffer, liveLabel }) {
621
+ return (_jsxs(Box, { marginBottom: 1, borderStyle: "round", borderColor: "cyan", paddingX: 1, flexDirection: "column", children: [liveLabel ? _jsx(LiveActivitySection, { label: liveLabel }) : null, assistantBuffer ? (_jsx(TranscriptSection, { entry: { id: "live:assistant", kind: "assistant", text: assistantBuffer } })) : null] }));
622
+ }
623
+ function TranscriptSection({ entry }) {
624
+ const isActivity = entry.kind === "activity";
625
+ return (_jsxs(Box, { marginBottom: 1, flexDirection: "column", children: [_jsx(Text, { color: entryColor(entry.kind), children: entryLabel(entry.kind) }), entry.text.split("\n").map((line, index) => isActivity ? (_jsx(Text, { color: "gray", children: line.length > 0 ? line : " " }, `${entry.id}:${index}`)) : (_jsx(Text, { children: line.length > 0 ? line : " " }, `${entry.id}:${index}`)))] }));
626
+ }
627
+ function LiveActivitySection({ label }) {
628
+ return (_jsxs(Box, { marginBottom: 1, flexDirection: "column", children: [_jsx(Text, { color: "gray", children: "doing" }), _jsxs(Box, { children: [_jsx(Text, { color: "cyan", children: _jsx(Spinner, { type: "dots" }) }), _jsxs(Text, { color: "gray", children: [" ", label] })] })] }));
629
+ }
630
+ function cloneSession(session) {
631
+ return {
632
+ ...session,
633
+ approvals: {
634
+ sessionActionKeys: [...session.approvals.sessionActionKeys],
635
+ outOfTreeRoots: [...session.approvals.outOfTreeRoots],
636
+ webAccess: session.approvals.webAccess
637
+ },
638
+ messages: [...session.messages],
639
+ referencedFiles: [...session.referencedFiles],
640
+ readFiles: [...session.readFiles],
641
+ pinnedSkills: [...session.pinnedSkills]
642
+ };
643
+ }
644
+ function formatSessionList(sessions) {
645
+ return sessions.length > 0
646
+ ? sessions
647
+ .slice(0, 10)
648
+ .map((item) => `${item.id} ${item.updatedAt} ${item.workspaceRoot}`)
649
+ .join("\n")
650
+ : "(no sessions)";
651
+ }
652
+ function formatTimestamp(value) {
653
+ const date = new Date(value);
654
+ return Number.isNaN(date.valueOf()) ? value : date.toLocaleString();
655
+ }
656
+ function describeAuth(config) {
657
+ switch (config.authSource) {
658
+ case "env":
659
+ return `${renderAuthMode(config.authMode)} from env`;
660
+ case "session":
661
+ return `${renderAuthMode(config.authMode)} in session`;
662
+ case "stored":
663
+ return `${renderAuthMode(config.authMode)} saved locally`;
664
+ case "stored_hash":
665
+ return `${renderAuthMode(config.authMode)} fingerprint only`;
666
+ case "missing":
667
+ return "missing";
668
+ }
669
+ }
670
+ function formatReasoningEffort(value) {
671
+ return value ?? "(none)";
672
+ }
673
+ function describeSkills(pinnedCount) {
674
+ return pinnedCount > 0 ? `${pinnedCount} pinned` : "none pinned";
675
+ }
676
+ function formatModelSetupSummary(state, config, authRetention) {
677
+ const lines = [
678
+ `Model: ${state.model}`,
679
+ `Reasoning effort: ${formatReasoningEffort(state.reasoningEffort)}`,
680
+ `Credential: ${describeAuth(config)}`,
681
+ `Stored SHA-256: ${config.authFingerprint?.slice(0, 16) ?? "(none)"}`
682
+ ];
683
+ if (authRetention === "persist") {
684
+ lines.push("Raw key is stored locally for all future sessions until /logout.");
685
+ }
686
+ else if (authRetention === "session") {
687
+ lines.push("Raw key is kept only in memory for this session.");
688
+ }
689
+ return lines.join("\n");
690
+ }
691
+ function describeContext(messageCount) {
692
+ if (messageCount <= 12) {
693
+ return `${messageCount} live messages`;
694
+ }
695
+ return `${messageCount - 12} compacted, 12 live`;
696
+ }
697
+ function summarizeUserPrompt(prompt) {
698
+ const lineCount = prompt.split("\n").length;
699
+ const hasLargePaste = prompt.length > 260 || lineCount > 6;
700
+ if (!hasLargePaste) {
701
+ return prompt;
702
+ }
703
+ const preview = prompt.replace(/\s+/g, " ").trim().slice(0, 120);
704
+ return [
705
+ `Pasted content: ${prompt.length} chars, ${lineCount} lines`,
706
+ `Preview: ${preview}${preview.length < prompt.replace(/\s+/g, " ").trim().length ? "..." : ""}`
707
+ ].join("\n");
708
+ }
709
+ function renderAuthMode(authMode) {
710
+ switch (authMode) {
711
+ case "bearer":
712
+ return "bearer token";
713
+ case "subscription_key":
714
+ return "API key";
715
+ case "missing":
716
+ return "missing";
717
+ }
718
+ }
719
+ function isControlInput(inputValue, key, expectedKey, rawControlChar) {
720
+ return (key.ctrl && inputValue.toLowerCase() === expectedKey) || inputValue === rawControlChar;
721
+ }
722
+ function isTabInput(inputValue, key) {
723
+ return key.tab === true || inputValue === "\t";
724
+ }
725
+ function maskSecretPreview(value) {
726
+ const compact = value.trim();
727
+ if (compact.length <= 8) {
728
+ return compact;
729
+ }
730
+ return `${compact.slice(0, 4)}...${compact.slice(-4)}`;
731
+ }
732
+ function entryColor(kind) {
733
+ switch (kind) {
734
+ case "assistant":
735
+ return "cyan";
736
+ case "user":
737
+ return "green";
738
+ case "tool":
739
+ return "magenta";
740
+ case "activity":
741
+ return "gray";
742
+ case "info":
743
+ return "blue";
744
+ case "warn":
745
+ return "yellow";
746
+ case "error":
747
+ return "red";
748
+ }
749
+ }
750
+ function entryLabel(kind) {
751
+ switch (kind) {
752
+ case "assistant":
753
+ return "assistant";
754
+ case "user":
755
+ return "user";
756
+ case "tool":
757
+ return "tool";
758
+ case "activity":
759
+ return "doing";
760
+ case "info":
761
+ return "info";
762
+ case "warn":
763
+ return "warn";
764
+ case "error":
765
+ return "error";
766
+ }
767
+ }
768
+ function transcriptCardBorder(entries) {
769
+ if (entries.some((entry) => entry.kind === "error")) {
770
+ return "red";
771
+ }
772
+ if (entries.some((entry) => entry.kind === "warn")) {
773
+ return "yellow";
774
+ }
775
+ if (entries.some((entry) => entry.kind === "tool")) {
776
+ return "magenta";
777
+ }
778
+ if (entries.some((entry) => entry.kind === "assistant")) {
779
+ return "white";
780
+ }
781
+ if (entries.some((entry) => entry.kind === "info")) {
782
+ return "blue";
783
+ }
784
+ if (entries.some((entry) => entry.kind === "activity")) {
785
+ return "gray";
786
+ }
787
+ return "white";
788
+ }
789
+ //# sourceMappingURL=repl-app.js.map