@dungle-scrubs/tallow 0.9.4 → 0.9.7

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 (212) hide show
  1. package/dist/cli.js +8 -5
  2. package/dist/cli.js.map +1 -1
  3. package/dist/config.d.ts +1 -1
  4. package/dist/config.js +1 -1
  5. package/dist/interactive-mode-patch.d.ts +24 -12
  6. package/dist/interactive-mode-patch.d.ts.map +1 -1
  7. package/dist/interactive-mode-patch.js +229 -146
  8. package/dist/interactive-mode-patch.js.map +1 -1
  9. package/dist/interactive-reset.d.ts +49 -0
  10. package/dist/interactive-reset.d.ts.map +1 -0
  11. package/dist/interactive-reset.js +40 -0
  12. package/dist/interactive-reset.js.map +1 -0
  13. package/dist/pi-tui-editor-patch.d.ts +10 -0
  14. package/dist/pi-tui-editor-patch.d.ts.map +1 -0
  15. package/dist/pi-tui-editor-patch.js +159 -0
  16. package/dist/pi-tui-editor-patch.js.map +1 -0
  17. package/dist/pi-tui-patch.d.ts +2 -0
  18. package/dist/pi-tui-patch.d.ts.map +1 -0
  19. package/dist/pi-tui-patch.js +563 -0
  20. package/dist/pi-tui-patch.js.map +1 -0
  21. package/dist/pi-tui-settings-list-patch.d.ts +11 -0
  22. package/dist/pi-tui-settings-list-patch.d.ts.map +1 -0
  23. package/dist/pi-tui-settings-list-patch.js +38 -0
  24. package/dist/pi-tui-settings-list-patch.js.map +1 -0
  25. package/dist/process-cleanup.js +1 -1
  26. package/dist/process-cleanup.js.map +1 -1
  27. package/dist/reset-diagnostics.d.ts +69 -0
  28. package/dist/reset-diagnostics.d.ts.map +1 -0
  29. package/dist/reset-diagnostics.js +41 -0
  30. package/dist/reset-diagnostics.js.map +1 -0
  31. package/dist/sdk.d.ts +7 -23
  32. package/dist/sdk.d.ts.map +1 -1
  33. package/dist/sdk.js +211 -174
  34. package/dist/sdk.js.map +1 -1
  35. package/dist/workspace-transition-interactive.d.ts +1 -0
  36. package/dist/workspace-transition-interactive.d.ts.map +1 -1
  37. package/dist/workspace-transition-interactive.js +8 -18
  38. package/dist/workspace-transition-interactive.js.map +1 -1
  39. package/extensions/__integration__/audit-findings.test.ts +4 -5
  40. package/extensions/_icons/index.ts +2 -4
  41. package/extensions/_shared/__tests__/image-metadata.test.ts +33 -0
  42. package/extensions/_shared/__tests__/shell-policy.test.ts +19 -0
  43. package/extensions/_shared/__tests__/terminal-links.test.ts +18 -0
  44. package/extensions/_shared/image-metadata.ts +99 -0
  45. package/extensions/_shared/inline-preview.ts +1 -1
  46. package/extensions/_shared/shell-policy.ts +121 -1
  47. package/extensions/_shared/terminal-links.ts +22 -0
  48. package/extensions/ask-user-question-tool/index.ts +0 -3
  49. package/extensions/clear/__tests__/clear.test.ts +269 -2
  50. package/extensions/command-expansion/index.ts +9 -3
  51. package/extensions/context-files/index.ts +5 -1
  52. package/extensions/context-fork/__tests__/context-fork.test.ts +94 -1
  53. package/extensions/context-fork/extension.json +1 -1
  54. package/extensions/context-fork/frontmatter-index.ts +6 -1
  55. package/extensions/context-fork/index.ts +32 -0
  56. package/extensions/edit-tool-enhanced/index.ts +2 -1
  57. package/extensions/git-status/__tests__/git-status.test.ts +65 -2
  58. package/extensions/git-status/index.ts +268 -98
  59. package/extensions/hooks/index.ts +33 -11
  60. package/extensions/loop/index.ts +14 -1
  61. package/extensions/lsp/index.ts +64 -13
  62. package/extensions/lsp/package.json +2 -2
  63. package/extensions/minimal-skill-display/index.ts +7 -1
  64. package/extensions/random-spinner/index.ts +7 -642
  65. package/extensions/read-tool-enhanced/index.ts +13 -10
  66. package/extensions/render-stabilizer/__tests__/render-stabilizer.test.ts +2 -3
  67. package/extensions/render-stabilizer/index.ts +6 -6
  68. package/extensions/rewind/__tests__/session-files.test.ts +115 -0
  69. package/extensions/rewind/__tests__/snapshots.test.ts +23 -0
  70. package/extensions/rewind/index.ts +5 -0
  71. package/extensions/rewind/session-files.ts +138 -0
  72. package/extensions/rewind/snapshots.ts +104 -5
  73. package/extensions/skill-commands/index.ts +6 -1
  74. package/extensions/slash-command-bridge/__tests__/slash-command-bridge.test.ts +26 -0
  75. package/extensions/slash-command-bridge/index.ts +14 -2
  76. package/extensions/subagent-tool/model-resolver.ts +274 -7
  77. package/extensions/subagent-tool/schema.ts +1 -2
  78. package/extensions/tasks/commands/register-tasks-extension.ts +9 -9
  79. package/extensions/teams-tool/tools/register-extension.ts +1 -3
  80. package/extensions/teams-tool/tools/teammate-tools.ts +1 -2
  81. package/extensions/web-search-tool/index.ts +2 -1
  82. package/extensions/wezterm-pane-control/index.ts +1 -2
  83. package/extensions/write-tool-enhanced/index.ts +2 -1
  84. package/node_modules/@mariozechner/pi-tui/README.md +56 -34
  85. package/node_modules/@mariozechner/pi-tui/dist/autocomplete.d.ts +18 -13
  86. package/node_modules/@mariozechner/pi-tui/dist/autocomplete.d.ts.map +1 -1
  87. package/node_modules/@mariozechner/pi-tui/dist/autocomplete.js +182 -113
  88. package/node_modules/@mariozechner/pi-tui/dist/autocomplete.js.map +1 -1
  89. package/node_modules/@mariozechner/pi-tui/dist/components/cancellable-loader.js +3 -3
  90. package/node_modules/@mariozechner/pi-tui/dist/components/cancellable-loader.js.map +1 -1
  91. package/node_modules/@mariozechner/pi-tui/dist/components/editor.d.ts +45 -36
  92. package/node_modules/@mariozechner/pi-tui/dist/components/editor.d.ts.map +1 -1
  93. package/node_modules/@mariozechner/pi-tui/dist/components/editor.js +489 -325
  94. package/node_modules/@mariozechner/pi-tui/dist/components/editor.js.map +1 -1
  95. package/node_modules/@mariozechner/pi-tui/dist/components/image.d.ts +1 -99
  96. package/node_modules/@mariozechner/pi-tui/dist/components/image.d.ts.map +1 -1
  97. package/node_modules/@mariozechner/pi-tui/dist/components/image.js +17 -192
  98. package/node_modules/@mariozechner/pi-tui/dist/components/image.js.map +1 -1
  99. package/node_modules/@mariozechner/pi-tui/dist/components/input.d.ts.map +1 -1
  100. package/node_modules/@mariozechner/pi-tui/dist/components/input.js +57 -60
  101. package/node_modules/@mariozechner/pi-tui/dist/components/input.js.map +1 -1
  102. package/node_modules/@mariozechner/pi-tui/dist/components/loader.d.ts +2 -69
  103. package/node_modules/@mariozechner/pi-tui/dist/components/loader.d.ts.map +1 -1
  104. package/node_modules/@mariozechner/pi-tui/dist/components/loader.js +5 -102
  105. package/node_modules/@mariozechner/pi-tui/dist/components/loader.js.map +1 -1
  106. package/node_modules/@mariozechner/pi-tui/dist/components/markdown.d.ts.map +1 -1
  107. package/node_modules/@mariozechner/pi-tui/dist/components/markdown.js +111 -53
  108. package/node_modules/@mariozechner/pi-tui/dist/components/markdown.js.map +1 -1
  109. package/node_modules/@mariozechner/pi-tui/dist/components/select-list.d.ts +19 -1
  110. package/node_modules/@mariozechner/pi-tui/dist/components/select-list.d.ts.map +1 -1
  111. package/node_modules/@mariozechner/pi-tui/dist/components/select-list.js +78 -67
  112. package/node_modules/@mariozechner/pi-tui/dist/components/select-list.js.map +1 -1
  113. package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.d.ts +1 -25
  114. package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.d.ts.map +1 -1
  115. package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.js +13 -50
  116. package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.js.map +1 -1
  117. package/node_modules/@mariozechner/pi-tui/dist/index.d.ts +8 -10
  118. package/node_modules/@mariozechner/pi-tui/dist/index.d.ts.map +1 -1
  119. package/node_modules/@mariozechner/pi-tui/dist/index.js +6 -9
  120. package/node_modules/@mariozechner/pi-tui/dist/index.js.map +1 -1
  121. package/node_modules/@mariozechner/pi-tui/dist/keybindings.d.ts +108 -238
  122. package/node_modules/@mariozechner/pi-tui/dist/keybindings.d.ts.map +1 -1
  123. package/node_modules/@mariozechner/pi-tui/dist/keybindings.js +108 -365
  124. package/node_modules/@mariozechner/pi-tui/dist/keybindings.js.map +1 -1
  125. package/node_modules/@mariozechner/pi-tui/dist/keys.d.ts +33 -48
  126. package/node_modules/@mariozechner/pi-tui/dist/keys.d.ts.map +1 -1
  127. package/node_modules/@mariozechner/pi-tui/dist/keys.js +239 -155
  128. package/node_modules/@mariozechner/pi-tui/dist/keys.js.map +1 -1
  129. package/node_modules/@mariozechner/pi-tui/dist/terminal-image.d.ts +14 -94
  130. package/node_modules/@mariozechner/pi-tui/dist/terminal-image.d.ts.map +1 -1
  131. package/node_modules/@mariozechner/pi-tui/dist/terminal-image.js +44 -186
  132. package/node_modules/@mariozechner/pi-tui/dist/terminal-image.js.map +1 -1
  133. package/node_modules/@mariozechner/pi-tui/dist/terminal.d.ts +13 -58
  134. package/node_modules/@mariozechner/pi-tui/dist/terminal.d.ts.map +1 -1
  135. package/node_modules/@mariozechner/pi-tui/dist/terminal.js +78 -111
  136. package/node_modules/@mariozechner/pi-tui/dist/terminal.js.map +1 -1
  137. package/node_modules/@mariozechner/pi-tui/dist/tui.d.ts +24 -110
  138. package/node_modules/@mariozechner/pi-tui/dist/tui.d.ts.map +1 -1
  139. package/node_modules/@mariozechner/pi-tui/dist/tui.js +188 -435
  140. package/node_modules/@mariozechner/pi-tui/dist/tui.js.map +1 -1
  141. package/node_modules/@mariozechner/pi-tui/dist/utils.d.ts +0 -18
  142. package/node_modules/@mariozechner/pi-tui/dist/utils.d.ts.map +1 -1
  143. package/node_modules/@mariozechner/pi-tui/dist/utils.js +251 -119
  144. package/node_modules/@mariozechner/pi-tui/dist/utils.js.map +1 -1
  145. package/node_modules/@mariozechner/pi-tui/package.json +6 -6
  146. package/node_modules/@mariozechner/pi-tui/src/__tests__/__snapshots__/render.test.ts.snap +3 -40
  147. package/node_modules/@mariozechner/pi-tui/src/__tests__/image-component.test.ts +71 -81
  148. package/node_modules/@mariozechner/pi-tui/src/__tests__/render.test.ts +0 -33
  149. package/node_modules/@mariozechner/pi-tui/src/__tests__/terminal-image.test.ts +93 -334
  150. package/node_modules/@mariozechner/pi-tui/src/__tests__/tui-render-scheduling.test.ts +1 -1
  151. package/node_modules/@mariozechner/pi-tui/src/__tests__/utils.test.ts +11 -196
  152. package/node_modules/@mariozechner/pi-tui/src/autocomplete.ts +228 -142
  153. package/node_modules/@mariozechner/pi-tui/src/components/cancellable-loader.ts +3 -3
  154. package/node_modules/@mariozechner/pi-tui/src/components/editor.ts +624 -390
  155. package/node_modules/@mariozechner/pi-tui/src/components/image.ts +17 -227
  156. package/node_modules/@mariozechner/pi-tui/src/components/input.ts +71 -63
  157. package/node_modules/@mariozechner/pi-tui/src/components/loader.ts +5 -137
  158. package/node_modules/@mariozechner/pi-tui/src/components/markdown.ts +143 -52
  159. package/node_modules/@mariozechner/pi-tui/src/components/select-list.ts +136 -70
  160. package/node_modules/@mariozechner/pi-tui/src/components/settings-list.ts +12 -51
  161. package/node_modules/@mariozechner/pi-tui/src/index.ts +17 -36
  162. package/node_modules/@mariozechner/pi-tui/src/keybindings.ts +148 -421
  163. package/node_modules/@mariozechner/pi-tui/src/keys.ts +253 -181
  164. package/node_modules/@mariozechner/pi-tui/src/terminal-image.ts +51 -252
  165. package/node_modules/@mariozechner/pi-tui/src/terminal.ts +78 -133
  166. package/node_modules/@mariozechner/pi-tui/src/tui.ts +202 -478
  167. package/node_modules/@mariozechner/pi-tui/src/utils.ts +289 -125
  168. package/node_modules/@mariozechner/pi-tui/tsconfig.build.json +1 -0
  169. package/package.json +13 -13
  170. package/packages/tallow-tui/node_modules/@types/mime-types/README.md +8 -2
  171. package/packages/tallow-tui/node_modules/@types/mime-types/index.d.ts +6 -0
  172. package/packages/tallow-tui/node_modules/@types/mime-types/package.json +9 -3
  173. package/packages/tallow-tui/node_modules/get-east-asian-width/lookup-data.js +18 -0
  174. package/packages/tallow-tui/node_modules/get-east-asian-width/lookup.js +116 -384
  175. package/packages/tallow-tui/node_modules/get-east-asian-width/package.json +5 -4
  176. package/packages/tallow-tui/node_modules/get-east-asian-width/utilities.js +24 -0
  177. package/packages/tallow-tui/node_modules/marked/README.md +5 -4
  178. package/packages/tallow-tui/node_modules/marked/bin/main.js +10 -8
  179. package/packages/tallow-tui/node_modules/marked/bin/marked.js +2 -1
  180. package/packages/tallow-tui/node_modules/marked/lib/marked.d.ts +156 -125
  181. package/packages/tallow-tui/node_modules/marked/lib/marked.esm.js +67 -2179
  182. package/packages/tallow-tui/node_modules/marked/lib/marked.esm.js.map +3 -3
  183. package/packages/tallow-tui/node_modules/marked/lib/marked.umd.js +67 -2201
  184. package/packages/tallow-tui/node_modules/marked/lib/marked.umd.js.map +3 -3
  185. package/packages/tallow-tui/node_modules/marked/man/marked.1 +4 -2
  186. package/packages/tallow-tui/node_modules/marked/man/marked.1.md +2 -1
  187. package/packages/tallow-tui/node_modules/marked/package.json +26 -34
  188. package/skills/tallow-expert/SKILL.md +3 -5
  189. package/node_modules/@mariozechner/pi-tui/dist/border-styles.d.ts +0 -32
  190. package/node_modules/@mariozechner/pi-tui/dist/border-styles.d.ts.map +0 -1
  191. package/node_modules/@mariozechner/pi-tui/dist/border-styles.js +0 -46
  192. package/node_modules/@mariozechner/pi-tui/dist/border-styles.js.map +0 -1
  193. package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.d.ts +0 -52
  194. package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.d.ts.map +0 -1
  195. package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.js +0 -89
  196. package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.js.map +0 -1
  197. package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.d.ts +0 -14
  198. package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.d.ts.map +0 -1
  199. package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.js +0 -55
  200. package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.js.map +0 -1
  201. package/node_modules/@mariozechner/pi-tui/src/__tests__/editor-change-listener.test.ts +0 -121
  202. package/node_modules/@mariozechner/pi-tui/src/__tests__/editor-ghost-text.test.ts +0 -112
  203. package/node_modules/@mariozechner/pi-tui/src/__tests__/mouse-events.test.ts +0 -134
  204. package/node_modules/@mariozechner/pi-tui/src/__tests__/settings-list.test.ts +0 -81
  205. package/node_modules/@mariozechner/pi-tui/src/__tests__/tui-diff-regression.test.ts +0 -555
  206. package/node_modules/@mariozechner/pi-tui/src/border-styles.ts +0 -60
  207. package/node_modules/@mariozechner/pi-tui/src/components/bordered-box.ts +0 -113
  208. package/node_modules/@mariozechner/pi-tui/src/test-utils/capability-env.ts +0 -56
  209. package/packages/tallow-tui/node_modules/marked/lib/marked.cjs +0 -2211
  210. package/packages/tallow-tui/node_modules/marked/lib/marked.cjs.map +0 -7
  211. package/packages/tallow-tui/node_modules/marked/lib/marked.d.cts +0 -728
  212. package/packages/tallow-tui/node_modules/marked/marked.min.js +0 -69
