@valni/cli-darwin-x64 0.0.0-stage → 0.1.3

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 (183) hide show
  1. package/LICENSE +52 -0
  2. package/package.json +18 -5
  3. package/runtime/LICENSE +52 -0
  4. package/runtime/assets/clankolas.png +0 -0
  5. package/runtime/examples/extensions/auto-commit-on-exit.ts +49 -0
  6. package/runtime/examples/extensions/bash-spawn-hook.ts +30 -0
  7. package/runtime/examples/extensions/bookmark.ts +50 -0
  8. package/runtime/examples/extensions/border-status-editor.ts +145 -0
  9. package/runtime/examples/extensions/built-in-tool-renderer.ts +249 -0
  10. package/runtime/examples/extensions/claude-rules.ts +86 -0
  11. package/runtime/examples/extensions/commands.ts +72 -0
  12. package/runtime/examples/extensions/confirm-destructive.ts +59 -0
  13. package/runtime/examples/extensions/custom-footer.ts +64 -0
  14. package/runtime/examples/extensions/custom-header.ts +73 -0
  15. package/runtime/examples/extensions/custom-provider-anthropic/index.ts +604 -0
  16. package/runtime/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
  17. package/runtime/examples/extensions/custom-provider-anthropic/package.json +19 -0
  18. package/runtime/examples/extensions/dirty-repo-guard.ts +56 -0
  19. package/runtime/examples/extensions/doom-overlay/doom/build/doom.js +21 -0
  20. package/runtime/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
  21. package/runtime/examples/extensions/doom-overlay/doom/build.sh +152 -0
  22. package/runtime/examples/extensions/doom-overlay/doom/doomgeneric_valni.c +72 -0
  23. package/runtime/examples/extensions/doom-overlay/doom-component.ts +132 -0
  24. package/runtime/examples/extensions/doom-overlay/doom-engine.ts +173 -0
  25. package/runtime/examples/extensions/doom-overlay/doom-keys.ts +104 -0
  26. package/runtime/examples/extensions/doom-overlay/index.ts +74 -0
  27. package/runtime/examples/extensions/doom-overlay/wad-finder.ts +51 -0
  28. package/runtime/examples/extensions/dynamic-resources/dynamic.json +78 -0
  29. package/runtime/examples/extensions/dynamic-resources/index.ts +13 -0
  30. package/runtime/examples/extensions/dynamic-tools.ts +74 -0
  31. package/runtime/examples/extensions/entry-renderer.ts +41 -0
  32. package/runtime/examples/extensions/event-bus.ts +43 -0
  33. package/runtime/examples/extensions/file-trigger.ts +41 -0
  34. package/runtime/examples/extensions/git-checkpoint.ts +53 -0
  35. package/runtime/examples/extensions/git-merge-and-resolve.ts +115 -0
  36. package/runtime/examples/extensions/github-issue-autocomplete.ts +185 -0
  37. package/runtime/examples/extensions/hello.ts +26 -0
  38. package/runtime/examples/extensions/hidden-thinking-label.ts +53 -0
  39. package/runtime/examples/extensions/inline-bash.ts +94 -0
  40. package/runtime/examples/extensions/input-transform-streaming.ts +39 -0
  41. package/runtime/examples/extensions/input-transform.ts +43 -0
  42. package/runtime/examples/extensions/interactive-shell.ts +196 -0
  43. package/runtime/examples/extensions/mac-system-theme.ts +47 -0
  44. package/runtime/examples/extensions/message-renderer.ts +59 -0
  45. package/runtime/examples/extensions/minimal-mode.ts +426 -0
  46. package/runtime/examples/extensions/modal-editor.ts +85 -0
  47. package/runtime/examples/extensions/model-status.ts +31 -0
  48. package/runtime/examples/extensions/notify.ts +55 -0
  49. package/runtime/examples/extensions/overlay-qa-tests.ts +1450 -0
  50. package/runtime/examples/extensions/overlay-test.ts +153 -0
  51. package/runtime/examples/extensions/permission-gate.ts +34 -0
  52. package/runtime/examples/extensions/pirate.ts +47 -0
  53. package/runtime/examples/extensions/plan-mode/index.ts +390 -0
  54. package/runtime/examples/extensions/plan-mode/utils.ts +168 -0
  55. package/runtime/examples/extensions/preset.ts +436 -0
  56. package/runtime/examples/extensions/project-trust.ts +64 -0
  57. package/runtime/examples/extensions/prompt-customizer.ts +97 -0
  58. package/runtime/examples/extensions/protected-paths.ts +30 -0
  59. package/runtime/examples/extensions/provider-payload.ts +18 -0
  60. package/runtime/examples/extensions/question.ts +278 -0
  61. package/runtime/examples/extensions/questionnaire.ts +440 -0
  62. package/runtime/examples/extensions/rainbow-editor.ts +88 -0
  63. package/runtime/examples/extensions/reload-runtime.ts +37 -0
  64. package/runtime/examples/extensions/rpc-demo.ts +118 -0
  65. package/runtime/examples/extensions/sandbox/index.ts +321 -0
  66. package/runtime/examples/extensions/sandbox/package-lock.json +92 -0
  67. package/runtime/examples/extensions/sandbox/package.json +19 -0
  68. package/runtime/examples/extensions/send-user-message.ts +97 -0
  69. package/runtime/examples/extensions/session-name.ts +27 -0
  70. package/runtime/examples/extensions/shutdown-command.ts +63 -0
  71. package/runtime/examples/extensions/snake.ts +343 -0
  72. package/runtime/examples/extensions/space-invaders.ts +560 -0
  73. package/runtime/examples/extensions/ssh.ts +220 -0
  74. package/runtime/examples/extensions/status-line.ts +32 -0
  75. package/runtime/examples/extensions/structured-output.ts +65 -0
  76. package/runtime/examples/extensions/subagent/agents.ts +126 -0
  77. package/runtime/examples/extensions/subagent/index.ts +1009 -0
  78. package/runtime/examples/extensions/system-prompt-header.ts +17 -0
  79. package/runtime/examples/extensions/tic-tac-toe.ts +1008 -0
  80. package/runtime/examples/extensions/timed-confirm.ts +70 -0
  81. package/runtime/examples/extensions/titlebar-spinner.ts +58 -0
  82. package/runtime/examples/extensions/todo.ts +297 -0
  83. package/runtime/examples/extensions/tool-override.ts +144 -0
  84. package/runtime/examples/extensions/tools.ts +146 -0
  85. package/runtime/examples/extensions/trigger-compact.ts +50 -0
  86. package/runtime/examples/extensions/truncated-tool.ts +195 -0
  87. package/runtime/examples/extensions/widget-placement.ts +9 -0
  88. package/runtime/examples/extensions/with-deps/index.ts +32 -0
  89. package/runtime/examples/extensions/with-deps/package-lock.json +31 -0
  90. package/runtime/examples/extensions/with-deps/package.json +22 -0
  91. package/runtime/examples/extensions/working-indicator.ts +123 -0
  92. package/runtime/examples/extensions/working-message-test.ts +25 -0
  93. package/runtime/examples/rpc-extension-ui.ts +632 -0
  94. package/runtime/examples/sdk/01-minimal.ts +26 -0
  95. package/runtime/examples/sdk/02-custom-model.ts +43 -0
  96. package/runtime/examples/sdk/03-custom-prompt.ts +70 -0
  97. package/runtime/examples/sdk/04-skills.ts +55 -0
  98. package/runtime/examples/sdk/05-tools.ts +48 -0
  99. package/runtime/examples/sdk/06-extensions.ts +94 -0
  100. package/runtime/examples/sdk/07-context-files.ts +42 -0
  101. package/runtime/examples/sdk/08-prompt-templates.ts +51 -0
  102. package/runtime/examples/sdk/09-api-keys-and-oauth.ts +34 -0
  103. package/runtime/examples/sdk/10-settings.ts +53 -0
  104. package/runtime/examples/sdk/11-sessions.ts +52 -0
  105. package/runtime/examples/sdk/12-full-control.ts +71 -0
  106. package/runtime/examples/sdk/13-session-runtime.ts +67 -0
  107. package/runtime/export-html/ansi-to-html.js +249 -0
  108. package/runtime/export-html/index.js +226 -0
  109. package/runtime/export-html/template.css +1066 -0
  110. package/runtime/export-html/template.html +55 -0
  111. package/runtime/export-html/template.js +1864 -0
  112. package/runtime/export-html/tool-renderer.js +108 -0
  113. package/runtime/export-html/vendor/highlight.min.js +1213 -0
  114. package/runtime/export-html/vendor/marked.min.js +78 -0
  115. package/runtime/extensions/pi-switchboard/.github/workflows/ci.yml +51 -0
  116. package/runtime/extensions/pi-switchboard/LICENSE +22 -0
  117. package/runtime/extensions/pi-switchboard/README.md +85 -0
  118. package/runtime/extensions/pi-switchboard/extensions/switchboard/catalog.ts +183 -0
  119. package/runtime/extensions/pi-switchboard/extensions/switchboard/config.ts +97 -0
  120. package/runtime/extensions/pi-switchboard/extensions/switchboard/connections.ts +386 -0
  121. package/runtime/extensions/pi-switchboard/extensions/switchboard/constants.ts +12 -0
  122. package/runtime/extensions/pi-switchboard/extensions/switchboard/device-auth.ts +127 -0
  123. package/runtime/extensions/pi-switchboard/extensions/switchboard/envelope.ts +199 -0
  124. package/runtime/extensions/pi-switchboard/extensions/switchboard/errors.ts +180 -0
  125. package/runtime/extensions/pi-switchboard/extensions/switchboard/index.ts +125 -0
  126. package/runtime/extensions/pi-switchboard/extensions/switchboard/participant.ts +17 -0
  127. package/runtime/extensions/pi-switchboard/extensions/switchboard/sessionStream.ts +131 -0
  128. package/runtime/extensions/pi-switchboard/extensions/switchboard/toolProxy.ts +136 -0
  129. package/runtime/extensions/pi-switchboard/extensions/switchboard/tools.ts +16 -0
  130. package/runtime/extensions/pi-switchboard/extensions/switchboard/types.ts +37 -0
  131. package/runtime/extensions/pi-switchboard/package.json +30 -0
  132. package/runtime/extensions/pi-switchboard/tsconfig.json +13 -0
  133. package/runtime/extensions/switchboard-local/.github/workflows/ci.yml +80 -0
  134. package/runtime/extensions/switchboard-local/.github/workflows/release.yml +46 -0
  135. package/runtime/extensions/switchboard-local/README.md +98 -0
  136. package/runtime/extensions/switchboard-local/extensions/local/engine.ts +28 -0
  137. package/runtime/extensions/switchboard-local/extensions/local/engines/gguf.ts +324 -0
  138. package/runtime/extensions/switchboard-local/extensions/local/engines/llamaBuild.ts +62 -0
  139. package/runtime/extensions/switchboard-local/extensions/local/engines/mlx.ts +245 -0
  140. package/runtime/extensions/switchboard-local/extensions/local/engines/select.ts +38 -0
  141. package/runtime/extensions/switchboard-local/extensions/local/engines/support.ts +151 -0
  142. package/runtime/extensions/switchboard-local/extensions/local/hf.ts +106 -0
  143. package/runtime/extensions/switchboard-local/extensions/local/index.ts +67 -0
  144. package/runtime/extensions/switchboard-local/extensions/local/nativeStream.ts +602 -0
  145. package/runtime/extensions/switchboard-local/extensions/local/paths.ts +44 -0
  146. package/runtime/extensions/switchboard-local/extensions/local/provider.ts +57 -0
  147. package/runtime/extensions/switchboard-local/extensions/local/store.ts +82 -0
  148. package/runtime/extensions/switchboard-local/extensions/local/ui.ts +60 -0
  149. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard/dist/apiTypes.js +74 -0
  150. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard/dist/client.js +292 -0
  151. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard/dist/deviceAuth.js +155 -0
  152. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard/dist/errors.js +95 -0
  153. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard/dist/index.js +8 -0
  154. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard/dist/messages.js +253 -0
  155. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard/dist/models.js +19 -0
  156. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard/dist/native.js +886 -0
  157. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard/dist/wire.js +85 -0
  158. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard/package.json +39 -0
  159. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard-native/package.json +29 -0
  160. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard-native/src/anthropic.ts +127 -0
  161. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard-native/src/google.ts +111 -0
  162. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard-native/src/index.ts +8 -0
  163. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard-native/src/modelRecord.test.ts +25 -0
  164. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard-native/src/modelRecord.ts +57 -0
  165. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard-native/src/openaiGeneric.ts +103 -0
  166. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard-native/src/openaiPro.ts +89 -0
  167. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard-native/src/profile.ts +120 -0
  168. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard-native/src/routing.test.ts +82 -0
  169. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard-native/src/routing.ts +74 -0
  170. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard-native/src/validateConfig.google.test.ts +137 -0
  171. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard-native/src/validateConfig.openai.test.ts +241 -0
  172. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard-native/src/validateConfig.test.ts +174 -0
  173. package/runtime/extensions/switchboard-local/node_modules/@valni/switchboard-native/src/validateConfig.ts +438 -0
  174. package/runtime/extensions/switchboard-local/package.json +34 -0
  175. package/runtime/extensions/switchboard-local/tsconfig.json +13 -0
  176. package/runtime/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
  177. package/runtime/package.json +98 -0
  178. package/runtime/photon_rs_bg.wasm +0 -0
  179. package/runtime/theme/dark.json +86 -0
  180. package/runtime/theme/light.json +85 -0
  181. package/runtime/theme/theme-schema.json +340 -0
  182. package/runtime/valni +4 -0
  183. package/README.md +0 -3
