lsd-pi 1.3.6 → 1.3.9
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.
- package/README.md +82 -0
- package/dist/cli.js +2 -1
- package/dist/lsd-settings-manager.d.ts +2 -0
- package/dist/lsd-settings-manager.js +5 -0
- package/dist/resource-loader.js +33 -3
- package/dist/resources/extensions/cache-timer/index.js +3 -2
- package/dist/resources/extensions/mcp-client/index.js +72 -4
- package/dist/resources/extensions/slash-commands/plan.js +5 -5
- package/dist/resources/extensions/usage/index.js +34 -2
- package/dist/resources/extensions/voice/index.js +1 -0
- package/dist/resources/extensions/voice/push-to-talk.js +2 -0
- package/dist/welcome-screen.js +2 -2
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.context-usage.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session.context-usage.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.context-usage.test.js +72 -0
- package/packages/pi-coding-agent/dist/core/agent-session.context-usage.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +4 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +29 -2
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.collapse-tool-calls.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.collapse-tool-calls.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.collapse-tool-calls.test.js +35 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.collapse-tool-calls.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +6 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +12 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tool-priority.js +1 -1
- package/packages/pi-coding-agent/dist/core/tool-priority.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.js +21 -0
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +16 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +1 -0
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.js +12 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +7 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +86 -28
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +16 -10
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +26 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +16 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +128 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.js +48 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.js +137 -6
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +64 -15
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +5 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +73 -27
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +4 -4
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +3 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.context-usage.test.ts +87 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +40 -2
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +1 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +3 -0
- package/packages/pi-coding-agent/src/core/settings-manager.collapse-tool-calls.test.ts +46 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +18 -0
- package/packages/pi-coding-agent/src/core/tool-priority.ts +1 -1
- package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +20 -0
- package/packages/pi-coding-agent/src/core/tools/edit-diff.ts +26 -0
- package/packages/pi-coding-agent/src/main.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-summary-line.test.ts +14 -4
- package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +105 -28
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +13 -6
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +31 -4
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +137 -14
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-summary-line.ts +60 -4
- package/packages/pi-coding-agent/src/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.ts +174 -6
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +73 -15
- package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +2 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +76 -27
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +4 -4
- package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +4 -0
- package/packages/pi-tui/dist/components/editor.js +3 -3
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/src/components/editor.ts +3 -3
- package/pkg/dist/modes/interactive/theme/themes.js +4 -4
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/cache-timer/index.ts +3 -2
- package/src/resources/extensions/mcp-client/index.ts +83 -4
- package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +16 -0
- package/src/resources/extensions/slash-commands/plan.ts +6 -6
- package/src/resources/extensions/usage/index.ts +40 -2
- package/src/resources/extensions/voice/index.ts +1 -0
- package/src/resources/extensions/voice/push-to-talk.ts +3 -0
- package/src/resources/extensions/voice/tests/push-to-talk.test.ts +6 -0
|
@@ -452,15 +452,15 @@ export class Editor implements Component, Focusable {
|
|
|
452
452
|
const remaining = width - visibleWidth(indicator);
|
|
453
453
|
result.push(this.borderColor(indicator + "─".repeat(Math.max(0, remaining))));
|
|
454
454
|
} else if (this.bottomHint) {
|
|
455
|
-
// Embed hint right
|
|
455
|
+
// Embed hint at far right in bottom border: ─────────────── hint ─
|
|
456
456
|
// Apply borderColor only to the dashes so the hint's own styling is preserved.
|
|
457
457
|
const hintVisible = visibleWidth(this.bottomHint);
|
|
458
458
|
const minDashes = 1;
|
|
459
459
|
const separatorWidth = 1; // single space on each side of hint
|
|
460
460
|
const totalFixed = hintVisible + separatorWidth * 2 + minDashes * 2;
|
|
461
461
|
if (width >= totalFixed) {
|
|
462
|
-
const
|
|
463
|
-
const
|
|
462
|
+
const rightDashes = minDashes;
|
|
463
|
+
const leftDashes = Math.max(minDashes, width - hintVisible - separatorWidth * 2 - rightDashes);
|
|
464
464
|
const line =
|
|
465
465
|
this.borderColor("─".repeat(leftDashes)) +
|
|
466
466
|
" " +
|
|
@@ -69,8 +69,8 @@ const dark = {
|
|
|
69
69
|
mdQuoteBorder: "gray",
|
|
70
70
|
mdHr: "gray",
|
|
71
71
|
mdListBullet: "accent",
|
|
72
|
-
toolDiffAdded: "
|
|
73
|
-
toolDiffRemoved: "
|
|
72
|
+
toolDiffAdded: "#4ade80",
|
|
73
|
+
toolDiffRemoved: "#fb7185",
|
|
74
74
|
toolDiffContext: "gray",
|
|
75
75
|
syntaxComment: "#6A9955",
|
|
76
76
|
syntaxKeyword: "#569CD6",
|
|
@@ -157,8 +157,8 @@ const light = {
|
|
|
157
157
|
mdQuoteBorder: "mediumGray",
|
|
158
158
|
mdHr: "mediumGray",
|
|
159
159
|
mdListBullet: "green",
|
|
160
|
-
toolDiffAdded: "
|
|
161
|
-
toolDiffRemoved: "
|
|
160
|
+
toolDiffAdded: "#15803d",
|
|
161
|
+
toolDiffRemoved: "#b91c1c",
|
|
162
162
|
toolDiffContext: "mediumGray",
|
|
163
163
|
syntaxComment: "#008000",
|
|
164
164
|
syntaxKeyword: "#0000FF",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"themes.js","sourceRoot":"","sources":["../../../../src/modes/interactive/theme/themes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E,MAAM,IAAI,GAAc;IACvB,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,SAAS;QACd,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,SAAS;QACjB,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,SAAS;QAClB,QAAQ,EAAE,SAAS;QACnB,MAAM,EAAE,SAAS;QACjB,SAAS,EAAE,SAAS;QACpB,OAAO,EAAE,SAAS;QAClB,UAAU,EAAE,SAAS;QACrB,QAAQ,EAAE,SAAS;QACnB,SAAS,EAAE,SAAS;QACpB,UAAU,EAAE,SAAS;QACrB,SAAS,EAAE,SAAS;QACpB,aAAa,EAAE,SAAS;QACxB,aAAa,EAAE,SAAS;QACxB,WAAW,EAAE,SAAS;QACtB,WAAW,EAAE,SAAS;KACtB;IACD,MAAM,EAAE;QACP,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE,MAAM;QACd,YAAY,EAAE,MAAM;QACpB,WAAW,EAAE,MAAM;QACnB,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,KAAK;QACZ,OAAO,EAAE,QAAQ;QACjB,MAAM,EAAE,QAAQ;QAChB,KAAK,EAAE,MAAM;QACb,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,EAAE;QACR,YAAY,EAAE,MAAM;QAEpB,UAAU,EAAE,YAAY;QACxB,aAAa,EAAE,WAAW;QAC1B,eAAe,EAAE,EAAE;QACnB,eAAe,EAAE,aAAa;QAC9B,iBAAiB,EAAE,EAAE;QACrB,kBAAkB,EAAE,SAAS;QAC7B,aAAa,EAAE,eAAe;QAC9B,aAAa,EAAE,eAAe;QAC9B,WAAW,EAAE,aAAa;QAC1B,SAAS,EAAE,EAAE;QACb,UAAU,EAAE,MAAM;QAElB,SAAS,EAAE,SAAS;QACpB,MAAM,EAAE,SAAS;QACjB,SAAS,EAAE,SAAS;QACpB,MAAM,EAAE,QAAQ;QAChB,WAAW,EAAE,OAAO;QACpB,iBAAiB,EAAE,MAAM;QACzB,OAAO,EAAE,MAAM;QACf,aAAa,EAAE,MAAM;QACrB,IAAI,EAAE,MAAM;QACZ,YAAY,EAAE,QAAQ;QAEtB,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"themes.js","sourceRoot":"","sources":["../../../../src/modes/interactive/theme/themes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Built-in theme definitions.\n *\n * Each theme is a self-contained record of color values. Variable references\n * (e.g. \"accent\") are resolved against the `vars` map at load time by the\n * theme engine in theme.ts.\n *\n * To add a new built-in theme, add an entry to `builtinThemes` below.\n */\n\n// Re-use the ThemeJson type from the schema defined in theme.ts.\n// We import only the type to avoid circular runtime dependencies.\nimport type { ThemeJson } from \"./theme.js\";\n\n// ---------------------------------------------------------------------------\n// Dark theme\n// ---------------------------------------------------------------------------\n\nconst dark: ThemeJson = {\n\tname: \"dark\",\n\tvars: {\n\t\tcyan: \"#4a8cf7\",\n\t\tblue: \"#4a8cf7\",\n\t\tgreen: \"#b5bd68\",\n\t\tred: \"#cc6666\",\n\t\tyellow: \"#facc15\",\n\t\tviolet: \"#a78bfa\",\n\t\tgray: \"#bec8d6\",\n\t\tdimGray: \"#8793a3\",\n\t\tdarkGray: \"#505050\",\n\t\taccent: \"#60a5fa\",\n\t\tblueMuted: \"#1e3a8a\",\n\t\tblueLow: \"#2563eb\",\n\t\tblueMedium: \"#4a8cf7\",\n\t\tblueHigh: \"#60a5fa\",\n\t\tblueXhigh: \"#93c5fd\",\n\t\tselectedBg: \"#323640\",\n\t\tuserMsgBg: \"#272727\",\n\t\ttoolPendingBg: \"#1e2230\",\n\t\ttoolSuccessBg: \"#1a2330\",\n\t\ttoolErrorBg: \"#2a1e30\",\n\t\tcustomMsgBg: \"#2d2838\",\n\t},\n\tcolors: {\n\t\taccent: \"accent\",\n\t\tborder: \"blue\",\n\t\tborderAccent: \"cyan\",\n\t\tborderMuted: \"blue\",\n\t\tsuccess: \"green\",\n\t\terror: \"red\",\n\t\twarning: \"yellow\",\n\t\tviolet: \"violet\",\n\t\tmuted: \"gray\",\n\t\tdim: \"dimGray\",\n\t\ttext: \"\",\n\t\tthinkingText: \"gray\",\n\n\t\tselectedBg: \"selectedBg\",\n\t\tuserMessageBg: \"userMsgBg\",\n\t\tuserMessageText: \"\",\n\t\tcustomMessageBg: \"customMsgBg\",\n\t\tcustomMessageText: \"\",\n\t\tcustomMessageLabel: \"#9575cd\",\n\t\ttoolPendingBg: \"toolPendingBg\",\n\t\ttoolSuccessBg: \"toolSuccessBg\",\n\t\ttoolErrorBg: \"toolErrorBg\",\n\t\ttoolTitle: \"\",\n\t\ttoolOutput: \"gray\",\n\n\t\tmdHeading: \"#f0c674\",\n\t\tmdLink: \"#5a8aaa\",\n\t\tmdLinkUrl: \"dimGray\",\n\t\tmdCode: \"accent\",\n\t\tmdCodeBlock: \"green\",\n\t\tmdCodeBlockBorder: \"gray\",\n\t\tmdQuote: \"gray\",\n\t\tmdQuoteBorder: \"gray\",\n\t\tmdHr: \"gray\",\n\t\tmdListBullet: \"accent\",\n\n\t\ttoolDiffAdded: \"#4ade80\",\n\t\ttoolDiffRemoved: \"#fb7185\",\n\t\ttoolDiffContext: \"gray\",\n\n\t\tsyntaxComment: \"#6A9955\",\n\t\tsyntaxKeyword: \"#569CD6\",\n\t\tsyntaxFunction: \"#DCDCAA\",\n\t\tsyntaxVariable: \"#9CDCFE\",\n\t\tsyntaxString: \"#CE9178\",\n\t\tsyntaxNumber: \"#B5CEA8\",\n\t\tsyntaxType: \"#4EC9B0\",\n\t\tsyntaxOperator: \"#D4D4D4\",\n\t\tsyntaxPunctuation: \"#D4D4D4\",\n\n\t\tthinkingOff: \"blueMuted\",\n\t\tthinkingMinimal: \"blueLow\",\n\t\tthinkingLow: \"blueMedium\",\n\t\tthinkingMedium: \"blueHigh\",\n\t\tthinkingHigh: \"blueXhigh\",\n\t\tthinkingXhigh: \"cyan\",\n\n\t\tbashMode: \"accent\",\n\t},\n\texport: {\n\t\tpageBg: \"#18181e\",\n\t\tcardBg: \"#1e1e24\",\n\t\tinfoBg: \"#3c3728\",\n\t},\n};\n\n// ---------------------------------------------------------------------------\n// Light theme\n// ---------------------------------------------------------------------------\n\nconst light: ThemeJson = {\n\tname: \"light\",\n\tvars: {\n\t\tteal: \"#3b82f6\",\n\t\tblue: \"#547da7\",\n\t\tgreen: \"#588458\",\n\t\tred: \"#aa5555\",\n\t\tyellow: \"#eab308\",\n\t\twarning: \"#7a5a00\",\n\t\tviolet: \"#8b5cf6\",\n\t\tmediumGray: \"#6c6c6c\",\n\t\tdimGray: \"#767676\",\n\t\tlightGray: \"#b0b0b0\",\n\t\tblueMuted: \"#6b8fb8\",\n\t\tblueLow: \"#547da7\",\n\t\tblueMedium: \"#3b82f6\",\n\t\tblueHigh: \"#2563eb\",\n\t\tblueXhigh: \"#1d4ed8\",\n\t\tselectedBg: \"#d0d0e0\",\n\t\tuserMsgBg: \"#e8e8e8\",\n\t\ttoolPendingBg: \"#e8eaf0\",\n\t\ttoolSuccessBg: \"#e8f0f0\",\n\t\ttoolErrorBg: \"#f0e8ee\",\n\t\tcustomMsgBg: \"#ede7f6\",\n\t},\n\tcolors: {\n\t\taccent: \"teal\",\n\t\tborder: \"blue\",\n\t\tborderAccent: \"teal\",\n\t\tborderMuted: \"lightGray\",\n\t\tsuccess: \"green\",\n\t\terror: \"red\",\n\t\twarning: \"warning\",\n\t\tviolet: \"violet\",\n\t\tmuted: \"mediumGray\",\n\t\tdim: \"dimGray\",\n\t\ttext: \"\",\n\t\tthinkingText: \"mediumGray\",\n\n\t\tselectedBg: \"selectedBg\",\n\t\tuserMessageBg: \"userMsgBg\",\n\t\tuserMessageText: \"\",\n\t\tcustomMessageBg: \"customMsgBg\",\n\t\tcustomMessageText: \"\",\n\t\tcustomMessageLabel: \"#7e57c2\",\n\t\ttoolPendingBg: \"toolPendingBg\",\n\t\ttoolSuccessBg: \"toolSuccessBg\",\n\t\ttoolErrorBg: \"toolErrorBg\",\n\t\ttoolTitle: \"\",\n\t\ttoolOutput: \"mediumGray\",\n\n\t\tmdHeading: \"yellow\",\n\t\tmdLink: \"blue\",\n\t\tmdLinkUrl: \"dimGray\",\n\t\tmdCode: \"teal\",\n\t\tmdCodeBlock: \"green\",\n\t\tmdCodeBlockBorder: \"mediumGray\",\n\t\tmdQuote: \"mediumGray\",\n\t\tmdQuoteBorder: \"mediumGray\",\n\t\tmdHr: \"mediumGray\",\n\t\tmdListBullet: \"green\",\n\n\t\ttoolDiffAdded: \"#15803d\",\n\t\ttoolDiffRemoved: \"#b91c1c\",\n\t\ttoolDiffContext: \"mediumGray\",\n\n\t\tsyntaxComment: \"#008000\",\n\t\tsyntaxKeyword: \"#0000FF\",\n\t\tsyntaxFunction: \"#795E26\",\n\t\tsyntaxVariable: \"#001080\",\n\t\tsyntaxString: \"#A31515\",\n\t\tsyntaxNumber: \"#098658\",\n\t\tsyntaxType: \"#267F99\",\n\t\tsyntaxOperator: \"#000000\",\n\t\tsyntaxPunctuation: \"#000000\",\n\n\t\tthinkingOff: \"blueMuted\",\n\t\tthinkingMinimal: \"blueLow\",\n\t\tthinkingLow: \"blueMedium\",\n\t\tthinkingMedium: \"teal\",\n\t\tthinkingHigh: \"blueHigh\",\n\t\tthinkingXhigh: \"blueXhigh\",\n\n\t\tbashMode: \"accent\",\n\t},\n\texport: {\n\t\tpageBg: \"#f8f8f8\",\n\t\tcardBg: \"#ffffff\",\n\t\tinfoBg: \"#fffae6\",\n\t},\n};\n\n// ---------------------------------------------------------------------------\n// Export\n// ---------------------------------------------------------------------------\n\nexport const builtinThemes: Record<string, ThemeJson> = { dark, light };\n"]}
|
package/pkg/package.json
CHANGED
|
@@ -22,6 +22,7 @@ const IS_CACHE_TIMER_FORCED_OFF = process.env.LSD_DISABLE_CACHE_TIMER === "1" ||
|
|
|
22
22
|
|
|
23
23
|
// ANSI color codes for timer display
|
|
24
24
|
const ANSI_RESET = "\x1b[0m";
|
|
25
|
+
const ANSI_GREEN = "\x1b[32m";
|
|
25
26
|
const ANSI_YELLOW = "\x1b[33m";
|
|
26
27
|
const ANSI_RED = "\x1b[31m";
|
|
27
28
|
|
|
@@ -68,8 +69,8 @@ function formatElapsed(ms: number): string {
|
|
|
68
69
|
// 5–10 minutes: yellow
|
|
69
70
|
return `${ANSI_YELLOW}⏱ ${time}${ANSI_RESET}`;
|
|
70
71
|
}
|
|
71
|
-
// Under 5 minutes:
|
|
72
|
-
return
|
|
72
|
+
// Under 5 minutes: green
|
|
73
|
+
return `${ANSI_GREEN}⏱ ${time}${ANSI_RESET}`;
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
export default function cacheTimerExtension(pi: ExtensionAPI) {
|
|
@@ -62,6 +62,14 @@ interface McpState {
|
|
|
62
62
|
const connections = new Map<string, ManagedConnection>();
|
|
63
63
|
let configCache: McpServerConfig[] | null = null;
|
|
64
64
|
const toolCache = new Map<string, McpToolSchema[]>();
|
|
65
|
+
let warmupPromise: Promise<McpWarmupResult[]> | null = null;
|
|
66
|
+
|
|
67
|
+
interface McpWarmupResult {
|
|
68
|
+
name: string;
|
|
69
|
+
status: "connected" | "error";
|
|
70
|
+
toolCount?: number;
|
|
71
|
+
error?: string;
|
|
72
|
+
}
|
|
65
73
|
|
|
66
74
|
const MCP_STATE_PATH = join(process.cwd(), ".lsd", "mcp-state.json");
|
|
67
75
|
|
|
@@ -263,6 +271,49 @@ async function getOrConnect(name: string, signal?: AbortSignal): Promise<Client>
|
|
|
263
271
|
return client;
|
|
264
272
|
}
|
|
265
273
|
|
|
274
|
+
async function warmupEnabledServers(): Promise<McpWarmupResult[]> {
|
|
275
|
+
if (warmupPromise) return warmupPromise;
|
|
276
|
+
|
|
277
|
+
warmupPromise = (async () => {
|
|
278
|
+
const enabledServers = readConfigs().filter((server) => server.enabled);
|
|
279
|
+
if (enabledServers.length === 0) return [];
|
|
280
|
+
|
|
281
|
+
const results = await Promise.allSettled(enabledServers.map(async (server) => {
|
|
282
|
+
const client = await getOrConnect(server.name);
|
|
283
|
+
const result = await client.listTools(undefined, { timeout: 30000 });
|
|
284
|
+
const tools: McpToolSchema[] = (result.tools ?? []).map((tool) => ({
|
|
285
|
+
name: tool.name,
|
|
286
|
+
description: tool.description ?? "",
|
|
287
|
+
inputSchema: tool.inputSchema as Record<string, unknown> | undefined,
|
|
288
|
+
}));
|
|
289
|
+
toolCache.set(server.name, tools);
|
|
290
|
+
return {
|
|
291
|
+
name: server.name,
|
|
292
|
+
status: "connected" as const,
|
|
293
|
+
toolCount: tools.length,
|
|
294
|
+
};
|
|
295
|
+
}));
|
|
296
|
+
|
|
297
|
+
return results.map((result, index) => {
|
|
298
|
+
if (result.status === "fulfilled") {
|
|
299
|
+
return result.value;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return {
|
|
303
|
+
name: enabledServers[index]?.name ?? `server-${index + 1}`,
|
|
304
|
+
status: "error" as const,
|
|
305
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason),
|
|
306
|
+
};
|
|
307
|
+
});
|
|
308
|
+
})();
|
|
309
|
+
|
|
310
|
+
try {
|
|
311
|
+
return await warmupPromise;
|
|
312
|
+
} finally {
|
|
313
|
+
warmupPromise = null;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
266
317
|
async function closeAll(): Promise<void> {
|
|
267
318
|
const closing = Array.from(connections.entries()).map(async ([name, conn]) => {
|
|
268
319
|
try {
|
|
@@ -277,6 +328,7 @@ async function closeAll(): Promise<void> {
|
|
|
277
328
|
}
|
|
278
329
|
|
|
279
330
|
async function reloadMcpState(): Promise<void> {
|
|
331
|
+
warmupPromise = null;
|
|
280
332
|
await closeAll();
|
|
281
333
|
configCache = null;
|
|
282
334
|
}
|
|
@@ -402,6 +454,14 @@ async function handleMcpCommand(args: string, ctx: ExtensionCommandContext): Pro
|
|
|
402
454
|
const action = enabled ? "enabled" : "disabled";
|
|
403
455
|
const changeText = result.changed ? action : `already ${action}`;
|
|
404
456
|
ctx.ui.notify(`MCP server ${result.canonicalName} ${changeText}.`, "info");
|
|
457
|
+
|
|
458
|
+
if (enabled) {
|
|
459
|
+
const warmupResults = await warmupEnabledServers();
|
|
460
|
+
const warmupResult = warmupResults.find((entry) => entry.name === result.canonicalName);
|
|
461
|
+
if (warmupResult?.status === "error") {
|
|
462
|
+
ctx.ui.notify(`Failed to connect ${result.canonicalName}: ${warmupResult.error}`, "error");
|
|
463
|
+
}
|
|
464
|
+
}
|
|
405
465
|
} catch (error) {
|
|
406
466
|
const message = error instanceof Error ? error.message : String(error);
|
|
407
467
|
ctx.ui.notify(message, "error");
|
|
@@ -412,7 +472,12 @@ async function handleMcpCommand(args: string, ctx: ExtensionCommandContext): Pro
|
|
|
412
472
|
if (subcommand === "reload") {
|
|
413
473
|
await reloadMcpState();
|
|
414
474
|
const servers = readConfigs();
|
|
415
|
-
|
|
475
|
+
const warmupResults = await warmupEnabledServers();
|
|
476
|
+
const failed = warmupResults.filter((entry) => entry.status === "error");
|
|
477
|
+
const summary = failed.length > 0
|
|
478
|
+
? `Reloaded MCP config — ${servers.length} server(s) available, ${failed.length} failed to connect.`
|
|
479
|
+
: `Reloaded MCP config — ${servers.length} server(s) available.`;
|
|
480
|
+
ctx.ui.notify(summary, failed.length > 0 ? "warning" : "info");
|
|
416
481
|
return;
|
|
417
482
|
}
|
|
418
483
|
|
|
@@ -733,17 +798,31 @@ export default function(pi: ExtensionAPI) {
|
|
|
733
798
|
|
|
734
799
|
pi.on("session_start", async (_event, ctx) => {
|
|
735
800
|
const servers = readConfigs();
|
|
801
|
+
const enabledServers = servers.filter((server) => server.enabled);
|
|
736
802
|
if (servers.length > 0) {
|
|
737
|
-
ctx.ui.notify(`MCP client ready — ${
|
|
803
|
+
ctx.ui.notify(`MCP client ready — ${enabledServers.length}/${servers.length} server(s) enabled`, "info");
|
|
738
804
|
}
|
|
805
|
+
if (enabledServers.length === 0) return;
|
|
806
|
+
|
|
807
|
+
void warmupEnabledServers().then((results) => {
|
|
808
|
+
const failed = results.filter((entry) => entry.status === "error");
|
|
809
|
+
if (failed.length > 0) {
|
|
810
|
+
const failureSummary = failed.map((entry) => `${entry.name}: ${entry.error}`).join("; ");
|
|
811
|
+
ctx.ui.notify(`MCP autoconnect partial failure — ${failureSummary}`, "warning");
|
|
812
|
+
}
|
|
813
|
+
}).catch((error) => {
|
|
814
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
815
|
+
ctx.ui.notify(`MCP autoconnect failed: ${message}`, "warning");
|
|
816
|
+
});
|
|
739
817
|
});
|
|
740
818
|
|
|
741
819
|
pi.on("session_shutdown", async () => {
|
|
820
|
+
warmupPromise = null;
|
|
742
821
|
await closeAll();
|
|
743
822
|
});
|
|
744
823
|
|
|
745
824
|
pi.on("session_switch", async () => {
|
|
746
|
-
await
|
|
747
|
-
|
|
825
|
+
await reloadMcpState();
|
|
826
|
+
void warmupEnabledServers();
|
|
748
827
|
});
|
|
749
828
|
}
|
|
@@ -53,3 +53,19 @@ test("#3029: getOrConnect normalizes name for connection cache lookup", () => {
|
|
|
53
53
|
"getOrConnect should use config.name (canonical) as the connections cache key",
|
|
54
54
|
);
|
|
55
55
|
});
|
|
56
|
+
|
|
57
|
+
test("enabled MCP servers are warmed up on session start", () => {
|
|
58
|
+
assert.match(
|
|
59
|
+
source,
|
|
60
|
+
/pi\.on\("session_start", async \(_event, ctx\) => {[\s\S]*?warmupEnabledServers\(/,
|
|
61
|
+
"session_start should trigger MCP autoconnect warmup for enabled servers",
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("warmupEnabledServers preloads tool schemas during autoconnect", () => {
|
|
66
|
+
assert.match(
|
|
67
|
+
source,
|
|
68
|
+
/async function warmupEnabledServers\([\s\S]*?client\.listTools\(undefined, \{ timeout: 30000 \}\)[\s\S]*?toolCache\.set\(/,
|
|
69
|
+
"warmupEnabledServers should list tools and populate tool cache during startup",
|
|
70
|
+
);
|
|
71
|
+
});
|
|
@@ -191,8 +191,8 @@ function readAutoSwitchPlanModelSetting(): boolean {
|
|
|
191
191
|
const settingsPath = join(getAgentDir(), "settings.json");
|
|
192
192
|
if (!existsSync(settingsPath)) return false;
|
|
193
193
|
const raw = readFileSync(settingsPath, "utf-8");
|
|
194
|
-
const parsed = JSON.parse(raw) as {
|
|
195
|
-
return parsed.
|
|
194
|
+
const parsed = JSON.parse(raw) as { planModeAutoSwitchModel?: unknown };
|
|
195
|
+
return parsed.planModeAutoSwitchModel === true;
|
|
196
196
|
} catch {
|
|
197
197
|
return false;
|
|
198
198
|
}
|
|
@@ -418,10 +418,10 @@ async function approvePlan(
|
|
|
418
418
|
permissionMode: RestorablePermissionMode,
|
|
419
419
|
executeWithSubagent = false,
|
|
420
420
|
): Promise<void> {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
421
|
+
// Do NOT switch to reasoning model during execution.
|
|
422
|
+
// The reasoning model is only for plan-mode investigation, not execution.
|
|
423
|
+
// If a coding model is configured and we're using a subagent, the explicit
|
|
424
|
+
// model="<planModeCodingModel>" in the kickoff message will handle it.
|
|
425
425
|
|
|
426
426
|
state = {
|
|
427
427
|
...state,
|
|
@@ -75,6 +75,8 @@ type UsageRow = {
|
|
|
75
75
|
cacheWrite: number;
|
|
76
76
|
total: number;
|
|
77
77
|
cost: number;
|
|
78
|
+
totalDurationMs: number;
|
|
79
|
+
totalOutputForSpeed: number;
|
|
78
80
|
};
|
|
79
81
|
|
|
80
82
|
type UsageReport = {
|
|
@@ -313,6 +315,7 @@ function collectUsage(sessionFiles: string[], startMs: number, endMs: number, sc
|
|
|
313
315
|
let projectLabel = basename(file);
|
|
314
316
|
let headerResolved = false;
|
|
315
317
|
let currentModel = "";
|
|
318
|
+
let lastUserTimestamp = 0;
|
|
316
319
|
|
|
317
320
|
const raw = readFileSync(file, "utf-8");
|
|
318
321
|
for (const line of raw.split("\n")) {
|
|
@@ -367,6 +370,8 @@ function collectUsage(sessionFiles: string[], startMs: number, endMs: number, sc
|
|
|
367
370
|
cacheWrite: 0,
|
|
368
371
|
total: 0,
|
|
369
372
|
cost: 0,
|
|
373
|
+
totalDurationMs: 0,
|
|
374
|
+
totalOutputForSpeed: 0,
|
|
370
375
|
};
|
|
371
376
|
|
|
372
377
|
existing.messages += 1;
|
|
@@ -376,10 +381,27 @@ function collectUsage(sessionFiles: string[], startMs: number, endMs: number, sc
|
|
|
376
381
|
existing.cacheWrite += cacheWrite;
|
|
377
382
|
existing.total += total;
|
|
378
383
|
existing.cost += cost;
|
|
384
|
+
|
|
385
|
+
// Track tok/sec: use preceding user message timestamp
|
|
386
|
+
if (output > 0 && lastUserTimestamp > 0) {
|
|
387
|
+
const durationMs = timestamp - lastUserTimestamp;
|
|
388
|
+
if (durationMs > 0) {
|
|
389
|
+
existing.totalDurationMs += durationMs;
|
|
390
|
+
existing.totalOutputForSpeed += output;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
379
394
|
rows.set(key, existing);
|
|
380
395
|
} else if (message.role === "user") {
|
|
381
396
|
const timestamp = Number(message.timestamp ?? 0);
|
|
382
|
-
if (!timestamp
|
|
397
|
+
if (!timestamp) continue;
|
|
398
|
+
|
|
399
|
+
// Always track last user timestamp for tok/sec calculation,
|
|
400
|
+
// even if this user message is outside the time range
|
|
401
|
+
// (the assistant response may still be within range).
|
|
402
|
+
lastUserTimestamp = timestamp;
|
|
403
|
+
|
|
404
|
+
if (timestamp < startMs || timestamp >= endMs) continue;
|
|
383
405
|
|
|
384
406
|
matchedUserPrompts++;
|
|
385
407
|
const model = currentModel;
|
|
@@ -397,6 +419,8 @@ function collectUsage(sessionFiles: string[], startMs: number, endMs: number, sc
|
|
|
397
419
|
cacheWrite: 0,
|
|
398
420
|
total: 0,
|
|
399
421
|
cost: 0,
|
|
422
|
+
totalDurationMs: 0,
|
|
423
|
+
totalOutputForSpeed: 0,
|
|
400
424
|
};
|
|
401
425
|
|
|
402
426
|
existing.userPrompts += 1;
|
|
@@ -431,9 +455,11 @@ function collectUsage(sessionFiles: string[], startMs: number, endMs: number, sc
|
|
|
431
455
|
acc.cacheWrite += row.cacheWrite;
|
|
432
456
|
acc.total += row.total;
|
|
433
457
|
acc.cost += row.cost;
|
|
458
|
+
acc.totalDurationMs += row.totalDurationMs;
|
|
459
|
+
acc.totalOutputForSpeed += row.totalOutputForSpeed;
|
|
434
460
|
return acc;
|
|
435
461
|
},
|
|
436
|
-
{ messages: 0, userPrompts: 0, input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0, cost: 0 },
|
|
462
|
+
{ messages: 0, userPrompts: 0, input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0, cost: 0, totalDurationMs: 0, totalOutputForSpeed: 0 },
|
|
437
463
|
);
|
|
438
464
|
|
|
439
465
|
return {
|
|
@@ -448,6 +474,11 @@ function collectUsage(sessionFiles: string[], startMs: number, endMs: number, sc
|
|
|
448
474
|
};
|
|
449
475
|
}
|
|
450
476
|
|
|
477
|
+
function formatSpeed(totalDurationMs: number, totalOutputForSpeed: number): string {
|
|
478
|
+
if (totalDurationMs <= 0) return "—";
|
|
479
|
+
return Math.round(totalOutputForSpeed / (totalDurationMs / 1000)).toLocaleString();
|
|
480
|
+
}
|
|
481
|
+
|
|
451
482
|
function renderTable(report: UsageReport): string {
|
|
452
483
|
const firstColumnHeader = report.groupBy === "project"
|
|
453
484
|
? "project"
|
|
@@ -465,8 +496,11 @@ function renderTable(report: UsageReport): string {
|
|
|
465
496
|
write: formatInt(row.cacheWrite),
|
|
466
497
|
total: formatInt(row.total),
|
|
467
498
|
cost: formatCost(row.cost),
|
|
499
|
+
speed: formatSpeed(row.totalDurationMs, row.totalOutputForSpeed),
|
|
468
500
|
}));
|
|
469
501
|
|
|
502
|
+
const totalsSpeed = formatSpeed(report.totals.totalDurationMs, report.totals.totalOutputForSpeed);
|
|
503
|
+
|
|
470
504
|
const widths = {
|
|
471
505
|
label: Math.max(firstColumnHeader.length, ...displayRows.map((row) => row.label.length), 5),
|
|
472
506
|
userPrompts: Math.max(11, ...displayRows.map((row) => row.userPrompts.length), String(report.totals.userPrompts).length),
|
|
@@ -477,6 +511,7 @@ function renderTable(report: UsageReport): string {
|
|
|
477
511
|
write: Math.max(5, ...displayRows.map((row) => row.write.length), formatInt(report.totals.cacheWrite).length),
|
|
478
512
|
total: Math.max(5, ...displayRows.map((row) => row.total.length), formatInt(report.totals.total).length),
|
|
479
513
|
cost: Math.max(7, ...displayRows.map((row) => row.cost.length), formatCost(report.totals.cost).length),
|
|
514
|
+
speed: Math.max(5, ...displayRows.map((row) => row.speed.length), totalsSpeed.length),
|
|
480
515
|
};
|
|
481
516
|
|
|
482
517
|
const header = [
|
|
@@ -489,6 +524,7 @@ function renderTable(report: UsageReport): string {
|
|
|
489
524
|
"write".padStart(widths.write),
|
|
490
525
|
"total".padStart(widths.total),
|
|
491
526
|
"cost".padStart(widths.cost),
|
|
527
|
+
"tok/s".padStart(widths.speed),
|
|
492
528
|
].join(" ");
|
|
493
529
|
|
|
494
530
|
const divider = "-".repeat(header.length);
|
|
@@ -502,6 +538,7 @@ function renderTable(report: UsageReport): string {
|
|
|
502
538
|
row.write.padStart(widths.write),
|
|
503
539
|
row.total.padStart(widths.total),
|
|
504
540
|
row.cost.padStart(widths.cost),
|
|
541
|
+
row.speed.padStart(widths.speed),
|
|
505
542
|
].join(" "));
|
|
506
543
|
|
|
507
544
|
const totalsLine = [
|
|
@@ -514,6 +551,7 @@ function renderTable(report: UsageReport): string {
|
|
|
514
551
|
formatInt(report.totals.cacheWrite).padStart(widths.write),
|
|
515
552
|
formatInt(report.totals.total).padStart(widths.total),
|
|
516
553
|
formatCost(report.totals.cost).padStart(widths.cost),
|
|
554
|
+
totalsSpeed.padStart(widths.speed),
|
|
517
555
|
].join(" ");
|
|
518
556
|
|
|
519
557
|
return [header, divider, ...body, divider, totalsLine].join("\n");
|
|
@@ -303,6 +303,7 @@ export default function(pi: ExtensionAPI) {
|
|
|
303
303
|
activationMode,
|
|
304
304
|
editorText: ctx.ui.getEditorText(),
|
|
305
305
|
holdToTalkSupported: isKittyProtocolActive(),
|
|
306
|
+
isEditorFocused: ctx.ui.isEditorFocused(),
|
|
306
307
|
onUnsupported: () => {
|
|
307
308
|
if (holdToTalkUnsupportedNotified) return;
|
|
308
309
|
holdToTalkUnsupportedNotified = true;
|
|
@@ -8,6 +8,7 @@ export interface PushToTalkState {
|
|
|
8
8
|
activationMode: VoiceActivationMode | null;
|
|
9
9
|
editorText: string;
|
|
10
10
|
holdToTalkSupported: boolean;
|
|
11
|
+
isEditorFocused: boolean;
|
|
11
12
|
onUnsupported?(): void;
|
|
12
13
|
startPushToTalk(): void | Promise<void>;
|
|
13
14
|
stopVoice(): void | Promise<void>;
|
|
@@ -16,6 +17,8 @@ export interface PushToTalkState {
|
|
|
16
17
|
export function handlePushToTalkInput(data: string, state: PushToTalkState): ReturnType<TerminalInputHandler> {
|
|
17
18
|
if (!matchesKey(data, Key.space)) return undefined;
|
|
18
19
|
|
|
20
|
+
if (!state.isEditorFocused) return undefined;
|
|
21
|
+
|
|
19
22
|
if (isKeyRelease(data)) {
|
|
20
23
|
if (state.activationMode === "push-to-talk") {
|
|
21
24
|
void Promise.resolve(state.stopVoice());
|
|
@@ -15,6 +15,7 @@ describe("voice push-to-talk handler", () => {
|
|
|
15
15
|
activationMode: null,
|
|
16
16
|
editorText: "",
|
|
17
17
|
holdToTalkSupported: true,
|
|
18
|
+
isEditorFocused: true,
|
|
18
19
|
startPushToTalk: () => { startCalls += 1; },
|
|
19
20
|
stopVoice: () => { stopCalls += 1; },
|
|
20
21
|
});
|
|
@@ -32,6 +33,7 @@ describe("voice push-to-talk handler", () => {
|
|
|
32
33
|
activationMode: null,
|
|
33
34
|
editorText: "hello",
|
|
34
35
|
holdToTalkSupported: true,
|
|
36
|
+
isEditorFocused: true,
|
|
35
37
|
startPushToTalk: () => { startCalls += 1; },
|
|
36
38
|
stopVoice: () => { },
|
|
37
39
|
});
|
|
@@ -48,6 +50,7 @@ describe("voice push-to-talk handler", () => {
|
|
|
48
50
|
activationMode: "push-to-talk",
|
|
49
51
|
editorText: "",
|
|
50
52
|
holdToTalkSupported: true,
|
|
53
|
+
isEditorFocused: true,
|
|
51
54
|
startPushToTalk: () => { startCalls += 1; },
|
|
52
55
|
stopVoice: () => { },
|
|
53
56
|
});
|
|
@@ -64,6 +67,7 @@ describe("voice push-to-talk handler", () => {
|
|
|
64
67
|
activationMode: "push-to-talk",
|
|
65
68
|
editorText: "",
|
|
66
69
|
holdToTalkSupported: true,
|
|
70
|
+
isEditorFocused: true,
|
|
67
71
|
startPushToTalk: () => { },
|
|
68
72
|
stopVoice: () => { stopCalls += 1; },
|
|
69
73
|
});
|
|
@@ -80,6 +84,7 @@ describe("voice push-to-talk handler", () => {
|
|
|
80
84
|
activationMode: "toggle",
|
|
81
85
|
editorText: "",
|
|
82
86
|
holdToTalkSupported: true,
|
|
87
|
+
isEditorFocused: true,
|
|
83
88
|
startPushToTalk: () => { },
|
|
84
89
|
stopVoice: () => { stopCalls += 1; },
|
|
85
90
|
});
|
|
@@ -97,6 +102,7 @@ describe("voice push-to-talk handler", () => {
|
|
|
97
102
|
activationMode: null,
|
|
98
103
|
editorText: "",
|
|
99
104
|
holdToTalkSupported: false,
|
|
105
|
+
isEditorFocused: true,
|
|
100
106
|
onUnsupported: () => { notifyCalls += 1; },
|
|
101
107
|
startPushToTalk: () => { startCalls += 1; },
|
|
102
108
|
stopVoice: () => { },
|