package/dist/sdk.js CHANGED
@@ -1,8 +1,7 @@
1
1
  import { existsSync, mkdirSync, readdirSync, readFileSync, statSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
3
  import { basename, delimiter, dirname, join, resolve, sep } from "node:path";
4
- import { bashTool, codingTools, createAgentSession, createEventBus, DefaultPackageManager, DefaultResourceLoader, editTool, findTool, grepTool, lsTool, ModelRegistry, readOnlyTools, readTool, SessionManager, SettingsManager, writeTool, } from "@mariozechner/pi-coding-agent";
5
- import * as PiTui from "@mariozechner/pi-tui";
4
+ import { createAgentSession, createAgentSessionRuntime, createEventBus, DefaultPackageManager, DefaultResourceLoader, ModelRegistry, SessionManager, SettingsManager, } from "@mariozechner/pi-coding-agent";
6
5
  import { atomicWriteFileSync } from "./atomic-write.js";
7
6
  import { createSecureAuthStorage, resolveRuntimeApiKeyFromEnv } from "./auth-hardening.js";
8
7
  import { applyAgentSessionCompactionCancelPatch } from "./compaction-cancel-patch.js";
@@ -10,6 +9,7 @@ import { BUNDLED, bootstrap, getRuntimeTallowHome, resolveOpSecrets, TALLOW_VERS
10
9
  import { applyInteractiveModeStaleUiPatch } from "./interactive-mode-patch.js";
11
10
  import { applyKnownModelMetadataOverrides } from "./model-metadata-overrides.js";
12
11
  import { createTelemetryHandle, extractTraceContextFromEnv, sessionAttributes, TELEMETRY_API_CHANNELS, } from "./otel.js";
12
+ import { applyPiTuiPatches } from "./pi-tui-patch.js";
13
13
  import { cleanupOrphanPids } from "./pid-manager.js";
14
14
  import { extractClaudePluginResources, readPluginManifest, resolvePlugins, } from "./plugins.js";
15
15
  import { applyProjectTrustContextToEnv, resolveProjectTrust, trustProject, untrustProject, } from "./project-trust.js";
@@ -48,32 +48,25 @@ const CONTEXT_BUDGET_API_CHANNELS = {
48
48
  };
49
49
  /** Default TTL for per-tool context-budget envelopes. */
50
50
  const CONTEXT_BUDGET_ENVELOPE_TTL_MS = 30_000;
51
- /** Map of tool name tool object for --tools flag resolution. */
52
- const TOOL_MAP = {
53
- read: readTool,
54
- bash: bashTool,
55
- edit: editTool,
56
- write: writeTool,
57
- grep: grepTool,
58
- find: findTool,
59
- ls: lsTool,
60
- };
61
- /** Preset aliases for --tools flag. */
51
+ const INDIVIDUAL_TOOL_NAMES = ["read", "bash", "edit", "write", "grep", "find", "ls"];
52
+ const CODING_TOOL_NAMES = ["read", "bash", "edit", "write"];
53
+ const READONLY_TOOL_NAMES = ["read", "grep", "find", "ls"];
54
+ /** Map of tool preset alias → tool names for --tools flag resolution. */
62
55
  const TOOL_PRESETS = {
63
- readonly: readOnlyTools,
64
- coding: codingTools,
56
+ readonly: READONLY_TOOL_NAMES,
57
+ coding: CODING_TOOL_NAMES,
65
58
  none: [],
66
59
  };
67
60
  /** All valid tool names and aliases for error messages. */
68
- const VALID_TOOL_NAMES = [...Object.keys(TOOL_MAP), ...Object.keys(TOOL_PRESETS)];
61
+ const VALID_TOOL_NAMES = [...INDIVIDUAL_TOOL_NAMES, ...Object.keys(TOOL_PRESETS)];
69
62
  /**
70
- * Parse a comma-separated tool names string into an array of tool objects.
63
+ * Parse a comma-separated tool names string into an array of tool names.
71
64
  *
72
65
  * Accepts individual tool names (read, bash, edit, write, grep, find, ls)
73
66
  * and preset aliases (readonly, coding, none).
74
67
  *
75
68
  * @param toolString - Comma-separated tool names (e.g. "read,grep,find")
76
- * @returns Array of resolved tool objects
69
+ * @returns Array of resolved tool names
77
70
  * @throws Error with list of valid names when an unknown tool is specified
78
71
  */
79
72
  export function parseToolFlag(toolString) {
@@ -88,14 +81,16 @@ export function parseToolFlag(toolString) {
88
81
  if (names.length === 1 && names[0] in TOOL_PRESETS) {
89
82
  return [...TOOL_PRESETS[names[0]]];
90
83
  }
91
- const tools = [];
84
+ const tools = new Set();
92
85
  const unknown = [];
93
86
  for (const name of names) {
94
- if (name in TOOL_MAP) {
95
- tools.push(TOOL_MAP[name]);
87
+ if (INDIVIDUAL_TOOL_NAMES.includes(name)) {
88
+ tools.add(name);
96
89
  }
97
90
  else if (name in TOOL_PRESETS) {
98
- tools.push(...TOOL_PRESETS[name]);
91
+ for (const toolName of TOOL_PRESETS[name]) {
92
+ tools.add(toolName);
93
+ }
99
94
  }
100
95
  else {
101
96
  unknown.push(name);
@@ -104,15 +99,26 @@ export function parseToolFlag(toolString) {
104
99
  if (unknown.length > 0) {
105
100
  throw new Error(`Unknown tool(s): ${unknown.join(", ")}. Valid names: ${VALID_TOOL_NAMES.join(", ")}`);
106
101
  }
107
- return tools;
102
+ return [...tools].sort((a, b) => a.localeCompare(b));
103
+ }
104
+ /**
105
+ * Extract tool names from the session tool allowlist.
106
+ *
107
+ * @param tools - Tool names from session options
108
+ * @returns Sorted unique tool names
109
+ */
110
+ function extractConfiguredToolNames(tools) {
111
+ if (!tools)
112
+ return [];
113
+ return [...new Set(tools)].sort((a, b) => a.localeCompare(b));
108
114
  }
109
115
  /**
110
- * Extract tool names from a tool-definition array.
116
+ * Extract tool names from custom tool definitions.
111
117
  *
112
118
  * @param tools - Tool definitions from session options
113
119
  * @returns Sorted unique tool names
114
120
  */
115
- function extractToolNames(tools) {
121
+ function extractCustomToolNames(tools) {
116
122
  if (!tools)
117
123
  return [];
118
124
  const names = new Set();
@@ -137,8 +143,8 @@ function extractToolNames(tools) {
137
143
  function resolveExplicitToolRestrictionNames(options) {
138
144
  if (options.tools === undefined)
139
145
  return null;
140
- const names = new Set(extractToolNames(options.tools));
141
- for (const name of extractToolNames(options.customTools)) {
146
+ const names = new Set(extractConfiguredToolNames(options.tools));
147
+ for (const name of extractCustomToolNames(options.customTools)) {
142
148
  names.add(name);
143
149
  }
144
150
  return [...names].sort((a, b) => a.localeCompare(b));
@@ -967,14 +973,41 @@ function applyExtensionStartupPolicies(base, options) {
967
973
  * await session.prompt("Fix the failing tests");
968
974
  * ```
969
975
  */
976
+ /**
977
+ * Apply tallow runtime setting overrides that must be consistent across initial
978
+ * startup and runtime-backed session recreation.
979
+ *
980
+ * @param settingsManager - Settings manager to mutate
981
+ * @param runtimeSettings - Optional runtime settings overrides from SDK/CLI
982
+ * @param trustStatus - Effective project trust status for the target cwd
983
+ * @returns Nothing
984
+ */
985
+ function applySessionSettingsOverrides(settingsManager, runtimeSettings, trustStatus) {
986
+ const global = settingsManager.getGlobalSettings();
987
+ const project = settingsManager.getProjectSettings();
988
+ if (global.quietStartup === undefined && project.quietStartup === undefined) {
989
+ settingsManager.applyOverrides({ quietStartup: true });
990
+ }
991
+ if (runtimeSettings) {
992
+ settingsManager.applyOverrides(runtimeSettings);
993
+ }
994
+ if (trustStatus !== "trusted") {
995
+ const globalPackages = settingsManager.getGlobalSettings().packages;
996
+ settingsManager.applyOverrides({
997
+ packages: (Array.isArray(globalPackages) ? globalPackages : []),
998
+ });
999
+ }
1000
+ }
970
1001
  export async function createTallowSession(options = {}) {
971
1002
  const startupProfile = normalizeStartupProfile(options.startupProfile);
972
1003
  const startupTiming = createStartupTimingLogger(startupProfile);
973
1004
  const createSessionStartedAtMs = Date.now();
1005
+ const callerCwd = process.cwd();
974
1006
  // Ensure env is configured before any framework internals resolve paths
975
1007
  bootstrap();
976
1008
  ensureTallowHome(startupProfile);
977
1009
  if (startupProfile === "interactive") {
1010
+ await applyPiTuiPatches();
978
1011
  await applyInteractiveModeStaleUiPatch();
979
1012
  }
980
1013
  await applyAgentSessionCompactionCancelPatch();
@@ -1015,26 +1048,7 @@ export async function createTallowSession(options = {}) {
1015
1048
  }
1016
1049
  // ── Settings ─────────────────────────────────────────────────────────────
1017
1050
  const settingsManager = SettingsManager.create(cwd, tallowHome);
1018
- // Default to quiet startup — the welcome-screen extension provides the branded
1019
- // header, so the built-in keybinding list and resource listing are redundant.
1020
- // Only apply when the user/project settings haven't explicitly set the value.
1021
- {
1022
- const global = settingsManager.getGlobalSettings();
1023
- const project = settingsManager.getProjectSettings();
1024
- if (global.quietStartup === undefined && project.quietStartup === undefined) {
1025
- settingsManager.applyOverrides({ quietStartup: true });
1026
- }
1027
- }
1028
- // Runtime overrides from options.settings come last so they win.
1029
- if (options.settings) {
1030
- settingsManager.applyOverrides(options.settings);
1031
- }
1032
- if (projectTrust.status !== "trusted") {
1033
- const globalPackages = settingsManager.getGlobalSettings().packages;
1034
- settingsManager.applyOverrides({
1035
- packages: (Array.isArray(globalPackages) ? globalPackages : []),
1036
- });
1037
- }
1051
+ applySessionSettingsOverrides(settingsManager, options.settings, projectTrust.status);
1038
1052
  const toolResultRetentionPolicy = resolveToolResultRetentionPolicy({
1039
1053
  globalSettings: settingsManager.getGlobalSettings(),
1040
1054
  projectSettings: settingsManager.getProjectSettings(),
@@ -1143,9 +1157,6 @@ export async function createTallowSession(options = {}) {
1143
1157
  // ── Package AGENTS.md loading ────────────────────────────────────────────
1144
1158
  // Packages contribute extensions, skills, prompts, themes — but the framework
1145
1159
  // doesn't load AGENTS.md from packages. Use agentsFilesOverride to inject them.
1146
- const packageAgentsFiles = loadAgentsFilesFromPackages(settingsManager, cwd);
1147
- const projectExtensionsDir = resolve(cwd, ".tallow", "extensions");
1148
- const shouldBlockProjectExtensions = projectTrust.status !== "trusted";
1149
1160
  if (projectTrust.status !== "trusted") {
1150
1161
  console.error(projectTrust.status === "stale_fingerprint"
1151
1162
  ? "\x1b[33m⚠ Project trust is stale — repo-controlled execution surfaces are blocked until /trust-project\x1b[0m"
@@ -1153,72 +1164,137 @@ export async function createTallowSession(options = {}) {
1153
1164
  }
1154
1165
  const dedupedExtensionPaths = [...new Set(additionalExtensionPaths)];
1155
1166
  const disabledExtensionNames = new Set(options.disabledExtensions ?? []);
1156
- const shouldApplyExtensionStartupPolicies = shouldBlockProjectExtensions ||
1157
- startupProfile === "headless" ||
1158
- disabledExtensionNames.size > 0;
1159
1167
  const explicitToolRestrictionNames = resolveExplicitToolRestrictionNames(options);
1160
- const loader = new DefaultResourceLoader({
1161
- cwd,
1162
- agentDir: tallowHome,
1163
- settingsManager,
1164
- eventBus,
1165
- additionalExtensionPaths: dedupedExtensionPaths,
1166
- additionalSkillPaths,
1167
- additionalPromptTemplatePaths: additionalPromptPaths,
1168
- additionalThemePaths,
1169
- extensionFactories: [
1170
- createRebrandSystemPromptExtension(contextBudgetPolicy),
1171
- injectImageFilePaths,
1172
- createToolResultRetentionExtension(toolResultRetentionPolicy, contextBudgetPolicy),
1173
- createContextBudgetPlannerExtension(contextBudgetPolicy),
1174
- detectOutputTruncation,
1175
- createProjectTrustExtension(cwd, projectTrust),
1176
- createTelemetryExtension(telemetry, cwd),
1177
- ...(explicitToolRestrictionNames
1178
- ? [createExplicitToolRestrictionExtension(explicitToolRestrictionNames)]
1179
- : []),
1180
- ...(options.extensionFactories ?? []),
1181
- ],
1182
- noExtensions: extensionsOnly,
1183
- extensionsOverride: shouldApplyExtensionStartupPolicies
1184
- ? (base) => applyExtensionStartupPolicies(base, {
1185
- blockProjectExtensions: shouldBlockProjectExtensions,
1186
- disabledExtensionNames,
1187
- projectExtensionsDir,
1188
- startupProfile,
1189
- })
1190
- : undefined,
1191
- systemPromptOverride: options.systemPrompt ? () => options.systemPrompt : undefined,
1192
- appendSystemPromptOverride: options.appendSystemPrompt
1193
- ? (base) => {
1194
- const append = options.appendSystemPrompt;
1195
- return append ? [...base, append] : base;
1196
- }
1197
- : undefined,
1198
- agentsFilesOverride: packageAgentsFiles.length > 0
1199
- ? (base) => ({
1200
- agentsFiles: [...base.agentsFiles, ...packageAgentsFiles],
1201
- })
1202
- : undefined,
1203
- skillsOverride: (base) => {
1204
- const normalized = normalizeSkillNames(base);
1205
- const extra = options.additionalSkills;
1206
- return {
1207
- skills: extra ? [...normalized.skills, ...extra] : normalized.skills,
1208
- diagnostics: normalized.diagnostics,
1209
- };
1210
- },
1211
- promptsOverride: options.additionalPrompts
1212
- ? (base) => {
1213
- const extra = options.additionalPrompts;
1168
+ /**
1169
+ * Create a runtime-backed session for the given cwd/session target.
1170
+ *
1171
+ * @param runtimeCwd - Effective session cwd
1172
+ * @param runtimeSessionManager - Session manager to attach
1173
+ * @param sessionStartEvent - Optional lifecycle metadata for replacement flows
1174
+ * @returns Created session, extension load result, and runtime services
1175
+ */
1176
+ const createRuntime = async ({ cwd: runtimeCwd, sessionManager: runtimeSessionManager, sessionStartEvent, }) => {
1177
+ const runtimeProjectTrust = resolveProjectTrust(runtimeCwd);
1178
+ applyProjectTrustContextToEnv(runtimeProjectTrust);
1179
+ const runtimeSettingsManager = SettingsManager.create(runtimeCwd, tallowHome);
1180
+ applySessionSettingsOverrides(runtimeSettingsManager, options.settings, runtimeProjectTrust.status);
1181
+ const runtimePackageAgentsFiles = loadAgentsFilesFromPackages(runtimeSettingsManager, runtimeCwd);
1182
+ const runtimeProjectExtensionsDir = resolve(runtimeCwd, ".tallow", "extensions");
1183
+ const runtimeShouldBlockProjectExtensions = runtimeProjectTrust.status !== "trusted";
1184
+ const runtimeShouldApplyExtensionStartupPolicies = runtimeShouldBlockProjectExtensions ||
1185
+ startupProfile === "headless" ||
1186
+ disabledExtensionNames.size > 0;
1187
+ const runtimeLoader = new DefaultResourceLoader({
1188
+ cwd: runtimeCwd,
1189
+ agentDir: tallowHome,
1190
+ settingsManager: runtimeSettingsManager,
1191
+ eventBus,
1192
+ additionalExtensionPaths: dedupedExtensionPaths,
1193
+ additionalSkillPaths,
1194
+ additionalPromptTemplatePaths: additionalPromptPaths,
1195
+ additionalThemePaths,
1196
+ extensionFactories: [
1197
+ createRebrandSystemPromptExtension(contextBudgetPolicy),
1198
+ createToolResultRetentionExtension(toolResultRetentionPolicy, contextBudgetPolicy),
1199
+ createContextBudgetPlannerExtension(contextBudgetPolicy),
1200
+ detectOutputTruncation,
1201
+ createProjectTrustExtension(runtimeCwd, runtimeProjectTrust),
1202
+ createTelemetryExtension(telemetry, runtimeCwd),
1203
+ ...(explicitToolRestrictionNames
1204
+ ? [createExplicitToolRestrictionExtension(explicitToolRestrictionNames)]
1205
+ : []),
1206
+ ...(options.extensionFactories ?? []),
1207
+ ],
1208
+ noExtensions: extensionsOnly,
1209
+ extensionsOverride: runtimeShouldApplyExtensionStartupPolicies
1210
+ ? (base) => applyExtensionStartupPolicies(base, {
1211
+ blockProjectExtensions: runtimeShouldBlockProjectExtensions,
1212
+ disabledExtensionNames,
1213
+ projectExtensionsDir: runtimeProjectExtensionsDir,
1214
+ startupProfile,
1215
+ })
1216
+ : undefined,
1217
+ systemPromptOverride: options.systemPrompt ? () => options.systemPrompt : undefined,
1218
+ appendSystemPromptOverride: options.appendSystemPrompt
1219
+ ? (base) => {
1220
+ const append = options.appendSystemPrompt;
1221
+ return append ? [...base, append] : base;
1222
+ }
1223
+ : undefined,
1224
+ agentsFilesOverride: runtimePackageAgentsFiles.length > 0
1225
+ ? (base) => ({
1226
+ agentsFiles: [...base.agentsFiles, ...runtimePackageAgentsFiles],
1227
+ })
1228
+ : undefined,
1229
+ skillsOverride: (base) => {
1230
+ const normalized = normalizeSkillNames(base);
1231
+ const extra = options.additionalSkills;
1214
1232
  return {
1215
- prompts: extra ? [...base.prompts, ...extra] : base.prompts,
1216
- diagnostics: base.diagnostics,
1233
+ skills: extra ? [...normalized.skills, ...extra] : normalized.skills,
1234
+ diagnostics: normalized.diagnostics,
1217
1235
  };
1236
+ },
1237
+ promptsOverride: options.additionalPrompts
1238
+ ? (base) => {
1239
+ const extra = options.additionalPrompts;
1240
+ return {
1241
+ prompts: extra ? [...base.prompts, ...extra] : base.prompts,
1242
+ diagnostics: base.diagnostics,
1243
+ };
1244
+ }
1245
+ : undefined,
1246
+ });
1247
+ await runtimeLoader.reload();
1248
+ applySessionSettingsOverrides(runtimeSettingsManager, options.settings, runtimeProjectTrust.status);
1249
+ let resolvedModel = options.model;
1250
+ if (!resolvedModel && options.provider) {
1251
+ const modelId = options.modelId ?? runtimeSettingsManager.getDefaultModel();
1252
+ if (modelId) {
1253
+ resolvedModel = modelRegistry.find(options.provider, modelId) ?? undefined;
1254
+ if (!resolvedModel) {
1255
+ throw new Error(`Model ${options.provider}/${modelId} not found`);
1256
+ }
1218
1257
  }
1219
- : undefined,
1220
- });
1221
- await loader.reload();
1258
+ else {
1259
+ const available = modelRegistry.getAll().filter((m) => m.provider === options.provider);
1260
+ if (available.length === 0) {
1261
+ throw new Error(`No models found for provider "${options.provider}"`);
1262
+ }
1263
+ resolvedModel = available[0];
1264
+ }
1265
+ }
1266
+ const result = await createAgentSession({
1267
+ cwd: runtimeCwd,
1268
+ agentDir: tallowHome,
1269
+ model: resolvedModel,
1270
+ thinkingLevel: options.thinkingLevel,
1271
+ authStorage,
1272
+ modelRegistry,
1273
+ resourceLoader: runtimeLoader,
1274
+ sessionManager: runtimeSessionManager,
1275
+ settingsManager: runtimeSettingsManager,
1276
+ tools: options.tools,
1277
+ customTools: options.customTools,
1278
+ sessionStartEvent,
1279
+ });
1280
+ if (explicitToolRestrictionNames) {
1281
+ const sessionWithToolControl = result.session;
1282
+ sessionWithToolControl.setActiveToolsByName?.(explicitToolRestrictionNames);
1283
+ }
1284
+ return {
1285
+ ...result,
1286
+ diagnostics: [],
1287
+ services: {
1288
+ agentDir: tallowHome,
1289
+ authStorage,
1290
+ cwd: runtimeCwd,
1291
+ diagnostics: [],
1292
+ modelRegistry,
1293
+ resourceLoader: runtimeLoader,
1294
+ settingsManager: runtimeSettingsManager,
1295
+ },
1296
+ };
1297
+ };
1222
1298
  // ── Session Manager ──────────────────────────────────────────────────────
1223
1299
  let sessionManager;
1224
1300
  const sessionOpt = options.session ?? { type: "new" };
@@ -1259,49 +1335,35 @@ export async function createTallowSession(options = {}) {
1259
1335
  break;
1260
1336
  }
1261
1337
  }
1262
- // ── Model resolution (string Model object) ────────────────────────────
1263
- let resolvedModel = options.model;
1264
- if (!resolvedModel && options.provider) {
1265
- const modelId = options.modelId ?? settingsManager.getDefaultModel();
1266
- if (modelId) {
1267
- resolvedModel = modelRegistry.find(options.provider, modelId) ?? undefined;
1268
- if (!resolvedModel) {
1269
- throw new Error(`Model ${options.provider}/${modelId} not found`);
1270
- }
1338
+ const initialSessionStartEvent = sessionOpt.type === "continue" || sessionOpt.type === "open" || sessionOpt.type === "resume"
1339
+ ? {
1340
+ type: "session_start",
1341
+ reason: "resume",
1342
+ previousSessionFile: sessionManager.getSessionFile(),
1271
1343
  }
1272
- else {
1273
- // Provider without model: find any available model for this provider
1274
- const available = modelRegistry.getAll().filter((m) => m.provider === options.provider);
1275
- if (available.length === 0) {
1276
- throw new Error(`No models found for provider "${options.provider}"`);
1277
- }
1278
- resolvedModel = available[0];
1279
- }
1280
- }
1281
- // ── Create Session ───────────────────────────────────────────────────────
1282
- const result = await createAgentSession({
1344
+ : undefined;
1345
+ const runtime = await createAgentSessionRuntime(({ cwd: runtimeCwd, sessionManager: runtimeSessionManager, sessionStartEvent }) => createRuntime({
1346
+ cwd: runtimeCwd,
1347
+ sessionManager: runtimeSessionManager,
1348
+ sessionStartEvent,
1349
+ }), {
1283
1350
  cwd,
1284
1351
  agentDir: tallowHome,
1285
- model: resolvedModel,
1286
- thinkingLevel: options.thinkingLevel,
1287
- authStorage,
1288
- modelRegistry,
1289
- resourceLoader: loader,
1290
1352
  sessionManager,
1291
- settingsManager,
1292
- tools: options.tools,
1293
- customTools: options.customTools,
1353
+ sessionStartEvent: initialSessionStartEvent,
1294
1354
  });
1295
- if (explicitToolRestrictionNames) {
1296
- const sessionWithToolControl = result.session;
1297
- sessionWithToolControl.setActiveToolsByName?.(explicitToolRestrictionNames);
1355
+ if (process.cwd() !== callerCwd) {
1356
+ process.chdir(callerCwd);
1298
1357
  }
1299
1358
  startupTiming.mark("create-session", createSessionStartedAtMs);
1300
- instrumentSessionStartupTimings(result.session, startupTiming);
1359
+ instrumentSessionStartupTimings(runtime.session, startupTiming);
1301
1360
  return {
1302
- session: result.session,
1303
- extensions: result.extensionsResult,
1304
- modelFallbackMessage: result.modelFallbackMessage,
1361
+ runtime,
1362
+ get session() {
1363
+ return runtime.session;
1364
+ },
1365
+ extensions: runtime.services.resourceLoader.getExtensions(),
1366
+ modelFallbackMessage: runtime.modelFallbackMessage,
1305
1367
  version: TALLOW_VERSION,
1306
1368
  extensionOverrides,
1307
1369
  resolvedPlugins,
@@ -1679,29 +1741,6 @@ function createRebrandSystemPromptExtension(budgetPolicy) {
1679
1741
  });
1680
1742
  };
1681
1743
  }
1682
- /**
1683
- * Injects file paths into Image components for clickable OSC 8 links.
1684
- * When the read tool returns an image, sets the pending file path so
1685
- * the next Image constructor picks it up automatically.
1686
- *
1687
- * @param pi - Extension API
1688
- */
1689
- function injectImageFilePaths(pi) {
1690
- pi.on("tool_result", async (event) => {
1691
- if (event.toolName !== "read")
1692
- return;
1693
- const hasImage = event.content?.some((c) => c.type === "image");
1694
- if (hasImage && event.input?.path) {
1695
- const filePath = resolve(String(event.input.path));
1696
- // pi-tui >= 0.55 may not expose this helper; skip injection when unavailable.
1697
- const maybeSetNextImageFilePath = PiTui
1698
- .setNextImageFilePath;
1699
- if (typeof maybeSetNextImageFilePath === "function") {
1700
- maybeSetNextImageFilePath(filePath);
1701
- }
1702
- }
1703
- });
1704
- }
1705
1744
  /**
1706
1745
  * Create a built-in extension that summarizes oversized historical tool results.
1707
1746
  *
@@ -1897,7 +1936,7 @@ function truncateTextToBytes(text, maxBytes) {
1897
1936
  * message content and allocates a budget envelope for each one, keyed
1898
1937
  * by toolCallId. Envelopes are single-use (consumed via the API) and
1899
1938
  * automatically cleaned up on turn_end, agent_end, session_before_switch,
1900
- * and session_switch events.
1939
+ * and post-transition session_start events.
1901
1940
  *
1902
1941
  * @param budgetPolicy - Resolved context-budget policy
1903
1942
  * @returns Extension factory
@@ -2003,6 +2042,7 @@ function createContextBudgetPlannerExtension(budgetPolicy) {
2003
2042
  },
2004
2043
  };
2005
2044
  pi.on("session_start", async () => {
2045
+ clearEnvelopes();
2006
2046
  publishBudgetApi();
2007
2047
  });
2008
2048
  pi.events.on(CONTEXT_BUDGET_API_CHANNELS.budgetApiRequest, () => {
@@ -2017,9 +2057,6 @@ function createContextBudgetPlannerExtension(budgetPolicy) {
2017
2057
  pi.on("session_before_switch", async () => {
2018
2058
  clearEnvelopes();
2019
2059
  });
2020
- pi.on("session_switch", async () => {
2021
- clearEnvelopes();
2022
- });
2023
2060
  };
2024
2061
  }
2025
2062
  /**