package/LICENSE ADDED
@@ -0,0 +1,52 @@
1
+ Copyright (c) 2026 Benovi Limited Company.
2
+
3
+ All rights reserved.
4
+
5
+ Subject to the terms below, Benovi Limited Company grants you a limited,
6
+ non-exclusive, non-transferable, revocable license to use, reproduce, and
7
+ compile this software solely for the purpose of building applications that
8
+ interact with Switchboard and related Benovi Labs services, or with inference
9
+ endpoints you operate or are authorized to use.
10
+
11
+ You may not:
12
+ - redistribute this software as a standalone product;
13
+ - remove or alter this notice;
14
+ - use the Benovi Labs or Switchboard names to endorse or promote products
15
+ derived from this software without prior written permission.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20
+ BENOVI LIMITED COMPANY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
22
+ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ --------------------------------------------------------------------------
25
+
26
+ THIRD-PARTY NOTICES
27
+
28
+ This software includes code from pi, used under the MIT License. That code remains under its own terms, reproduced
29
+ below. Nothing in this notice grants rights to Benovi Limited Company's own
30
+ code, which is governed by the terms above.
31
+
32
+ MIT License
33
+
34
+ Copyright (c) 2025 Mario Zechner
35
+
36
+ Permission is hereby granted, free of charge, to any person obtaining a copy
37
+ of this software and associated documentation files (the "Software"), to deal
38
+ in the Software without restriction, including without limitation the rights
39
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
40
+ copies of the Software, and to permit persons to whom the Software is
41
+ furnished to do so, subject to the following conditions:
42
+
43
+ The above copyright notice and this permission notice shall be included in all
44
+ copies or substantial portions of the Software.
45
+
46
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
49
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
51
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
52
+ SOFTWARE.
package/package.json CHANGED
@@ -1,6 +1,19 @@
1
1
  {
2
- "name": "@valni/cli-darwin-x64",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "@valni/cli-darwin-x64",
3
+ "version": "0.1.3",
4
+ "license": "SEE LICENSE IN LICENSE",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "description": "The valni binary for darwin x64.",
9
+ "os": [
10
+ "darwin"
11
+ ],
12
+ "cpu": [
13
+ "x64"
14
+ ],
15
+ "files": [
16
+ "runtime",
17
+ "LICENSE"
18
+ ]
19
+ }
@@ -0,0 +1,52 @@
1
+ Copyright (c) 2026 Benovi Limited Company.
2
+
3
+ All rights reserved.
4
+
5
+ Subject to the terms below, Benovi Limited Company grants you a limited,
6
+ non-exclusive, non-transferable, revocable license to use, reproduce, and
7
+ compile this software solely for the purpose of building applications that
8
+ interact with Switchboard and related Benovi Labs services, or with inference
9
+ endpoints you operate or are authorized to use.
10
+
11
+ You may not:
12
+ - redistribute this software as a standalone product;
13
+ - remove or alter this notice;
14
+ - use the Benovi Labs or Switchboard names to endorse or promote products
15
+ derived from this software without prior written permission.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20
+ BENOVI LIMITED COMPANY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
22
+ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ --------------------------------------------------------------------------
25
+
26
+ THIRD-PARTY NOTICES
27
+
28
+ This software includes code from pi, used under the MIT License. That code remains under its own terms, reproduced
29
+ below. Nothing in this notice grants rights to Benovi Limited Company's own
30
+ code, which is governed by the terms above.
31
+
32
+ MIT License
33
+
34
+ Copyright (c) 2025 Mario Zechner
35
+
36
+ Permission is hereby granted, free of charge, to any person obtaining a copy
37
+ of this software and associated documentation files (the "Software"), to deal
38
+ in the Software without restriction, including without limitation the rights
39
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
40
+ copies of the Software, and to permit persons to whom the Software is
41
+ furnished to do so, subject to the following conditions:
42
+
43
+ The above copyright notice and this permission notice shall be included in all
44
+ copies or substantial portions of the Software.
45
+
46
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
49
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
51
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
52
+ SOFTWARE.
Binary file
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Auto-Commit on Exit Extension
3
+ *
4
+ * Automatically commits changes when the agent exits.
5
+ * Uses the last assistant message to generate a commit message.
6
+ */
7
+
8
+ import type { ExtensionAPI } from "@valni/cli";
9
+
10
+ export default function (valni: ExtensionAPI) {
11
+ valni.on("session_shutdown", async (_event, ctx) => {
12
+ // Check for uncommitted changes
13
+ const { stdout: status, code } = await valni.exec("git", ["status", "--porcelain"]);
14
+
15
+ if (code !== 0 || status.trim().length === 0) {
16
+ // Not a git repo or no changes
17
+ return;
18
+ }
19
+
20
+ // Find the last assistant message for commit context
21
+ const entries = ctx.sessionManager.getEntries();
22
+ let lastAssistantText = "";
23
+ for (let i = entries.length - 1; i >= 0; i--) {
24
+ const entry = entries[i];
25
+ if (entry.type === "message" && entry.message.role === "assistant") {
26
+ const content = entry.message.content;
27
+ if (Array.isArray(content)) {
28
+ lastAssistantText = content
29
+ .filter((c): c is { type: "text"; text: string } => c.type === "text")
30
+ .map((c) => c.text)
31
+ .join("\n");
32
+ }
33
+ break;
34
+ }
35
+ }
36
+
37
+ // Generate a simple commit message
38
+ const firstLine = lastAssistantText.split("\n")[0] || "Work in progress";
39
+ const commitMessage = `[valni] ${firstLine.slice(0, 50)}${firstLine.length > 50 ? "..." : ""}`;
40
+
41
+ // Stage and commit
42
+ await valni.exec("git", ["add", "-A"]);
43
+ const { code: commitCode } = await valni.exec("git", ["commit", "-m", commitMessage]);
44
+
45
+ if (commitCode === 0 && ctx.hasUI) {
46
+ ctx.ui.notify(`Auto-committed: ${commitMessage}`, "info");
47
+ }
48
+ });
49
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Bash Spawn Hook Example
3
+ *
4
+ * Adjusts command, cwd, and env before execution.
5
+ *
6
+ * Usage:
7
+ * valni -e ./bash-spawn-hook.ts
8
+ */
9
+
10
+ import type { ExtensionAPI } from "@valni/cli";
11
+ import { createBashTool } from "@valni/cli";
12
+
13
+ export default function (valni: ExtensionAPI) {
14
+ const cwd = process.cwd();
15
+
16
+ const bashTool = createBashTool(cwd, {
17
+ spawnHook: ({ command, cwd, env }) => ({
18
+ command: `source ~/.profile\n${command}`,
19
+ cwd,
20
+ env: { ...env, PI_SPAWN_HOOK: "1" },
21
+ }),
22
+ });
23
+
24
+ valni.registerTool({
25
+ ...bashTool,
26
+ execute: async (id, params, signal, onUpdate, _ctx) => {
27
+ return bashTool.execute(id, params, signal, onUpdate);
28
+ },
29
+ });
30
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Entry bookmarking example.
3
+ *
4
+ * Shows setLabel to mark entries with labels for easy navigation in /tree.
5
+ * Labels appear in the tree view and help you find important points.
6
+ *
7
+ * Usage: /bookmark [label] - bookmark the last assistant message
8
+ */
9
+
10
+ import type { ExtensionAPI } from "@valni/cli";
11
+
12
+ export default function (valni: ExtensionAPI) {
13
+ valni.registerCommand("bookmark", {
14
+ description: "Bookmark last message (usage: /bookmark [label])",
15
+ handler: async (args, ctx) => {
16
+ const label = args.trim() || `bookmark-${Date.now()}`;
17
+
18
+ // Find the last assistant message entry
19
+ const entries = ctx.sessionManager.getEntries();
20
+ for (let i = entries.length - 1; i >= 0; i--) {
21
+ const entry = entries[i];
22
+ if (entry.type === "message" && entry.message.role === "assistant") {
23
+ valni.setLabel(entry.id, label);
24
+ ctx.ui.notify(`Bookmarked as: ${label}`, "info");
25
+ return;
26
+ }
27
+ }
28
+
29
+ ctx.ui.notify("No assistant message to bookmark", "warning");
30
+ },
31
+ });
32
+
33
+ // Remove bookmark
34
+ valni.registerCommand("unbookmark", {
35
+ description: "Remove bookmark from last labeled entry",
36
+ handler: async (_args, ctx) => {
37
+ const entries = ctx.sessionManager.getEntries();
38
+ for (let i = entries.length - 1; i >= 0; i--) {
39
+ const entry = entries[i];
40
+ const label = ctx.sessionManager.getLabel(entry.id);
41
+ if (label) {
42
+ valni.setLabel(entry.id, undefined);
43
+ ctx.ui.notify(`Removed bookmark: ${label}`, "info");
44
+ return;
45
+ }
46
+ }
47
+ ctx.ui.notify("No bookmarked entry found", "warning");
48
+ },
49
+ });
50
+ }
@@ -0,0 +1,145 @@
1
+ import { CustomEditor, type ExtensionAPI, type ExtensionContext, type KeybindingsManager } from "@valni/cli";
2
+ import type { Component, EditorTheme, TUI } from "@valni/tui";
3
+ import { truncateToWidth, visibleWidth } from "@valni/tui";
4
+
5
+ function fitBorder(
6
+ left: string,
7
+ right: string,
8
+ width: number,
9
+ border: (text: string) => string,
10
+ fill: (text: string) => string = border,
11
+ ): string {
12
+ if (width <= 0) return "";
13
+ if (width === 1) return border("─");
14
+
15
+ let leftText = left;
16
+ let rightText = right;
17
+ const fixedWidth = 2;
18
+ const minimumGap = 3;
19
+
20
+ while (
21
+ fixedWidth + visibleWidth(leftText) + visibleWidth(rightText) + minimumGap > width &&
22
+ visibleWidth(rightText) > 0
23
+ ) {
24
+ rightText = truncateToWidth(rightText, Math.max(0, visibleWidth(rightText) - 1), "");
25
+ }
26
+ while (
27
+ fixedWidth + visibleWidth(leftText) + visibleWidth(rightText) + minimumGap > width &&
28
+ visibleWidth(leftText) > 0
29
+ ) {
30
+ leftText = truncateToWidth(leftText, Math.max(0, visibleWidth(leftText) - 1), "");
31
+ }
32
+
33
+ const gapWidth = Math.max(0, width - fixedWidth - visibleWidth(leftText) - visibleWidth(rightText));
34
+ return `${border("─")}${leftText}${fill("─".repeat(gapWidth))}${rightText}${border("─")}`;
35
+ }
36
+
37
+ function formatCwd(cwd: string): string {
38
+ const home = process.env.HOME;
39
+ if (home && cwd.startsWith(home)) {
40
+ return `~${cwd.slice(home.length)}`;
41
+ }
42
+ return cwd;
43
+ }
44
+
45
+ function formatContext(ctx: ExtensionContext): string {
46
+ const usage = ctx.getContextUsage();
47
+ const contextWindow = usage?.contextWindow ?? ctx.model?.contextWindow;
48
+ if (!contextWindow || !usage || usage.percent === null) {
49
+ return "ctx ?";
50
+ }
51
+ return `ctx ${Math.round(usage.percent)}%/${(contextWindow / 1000).toFixed(0)}k`;
52
+ }
53
+
54
+ function formatThinking(level: string): string {
55
+ return level === "off" ? "off" : level;
56
+ }
57
+
58
+ class EmptyFooter implements Component {
59
+ render(): string[] {
60
+ return [];
61
+ }
62
+
63
+ invalidate(): void {}
64
+ }
65
+
66
+ export default function (valni: ExtensionAPI) {
67
+ let isWorking = false;
68
+ let spinnerIndex = 0;
69
+ let spinnerTimer: ReturnType<typeof setInterval> | undefined;
70
+ let activeTui: TUI | undefined;
71
+ const spinnerFrames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
72
+
73
+ const stopSpinner = () => {
74
+ if (spinnerTimer) {
75
+ clearInterval(spinnerTimer);
76
+ spinnerTimer = undefined;
77
+ }
78
+ };
79
+
80
+ valni.on("agent_start", () => {
81
+ isWorking = true;
82
+ stopSpinner();
83
+ spinnerTimer = setInterval(() => {
84
+ spinnerIndex = (spinnerIndex + 1) % spinnerFrames.length;
85
+ activeTui?.requestRender();
86
+ }, 80);
87
+ activeTui?.requestRender();
88
+ });
89
+
90
+ valni.on("agent_end", () => {
91
+ isWorking = false;
92
+ stopSpinner();
93
+ activeTui?.requestRender();
94
+ });
95
+
96
+ valni.on("session_shutdown", () => {
97
+ stopSpinner();
98
+ activeTui = undefined;
99
+ });
100
+
101
+ valni.on("session_start", (_event, ctx) => {
102
+ ctx.ui.setWorkingVisible(false);
103
+ ctx.ui.setFooter(() => new EmptyFooter());
104
+
105
+ let branch: string | undefined;
106
+
107
+ const refreshBranch = async () => {
108
+ const result = await valni.exec("git", ["branch", "--show-current"], { cwd: ctx.cwd }).catch(() => undefined);
109
+ const stdout = result?.stdout.trim();
110
+ branch = stdout && stdout.length > 0 ? stdout : undefined;
111
+ activeTui?.requestRender();
112
+ };
113
+ void refreshBranch();
114
+
115
+ class BorderStatusEditor extends CustomEditor {
116
+ constructor(tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager) {
117
+ super(tui, theme, keybindings, { paddingX: 0 });
118
+ activeTui = tui;
119
+ }
120
+
121
+ render(width: number): string[] {
122
+ const lines = super.render(width);
123
+ if (lines.length < 2) return lines;
124
+
125
+ const thm = ctx.ui.theme;
126
+ const model = ctx.model ? `${ctx.model.provider}/${ctx.model.id}` : "no model";
127
+ const thinking = valni.getThinkingLevel();
128
+ const topLeft = isWorking ? thm.fg("accent", ` ${spinnerFrames[spinnerIndex]} `) : "";
129
+ const topRight = "";
130
+ const bottomLeft = thm.fg("muted", ` ${model} · ${formatThinking(thinking)} `);
131
+ const bottomRight = thm.fg(
132
+ "muted",
133
+ ` ${formatContext(ctx)} · ${formatCwd(ctx.cwd)}${branch ? ` (${branch})` : ""} `,
134
+ );
135
+ const borderColor = (text: string) => this.borderColor(text);
136
+
137
+ lines[0] = fitBorder(topLeft, topRight, width, borderColor);
138
+ lines[lines.length - 1] = fitBorder(bottomLeft, bottomRight, width, borderColor);
139
+ return lines;
140
+ }
141
+ }
142
+
143
+ ctx.ui.setEditorComponent((tui, theme, keybindings) => new BorderStatusEditor(tui, theme, keybindings));
144
+ });
145
+ }
@@ -0,0 +1,249 @@
1
+ /**
2
+ * Built-in Tool Renderer Example - Custom rendering for built-in tools
3
+ *
4
+ * Demonstrates how to override the rendering of built-in tools (read, bash,
5
+ * edit, write) without changing their behavior. Each tool is re-registered
6
+ * with the same name, delegating execution to the original implementation
7
+ * while providing compact custom renderCall/renderResult functions.
8
+ *
9
+ * This is useful for users who prefer more concise tool output, or who want
10
+ * to highlight specific information (e.g., showing only the diff stats for
11
+ * edit, or just the exit code for bash).
12
+ *
13
+ * How it works:
14
+ * - registerTool() with the same name as a built-in replaces it entirely
15
+ * - We create instances of the original tools via createReadTool(), etc.
16
+ * and delegate execute() to them
17
+ * - renderCall() controls what's shown when the tool is invoked
18
+ * - renderResult() controls what's shown after execution completes
19
+ * - renderShell: "self" lets a tool render its own outer shell instead of
20
+ * using the default boxed shell from ToolExecutionComponent
21
+ * - The `expanded` flag in renderResult indicates whether the user has
22
+ * toggled the tool output open (via ctrl+e or clicking)
23
+ *
24
+ * Usage:
25
+ * valni -e ./built-in-tool-renderer.ts
26
+ */
27
+
28
+ import type { BashToolDetails, EditToolDetails, ExtensionAPI, ReadToolDetails } from "@valni/cli";
29
+ import { createBashTool, createEditTool, createReadTool, createWriteTool } from "@valni/cli";
30
+ import { Text } from "@valni/tui";
31
+
32
+ export default function (valni: ExtensionAPI) {
33
+ const cwd = process.cwd();
34
+
35
+ // --- Read tool: show path and line count ---
36
+ const originalRead = createReadTool(cwd);
37
+ valni.registerTool({
38
+ name: "read",
39
+ label: "read",
40
+ description: originalRead.description,
41
+ parameters: originalRead.parameters,
42
+
43
+ async execute(toolCallId, params, signal, onUpdate) {
44
+ return originalRead.execute(toolCallId, params, signal, onUpdate);
45
+ },
46
+
47
+ renderCall(args, theme, _context) {
48
+ let text = theme.fg("toolTitle", theme.bold("read "));
49
+ text += theme.fg("accent", args.path);
50
+ if (args.offset || args.limit) {
51
+ const parts: string[] = [];
52
+ if (args.offset) parts.push(`offset=${args.offset}`);
53
+ if (args.limit) parts.push(`limit=${args.limit}`);
54
+ text += theme.fg("dim", ` (${parts.join(", ")})`);
55
+ }
56
+ return new Text(text, 0, 0);
57
+ },
58
+
59
+ renderResult(result, { expanded, isPartial }, theme, _context) {
60
+ if (isPartial) return new Text(theme.fg("warning", "Reading..."), 0, 0);
61
+
62
+ const details = result.details as ReadToolDetails | undefined;
63
+ const content = result.content[0];
64
+
65
+ if (content?.type === "image") {
66
+ return new Text(theme.fg("success", "Image loaded"), 0, 0);
67
+ }
68
+
69
+ if (content?.type !== "text") {
70
+ return new Text(theme.fg("error", "No content"), 0, 0);
71
+ }
72
+
73
+ const lineCount = content.text.split("\n").length;
74
+ let text = theme.fg("success", `${lineCount} lines`);
75
+
76
+ if (details?.truncation?.truncated) {
77
+ text += theme.fg("warning", ` (truncated from ${details.truncation.totalLines})`);
78
+ }
79
+
80
+ if (expanded) {
81
+ const lines = content.text.split("\n").slice(0, 15);
82
+ for (const line of lines) {
83
+ text += `\n${theme.fg("dim", line)}`;
84
+ }
85
+ if (lineCount > 15) {
86
+ text += `\n${theme.fg("muted", `... ${lineCount - 15} more lines`)}`;
87
+ }
88
+ }
89
+
90
+ return new Text(text, 0, 0);
91
+ },
92
+ });
93
+
94
+ // --- Bash tool: show command and exit code ---
95
+ const originalBash = createBashTool(cwd);
96
+ valni.registerTool({
97
+ name: "bash",
98
+ label: "bash",
99
+ description: originalBash.description,
100
+ parameters: originalBash.parameters,
101
+
102
+ async execute(toolCallId, params, signal, onUpdate) {
103
+ return originalBash.execute(toolCallId, params, signal, onUpdate);
104
+ },
105
+
106
+ renderCall(args, theme, _context) {
107
+ let text = theme.fg("toolTitle", theme.bold("$ "));
108
+ const cmd = args.command.length > 80 ? `${args.command.slice(0, 77)}...` : args.command;
109
+ text += theme.fg("accent", cmd);
110
+ if (args.timeout) {
111
+ text += theme.fg("dim", ` (timeout: ${args.timeout}s)`);
112
+ }
113
+ return new Text(text, 0, 0);
114
+ },
115
+
116
+ renderResult(result, { expanded, isPartial }, theme, _context) {
117
+ if (isPartial) return new Text(theme.fg("warning", "Running..."), 0, 0);
118
+
119
+ const details = result.details as BashToolDetails | undefined;
120
+ const content = result.content[0];
121
+ const output = content?.type === "text" ? content.text : "";
122
+
123
+ const exitMatch = output.match(/exit code: (\d+)/);
124
+ const exitCode = exitMatch ? parseInt(exitMatch[1], 10) : null;
125
+ const lineCount = output.split("\n").filter((l) => l.trim()).length;
126
+
127
+ let text = "";
128
+ if (exitCode === 0 || exitCode === null) {
129
+ text += theme.fg("success", "done");
130
+ } else {
131
+ text += theme.fg("error", `exit ${exitCode}`);
132
+ }
133
+ text += theme.fg("dim", ` (${lineCount} lines)`);
134
+
135
+ if (details?.truncation?.truncated) {
136
+ text += theme.fg("warning", " [truncated]");
137
+ }
138
+
139
+ if (expanded) {
140
+ const lines = output.split("\n").slice(0, 20);
141
+ for (const line of lines) {
142
+ text += `\n${theme.fg("dim", line)}`;
143
+ }
144
+ if (output.split("\n").length > 20) {
145
+ text += `\n${theme.fg("muted", "... more output")}`;
146
+ }
147
+ }
148
+
149
+ return new Text(text, 0, 0);
150
+ },
151
+ });
152
+
153
+ // --- Edit tool: show path and diff stats ---
154
+ const originalEdit = createEditTool(cwd);
155
+ valni.registerTool({
156
+ name: "edit",
157
+ label: "edit",
158
+ description: originalEdit.description,
159
+ parameters: originalEdit.parameters,
160
+ renderShell: "self",
161
+
162
+ async execute(toolCallId, params, signal, onUpdate) {
163
+ return originalEdit.execute(toolCallId, params, signal, onUpdate);
164
+ },
165
+
166
+ renderCall(args, theme, _context) {
167
+ let text = theme.fg("toolTitle", theme.bold("edit "));
168
+ text += theme.fg("accent", args.path);
169
+ return new Text(text, 0, 0);
170
+ },
171
+
172
+ renderResult(result, { expanded, isPartial }, theme, _context) {
173
+ if (isPartial) return new Text(theme.fg("warning", "Editing..."), 0, 0);
174
+
175
+ const details = result.details as EditToolDetails | undefined;
176
+ const content = result.content[0];
177
+
178
+ if (content?.type === "text" && content.text.startsWith("Error")) {
179
+ return new Text(theme.fg("error", content.text.split("\n")[0]), 0, 0);
180
+ }
181
+
182
+ if (!details?.diff) {
183
+ return new Text(theme.fg("success", "Applied"), 0, 0);
184
+ }
185
+
186
+ // Count additions and removals from the diff
187
+ const diffLines = details.diff.split("\n");
188
+ let additions = 0;
189
+ let removals = 0;
190
+ for (const line of diffLines) {
191
+ if (line.startsWith("+") && !line.startsWith("+++")) additions++;
192
+ if (line.startsWith("-") && !line.startsWith("---")) removals++;
193
+ }
194
+
195
+ let text = theme.fg("success", `+${additions}`);
196
+ text += theme.fg("dim", " / ");
197
+ text += theme.fg("error", `-${removals}`);
198
+
199
+ if (expanded) {
200
+ for (const line of diffLines.slice(0, 30)) {
201
+ if (line.startsWith("+") && !line.startsWith("+++")) {
202
+ text += `\n${theme.fg("success", line)}`;
203
+ } else if (line.startsWith("-") && !line.startsWith("---")) {
204
+ text += `\n${theme.fg("error", line)}`;
205
+ } else {
206
+ text += `\n${theme.fg("dim", line)}`;
207
+ }
208
+ }
209
+ if (diffLines.length > 30) {
210
+ text += `\n${theme.fg("muted", `... ${diffLines.length - 30} more diff lines`)}`;
211
+ }
212
+ }
213
+
214
+ return new Text(text, 0, 0);
215
+ },
216
+ });
217
+
218
+ // --- Write tool: show path and size ---
219
+ const originalWrite = createWriteTool(cwd);
220
+ valni.registerTool({
221
+ name: "write",
222
+ label: "write",
223
+ description: originalWrite.description,
224
+ parameters: originalWrite.parameters,
225
+
226
+ async execute(toolCallId, params, signal, onUpdate) {
227
+ return originalWrite.execute(toolCallId, params, signal, onUpdate);
228
+ },
229
+
230
+ renderCall(args, theme, _context) {
231
+ let text = theme.fg("toolTitle", theme.bold("write "));
232
+ text += theme.fg("accent", args.path);
233
+ const lineCount = args.content.split("\n").length;
234
+ text += theme.fg("dim", ` (${lineCount} lines)`);
235
+ return new Text(text, 0, 0);
236
+ },
237
+
238
+ renderResult(result, { isPartial }, theme, _context) {
239
+ if (isPartial) return new Text(theme.fg("warning", "Writing..."), 0, 0);
240
+
241
+ const content = result.content[0];
242
+ if (content?.type === "text" && content.text.startsWith("Error")) {
243
+ return new Text(theme.fg("error", content.text.split("\n")[0]), 0, 0);
244
+ }
245
+
246
+ return new Text(theme.fg("success", "Written"), 0, 0);
247
+ },
248
+ });
249
+ }