@deepseek-harness-tui/dsh-tui 0.9.2 → 0.9.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.
- package/README.md +4 -4
- package/bin/dsh-tui.js +26 -4
- package/dsh-ecosystem-spec/protocols/profile-definitions.d.ts +13 -13
- package/dsh-ecosystem-spec/protocols/profile-definitions.js +59 -59
- package/dsh-ecosystem-spec/protocols/tui-channel-http.d.ts +15 -15
- package/dsh-ecosystem-spec/protocols/tui-channel-http.js +32 -32
- package/dsh-ecosystem-spec/protocols/tui-channel.d.ts +59 -59
- package/dsh-ecosystem-spec/protocols/tui-channel.js +166 -166
- package/dsh-ecosystem-spec/protocols/tui-contributions.d.ts +42 -42
- package/dsh-ecosystem-spec/protocols/tui-contributions.js +143 -143
- package/dsh-ecosystem-spec/registry/README.md +14 -14
- package/dsh-ecosystem-spec/registry/host-descriptor.tui.example.json +56 -56
- package/dsh-ecosystem-spec/registry/permissions-0.1.json +13 -13
- package/dsh-ecosystem-spec/registry/registry-0.15.json +149 -149
- package/lib/types/commands.d.ts.map +1 -1
- package/lib/types/commands.js +7 -8
- package/lib/types/components/BalanceReportRow.d.ts +24 -0
- package/lib/types/components/BalanceReportRow.d.ts.map +1 -0
- package/lib/types/components/BalanceReportRow.js +87 -0
- package/lib/types/components/HistorySearchDialog.js +1 -1
- package/lib/types/components/MessageList.d.ts +3 -1
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +11 -7
- package/lib/types/components/PluginSceneBoundary.d.ts +1 -1
- package/lib/types/components/PluginSceneBoundary.js +1 -1
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +16 -0
- package/lib/types/components/Whale.d.ts +15 -4
- package/lib/types/components/Whale.d.ts.map +1 -1
- package/lib/types/components/Whale.js +9 -8
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts +7 -1
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.js +34 -4
- package/lib/types/deepseekBalance.d.ts +53 -0
- package/lib/types/deepseekBalance.d.ts.map +1 -0
- package/lib/types/deepseekBalance.js +86 -0
- package/lib/types/deepseekPricing.d.ts +82 -0
- package/lib/types/deepseekPricing.d.ts.map +1 -0
- package/lib/types/deepseekPricing.js +133 -0
- package/lib/types/dsh-adapter/channel.d.ts +46 -1
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +84 -10
- package/lib/types/dsh-adapter/index.d.ts +5 -0
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +1 -0
- package/lib/types/dsh-adapter/packaged-skills.d.ts +9 -0
- package/lib/types/dsh-adapter/packaged-skills.d.ts.map +1 -1
- package/lib/types/dsh-adapter/packaged-skills.js +19 -4
- package/lib/types/dsh-adapter/plugin.d.ts +6 -0
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +122 -18
- package/lib/types/dsh-adapter/settings-sections.d.ts +1 -0
- package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -1
- package/lib/types/dsh-adapter/settings-sections.js +35 -2
- package/lib/types/history.d.ts +4 -3
- package/lib/types/history.d.ts.map +1 -1
- package/lib/types/history.js +66 -18
- package/lib/types/i18n.d.ts +122 -55
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +39 -18
- package/lib/types/ink/ink.d.ts.map +1 -1
- package/lib/types/ink/ink.js +67 -17
- package/lib/types/ink/root.d.ts +16 -0
- package/lib/types/ink/root.d.ts.map +1 -1
- package/lib/types/ink/root.js +2 -0
- package/lib/types/ink/terminal-querier.d.ts +8 -0
- package/lib/types/ink/terminal-querier.d.ts.map +1 -1
- package/lib/types/ink/terminal-querier.js +13 -0
- package/lib/types/ink/terminal.d.ts +42 -0
- package/lib/types/ink/terminal.d.ts.map +1 -1
- package/lib/types/ink/terminal.js +52 -2
- package/lib/types/plugin-spec/registry.d.ts +1 -1
- package/lib/types/plugin-spec/registry.js +1 -1
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +72 -37
- package/lib/types/screens/SessionBrowser.d.ts.map +1 -1
- package/lib/types/screens/SessionBrowser.js +28 -13
- package/lib/types/screens/SessionTree.d.ts.map +1 -1
- package/lib/types/screens/SessionTree.js +33 -9
- package/lib/types/screens/Settings.d.ts +7 -5
- package/lib/types/screens/Settings.d.ts.map +1 -1
- package/lib/types/screens/Settings.js +206 -99
- package/lib/types/screens/StatusLine.d.ts.map +1 -1
- package/lib/types/screens/StatusLine.js +32 -1
- package/lib/types/sessionHistory.d.ts +11 -0
- package/lib/types/sessionHistory.d.ts.map +1 -1
- package/lib/types/sessionHistory.js +29 -0
- package/lib/types/sessions/format.d.ts.map +1 -1
- package/lib/types/sessions/format.js +14 -4
- package/lib/types/tips.js +2 -2
- package/lib/types/tuiDisplayPrefs.d.ts +3 -0
- package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
- package/lib/types/tuiDisplayPrefs.js +1 -0
- package/lib/types/update.d.ts +46 -0
- package/lib/types/update.d.ts.map +1 -1
- package/lib/types/update.js +232 -3
- package/node_modules/@deepseek-harness-tui/dsh-auth/LICENSE +21 -21
- package/node_modules/@deepseek-harness-tui/dsh-auth/dsh-plugin.json +44 -44
- package/node_modules/@dsh-std/command/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/command/LICENSE +21 -21
- package/node_modules/@dsh-std/command/README.md +26 -26
- package/node_modules/@dsh-std/command/README.zh.md +28 -28
- package/node_modules/@dsh-std/command/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/command/package.json +22 -22
- package/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/connection/LICENSE +21 -21
- package/node_modules/@dsh-std/connection/README.md +42 -42
- package/node_modules/@dsh-std/connection/README.zh.md +42 -42
- package/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
- package/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
- package/node_modules/@dsh-std/connection/package.json +20 -20
- package/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/core/LICENSE +21 -21
- package/node_modules/@dsh-std/core/README.md +13 -13
- package/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/core/package.json +21 -21
- package/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -9
- package/node_modules/@dsh-std/manifest/LICENSE +21 -21
- package/node_modules/@dsh-std/manifest/README.md +5 -5
- package/node_modules/@dsh-std/manifest/README.zh.md +5 -5
- package/node_modules/@dsh-std/manifest/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/manifest/package.json +20 -20
- package/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -144
- package/node_modules/@dsh-std/messages/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/messages/LICENSE +21 -21
- package/node_modules/@dsh-std/messages/README.md +5 -5
- package/node_modules/@dsh-std/messages/README.zh.md +7 -7
- package/node_modules/@dsh-std/messages/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/messages/package.json +20 -20
- package/node_modules/@dsh-std/messages/schema/message-observer-envelope-0.15.schema.json +54 -54
- package/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -9
- package/node_modules/@dsh-std/presentation/LICENSE +21 -21
- package/node_modules/@dsh-std/presentation/README.md +27 -27
- package/node_modules/@dsh-std/presentation/README.zh.md +29 -29
- package/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -1
- package/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/presentation/package.json +25 -25
- package/node_modules/@dsh-std/storage/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/storage/LICENSE +21 -21
- package/node_modules/@dsh-std/storage/README.md +5 -5
- package/node_modules/@dsh-std/storage/README.zh.md +7 -7
- package/node_modules/@dsh-std/storage/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/storage/package.json +20 -20
- package/node_modules/@dsh-std/storage/schema/local-storage-0.15.schema.json +56 -56
- package/package.json +95 -5
- package/skills/pr-comments/SKILL.md +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/LICENSE +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.md +42 -42
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.zh.md +42 -42
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/package.json +20 -20
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -9
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/LICENSE +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.md +5 -5
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.zh.md +5 -5
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/package.json +20 -20
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -144
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -9
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/LICENSE +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.md +27 -27
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.zh.md +29 -29
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/package.json +25 -25
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/LICENSE +21 -21
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.md +42 -42
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.zh.md +42 -42
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/package.json +20 -20
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/package.json +21 -21
package/lib/types/ink/root.js
CHANGED
|
@@ -26,6 +26,8 @@ export const renderSync = (node, options) => {
|
|
|
26
26
|
instance.unmount();
|
|
27
27
|
},
|
|
28
28
|
waitUntilExit: instance.waitUntilExit,
|
|
29
|
+
detachForShutdown: () => instance.detachForShutdown(),
|
|
30
|
+
detachStdinForHandoff: () => instance.detachStdinForHandoff(),
|
|
29
31
|
cleanup: () => instances.delete(inkOptions.stdout),
|
|
30
32
|
};
|
|
31
33
|
};
|
|
@@ -112,6 +112,14 @@ export declare class TerminalQuerier {
|
|
|
112
112
|
* before it — concurrent batches from independent callers stay isolated.
|
|
113
113
|
*/
|
|
114
114
|
private queue;
|
|
115
|
+
/**
|
|
116
|
+
* Set by dispose(). Post-dispose send()/flush() must not touch the
|
|
117
|
+
* terminal: they would re-enable raw mode (holdRawMode) and emit query
|
|
118
|
+
* bytes after the exit funnel's cleanup has already restored cooked
|
|
119
|
+
* mode — the replies then leak into the shell (#507). Resolving as
|
|
120
|
+
* "no answer" keeps callers' .then() chains inert instead of pending.
|
|
121
|
+
*/
|
|
122
|
+
private disposed;
|
|
115
123
|
constructor(stdout: NodeJS.WriteStream, setRawMode?: ((enabled: boolean) => void) | undefined);
|
|
116
124
|
private holdRawMode;
|
|
117
125
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminal-querier.d.ts","sourceRoot":"","sources":["../../../src/ink/terminal-querier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAI3D;;4CAE4C;AAC5C,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB,IAAI;IACzE,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAA;IACf,6DAA6D;IAC7D,KAAK,EAAE,CAAC,CAAC,EAAE,gBAAgB,KAAK,CAAC,IAAI,CAAC,CAAA;CACvC,CAAA;AAED,KAAK,cAAc,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC,CAAA;AACnE,KAAK,WAAW,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC,CAAA;AAC7D,KAAK,WAAW,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC,CAAA;AAC7D,KAAK,aAAa,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC,CAAA;AACzE,KAAK,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC,CAAA;AAC9E,KAAK,WAAW,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC,CAAA;AAC7D,KAAK,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC,CAAA;AAIzE;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC,cAAc,CAAC,CAKlE;AAED;;;;;GAKG;AACH,wBAAgB,GAAG,IAAI,aAAa,CAAC,WAAW,CAAC,CAKhD;AAED;;;GAGG;AACH,wBAAgB,GAAG,IAAI,aAAa,CAAC,WAAW,CAAC,CAKhD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,aAAa,CAAC,aAAa,CAAC,CAK5D;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,IAAI,aAAa,CAAC,iBAAiB,CAAC,CAKjE;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC,WAAW,CAAC,CAKjE;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,IAAI,aAAa,CAAC,iBAAiB,CAAC,CAK5D;AAgBD;;;GAGG;AACH,qBAAa,eAAe;
|
|
1
|
+
{"version":3,"file":"terminal-querier.d.ts","sourceRoot":"","sources":["../../../src/ink/terminal-querier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAI3D;;4CAE4C;AAC5C,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB,IAAI;IACzE,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAA;IACf,6DAA6D;IAC7D,KAAK,EAAE,CAAC,CAAC,EAAE,gBAAgB,KAAK,CAAC,IAAI,CAAC,CAAA;CACvC,CAAA;AAED,KAAK,cAAc,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC,CAAA;AACnE,KAAK,WAAW,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC,CAAA;AAC7D,KAAK,WAAW,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC,CAAA;AAC7D,KAAK,aAAa,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC,CAAA;AACzE,KAAK,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC,CAAA;AAC9E,KAAK,WAAW,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC,CAAA;AAC7D,KAAK,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC,CAAA;AAIzE;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC,cAAc,CAAC,CAKlE;AAED;;;;;GAKG;AACH,wBAAgB,GAAG,IAAI,aAAa,CAAC,WAAW,CAAC,CAKhD;AAED;;;GAGG;AACH,wBAAgB,GAAG,IAAI,aAAa,CAAC,WAAW,CAAC,CAKhD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,aAAa,CAAC,aAAa,CAAC,CAK5D;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,IAAI,aAAa,CAAC,iBAAiB,CAAC,CAKjE;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC,WAAW,CAAC,CAKjE;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,IAAI,aAAa,CAAC,iBAAiB,CAAC,CAK5D;AAgBD;;;GAGG;AACH,qBAAa,eAAe;IAkBxB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,UAAU,CAAC;IAlBrB;;;;OAIG;IACH,OAAO,CAAC,KAAK,CAAgB;IAE7B;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAQ;gBAGd,MAAM,EAAE,MAAM,CAAC,WAAW,EAC1B,UAAU,CAAC,GAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,aAAA;IAGjD,OAAO,CAAC,WAAW;IAKnB;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,CAAC,SAAS,gBAAgB,EAC7B,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GACtB,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAazB;;;;;;;;OAQG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAYtB,8EAA8E;IAC9E,OAAO,IAAI,IAAI;IASf;;;;;;;;;;;;;;;;;;OAkBG;IACH,UAAU,CAAC,CAAC,EAAE,gBAAgB,GAAG,IAAI;CAqBtC"}
|
|
@@ -122,6 +122,14 @@ export class TerminalQuerier {
|
|
|
122
122
|
* before it — concurrent batches from independent callers stay isolated.
|
|
123
123
|
*/
|
|
124
124
|
queue = [];
|
|
125
|
+
/**
|
|
126
|
+
* Set by dispose(). Post-dispose send()/flush() must not touch the
|
|
127
|
+
* terminal: they would re-enable raw mode (holdRawMode) and emit query
|
|
128
|
+
* bytes after the exit funnel's cleanup has already restored cooked
|
|
129
|
+
* mode — the replies then leak into the shell (#507). Resolving as
|
|
130
|
+
* "no answer" keeps callers' .then() chains inert instead of pending.
|
|
131
|
+
*/
|
|
132
|
+
disposed = false;
|
|
125
133
|
constructor(stdout, setRawMode) {
|
|
126
134
|
this.stdout = stdout;
|
|
127
135
|
this.setRawMode = setRawMode;
|
|
@@ -144,6 +152,8 @@ export class TerminalQuerier {
|
|
|
144
152
|
* answer before the next flush() sentinel.
|
|
145
153
|
*/
|
|
146
154
|
send(query) {
|
|
155
|
+
if (this.disposed)
|
|
156
|
+
return Promise.resolve(undefined);
|
|
147
157
|
return new Promise(resolve => {
|
|
148
158
|
this.queue.push({
|
|
149
159
|
kind: 'query',
|
|
@@ -164,6 +174,8 @@ export class TerminalQuerier {
|
|
|
164
174
|
* Safe to call with no pending queries — still waits for a round-trip.
|
|
165
175
|
*/
|
|
166
176
|
flush() {
|
|
177
|
+
if (this.disposed)
|
|
178
|
+
return Promise.resolve();
|
|
167
179
|
return new Promise(resolve => {
|
|
168
180
|
this.queue.push({
|
|
169
181
|
kind: 'sentinel',
|
|
@@ -175,6 +187,7 @@ export class TerminalQuerier {
|
|
|
175
187
|
}
|
|
176
188
|
/** Resolve and release all pending queries when their owning app unmounts. */
|
|
177
189
|
dispose() {
|
|
190
|
+
this.disposed = true;
|
|
178
191
|
for (const pending of this.queue.splice(0)) {
|
|
179
192
|
if (pending.kind === 'query')
|
|
180
193
|
pending.resolve(undefined);
|
|
@@ -53,6 +53,31 @@ export declare function setXtversionName(name: string): void;
|
|
|
53
53
|
* @returns true when the terminal is xterm.js-based.
|
|
54
54
|
*/
|
|
55
55
|
export declare function isXtermJs(): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* True when the terminal can be safely probed with DECRQM
|
|
58
|
+
* (`CSI ? <mode> $ p`).
|
|
59
|
+
*
|
|
60
|
+
* DECRQM carries a `$` intermediate byte before its final `p`. A conforming
|
|
61
|
+
* parser consumes the whole sequence and either answers with DECRPM or stays
|
|
62
|
+
* silent, so callers have historically treated an unanswered probe as
|
|
63
|
+
* "unsupported" and sent it unconditionally. macOS Terminal.app breaks that
|
|
64
|
+
* assumption: it does not implement DECRQM *and* its CSI parser gives up at
|
|
65
|
+
* the `$`, printing the trailing `p` to the screen as literal text. Every
|
|
66
|
+
* probe therefore leaks a visible `p` at the cursor.
|
|
67
|
+
*
|
|
68
|
+
* Terminal.app reports `TERM=xterm-256color`, so TERM sniffing cannot tell it
|
|
69
|
+
* apart from a real xterm — `TERM_PROGRAM=Apple_Terminal` is the only marker.
|
|
70
|
+
* It is not forwarded over SSH, which matches the scope of the bug: the leak
|
|
71
|
+
* only happens when the sequence reaches Terminal.app's own parser, and a
|
|
72
|
+
* remote session is parsed by whatever terminal is actually attached.
|
|
73
|
+
*
|
|
74
|
+
* Kept as an exclusion rather than an allowlist so unknown terminals keep the
|
|
75
|
+
* (correct, spec-conforming) probe and only the known-broken one opts out.
|
|
76
|
+
* Same failure mode as the extended-keys allowlist below: assuming terminals
|
|
77
|
+
* silently ignore unknown CSI is not safe in practice.
|
|
78
|
+
* @returns true when it is safe to send a DECRQM probe.
|
|
79
|
+
*/
|
|
80
|
+
export declare function supportsDecrqmProbe(): boolean;
|
|
56
81
|
/**
|
|
57
82
|
* True if this terminal correctly handles extended key reporting
|
|
58
83
|
* (Kitty keyboard protocol + xterm modifyOtherKeys).
|
|
@@ -122,6 +147,23 @@ export type Terminal = {
|
|
|
122
147
|
stdout: Writable;
|
|
123
148
|
stderr: Writable;
|
|
124
149
|
};
|
|
150
|
+
/**
|
|
151
|
+
* Write a frame diff to the terminal as a single buffered write. Wraps
|
|
152
|
+
* the output in BSU/ESU synchronized-update markers unless skipSyncMarkers
|
|
153
|
+
* is set. No-op when the diff contains no patches.
|
|
154
|
+
* @param terminal - the terminal to write to.
|
|
155
|
+
* @param diff - the frame diff patches to render.
|
|
156
|
+
* @param skipSyncMarkers - when true, omit the BSU/ESU wrapping.
|
|
157
|
+
*/
|
|
158
|
+
/**
|
|
159
|
+
* Serialize a frame diff into a single ANSI string (BSU/ESU-wrapped unless
|
|
160
|
+
* skipSyncMarkers is set). Empty string when the diff has no patches.
|
|
161
|
+
* Extracted from writeDiffToTerminal so shutdown paths can write the last
|
|
162
|
+
* frame synchronously (issue #522: an async frame write racing the
|
|
163
|
+
* synchronous EXIT_ALT_SCREEN lands on the MAIN screen after the alt
|
|
164
|
+
* screen is gone, leaving misplaced residue).
|
|
165
|
+
*/
|
|
166
|
+
export declare function serializeDiff(terminal: Terminal, diff: Diff, skipSyncMarkers?: boolean): string;
|
|
125
167
|
/**
|
|
126
168
|
* Write a frame diff to the terminal as a single buffered write. Wraps
|
|
127
169
|
* the output in BSU/ESU synchronized-update markers unless skipSyncMarkers
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../../src/ink/terminal.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAKtC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAYtC;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,EAAE,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,eAAe,CAAA;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,IAAI,OAAO,CAuCtD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,IAAI,OAAO,CAwDvD;AAcD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEnD;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAGnC;AAyBD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAG9C;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAC5C,WAAW,GAAE,MAAM,GAAG,SAAoC,EAC1D,kBAAkB,GAAE,MAAM,GAAG,SAA4C,GACxE,OAAO,CAOT;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,SAAkC,CAAA;AAEpE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAuBD;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,MAAM,EAAE,QAAQ,CAAA;IAChB,MAAM,EAAE,QAAQ,CAAA;CACjB,CAAA;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,IAAI,EACV,eAAe,UAAQ,GACtB,IAAI,
|
|
1
|
+
{"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../../src/ink/terminal.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAKtC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAYtC;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,EAAE,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,eAAe,CAAA;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,IAAI,OAAO,CAuCtD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,IAAI,OAAO,CAwDvD;AAcD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEnD;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAGnC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAyBD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAG9C;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAC5C,WAAW,GAAE,MAAM,GAAG,SAAoC,EAC1D,kBAAkB,GAAE,MAAM,GAAG,SAA4C,GACxE,OAAO,CAOT;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,SAAkC,CAAA;AAEpE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAuBD;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,MAAM,EAAE,QAAQ,CAAA;IAChB,MAAM,EAAE,QAAQ,CAAA;CACjB,CAAA;AAED;;;;;;;GAOG;AACH;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,IAAI,EACV,eAAe,UAAQ,GACtB,MAAM,CAwFR;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,IAAI,EACV,eAAe,UAAQ,GACtB,IAAI,CAMN"}
|
|
@@ -153,6 +153,33 @@ export function isXtermJs() {
|
|
|
153
153
|
return true;
|
|
154
154
|
return xtversionName?.startsWith('xterm.js') ?? false;
|
|
155
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* True when the terminal can be safely probed with DECRQM
|
|
158
|
+
* (`CSI ? <mode> $ p`).
|
|
159
|
+
*
|
|
160
|
+
* DECRQM carries a `$` intermediate byte before its final `p`. A conforming
|
|
161
|
+
* parser consumes the whole sequence and either answers with DECRPM or stays
|
|
162
|
+
* silent, so callers have historically treated an unanswered probe as
|
|
163
|
+
* "unsupported" and sent it unconditionally. macOS Terminal.app breaks that
|
|
164
|
+
* assumption: it does not implement DECRQM *and* its CSI parser gives up at
|
|
165
|
+
* the `$`, printing the trailing `p` to the screen as literal text. Every
|
|
166
|
+
* probe therefore leaks a visible `p` at the cursor.
|
|
167
|
+
*
|
|
168
|
+
* Terminal.app reports `TERM=xterm-256color`, so TERM sniffing cannot tell it
|
|
169
|
+
* apart from a real xterm — `TERM_PROGRAM=Apple_Terminal` is the only marker.
|
|
170
|
+
* It is not forwarded over SSH, which matches the scope of the bug: the leak
|
|
171
|
+
* only happens when the sequence reaches Terminal.app's own parser, and a
|
|
172
|
+
* remote session is parsed by whatever terminal is actually attached.
|
|
173
|
+
*
|
|
174
|
+
* Kept as an exclusion rather than an allowlist so unknown terminals keep the
|
|
175
|
+
* (correct, spec-conforming) probe and only the known-broken one opts out.
|
|
176
|
+
* Same failure mode as the extended-keys allowlist below: assuming terminals
|
|
177
|
+
* silently ignore unknown CSI is not safe in practice.
|
|
178
|
+
* @returns true when it is safe to send a DECRQM probe.
|
|
179
|
+
*/
|
|
180
|
+
export function supportsDecrqmProbe() {
|
|
181
|
+
return process.env.TERM_PROGRAM !== 'Apple_Terminal';
|
|
182
|
+
}
|
|
156
183
|
// Terminals known to correctly implement the Kitty keyboard protocol
|
|
157
184
|
// (CSI >1u) and/or xterm modifyOtherKeys (CSI >4;2m) for ctrl+shift+<letter>
|
|
158
185
|
// disambiguation. We previously enabled unconditionally (#23350), assuming
|
|
@@ -280,10 +307,18 @@ function dumpFrame(buffer) {
|
|
|
280
307
|
* @param diff - the frame diff patches to render.
|
|
281
308
|
* @param skipSyncMarkers - when true, omit the BSU/ESU wrapping.
|
|
282
309
|
*/
|
|
283
|
-
|
|
310
|
+
/**
|
|
311
|
+
* Serialize a frame diff into a single ANSI string (BSU/ESU-wrapped unless
|
|
312
|
+
* skipSyncMarkers is set). Empty string when the diff has no patches.
|
|
313
|
+
* Extracted from writeDiffToTerminal so shutdown paths can write the last
|
|
314
|
+
* frame synchronously (issue #522: an async frame write racing the
|
|
315
|
+
* synchronous EXIT_ALT_SCREEN lands on the MAIN screen after the alt
|
|
316
|
+
* screen is gone, leaving misplaced residue).
|
|
317
|
+
*/
|
|
318
|
+
export function serializeDiff(terminal, diff, skipSyncMarkers = false) {
|
|
284
319
|
// No output if there are no patches
|
|
285
320
|
if (diff.length === 0) {
|
|
286
|
-
return;
|
|
321
|
+
return '';
|
|
287
322
|
}
|
|
288
323
|
// BSU/ESU wrapping is opt-out to keep main-screen behavior unchanged.
|
|
289
324
|
// Callers pass skipSyncMarkers=true when the terminal doesn't support
|
|
@@ -364,5 +399,20 @@ export function writeDiffToTerminal(terminal, diff, skipSyncMarkers = false) {
|
|
|
364
399
|
if (useSync)
|
|
365
400
|
buffer += ESU;
|
|
366
401
|
dumpFrame(buffer);
|
|
402
|
+
return buffer;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Write a frame diff to the terminal as a single buffered write. Wraps
|
|
406
|
+
* the output in BSU/ESU synchronized-update markers unless skipSyncMarkers
|
|
407
|
+
* is set. No-op when the diff contains no patches.
|
|
408
|
+
* @param terminal - the terminal to write to.
|
|
409
|
+
* @param diff - the frame diff patches to render.
|
|
410
|
+
* @param skipSyncMarkers - when true, omit the BSU/ESU wrapping.
|
|
411
|
+
*/
|
|
412
|
+
export function writeDiffToTerminal(terminal, diff, skipSyncMarkers = false) {
|
|
413
|
+
const buffer = serializeDiff(terminal, diff, skipSyncMarkers);
|
|
414
|
+
if (buffer === '') {
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
367
417
|
terminal.stdout.write(buffer);
|
|
368
418
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Load and verify the pinned dsh-TUI admission profile. */
|
|
2
2
|
import type { ContractRegistry, PermissionRegistry, RegistryEntry } from './types.js';
|
|
3
3
|
export declare const DSH_STD_REVISION = "614dfa1ac168db79fcf4577cf0ebb34e2e3b944b";
|
|
4
|
-
export declare const ECOSYSTEM_SPEC_REVISION = "
|
|
4
|
+
export declare const ECOSYSTEM_SPEC_REVISION = "04d6798152db1df8523d97f51541adf42d3e41d9";
|
|
5
5
|
export interface SpecData {
|
|
6
6
|
dir: string;
|
|
7
7
|
registry: ContractRegistry;
|
|
@@ -5,7 +5,7 @@ import { dirname, join } from 'node:path';
|
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { createAdmissionCatalog } from './tui-extension.js';
|
|
7
7
|
export const DSH_STD_REVISION = '614dfa1ac168db79fcf4577cf0ebb34e2e3b944b';
|
|
8
|
-
export const ECOSYSTEM_SPEC_REVISION = '
|
|
8
|
+
export const ECOSYSTEM_SPEC_REVISION = '04d6798152db1df8523d97f51541adf42d3e41d9';
|
|
9
9
|
const REGISTRY_FILE = join('registry', 'registry-0.15.json');
|
|
10
10
|
const EXPECTED_PROFILE_VERSION = 'tui-admission/0.15';
|
|
11
11
|
const EXPECTED_STD_REPOSITORY = 'https://github.com/Yan-Zero/dsh-std';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/screens/Chat.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAwBzB,OAAO,EAAqB,KAAK,OAAO,EAAsE,MAAM,2BAA2B,CAAA;AAC/I,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAGlE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;
|
|
1
|
+
{"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/screens/Chat.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAwBzB,OAAO,EAAqB,KAAK,OAAO,EAAsE,MAAM,2BAA2B,CAAA;AAC/I,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAGlE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAwJ3D,wBAAgB,IAAI,CAAC,EACnB,OAAO,EACP,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,MAAM,EACN,QAAQ,EACR,SAAS,EACT,UAAkB,EAClB,cAAc,EAAE,kBAAkB,GACnC,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,EAAE,aAAa,CAAA;IAC5B;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,cAAc,CAAA;IACjC,oEAAoE;IACpE,eAAe,CAAC,EAAE,cAAc,CAAA;IAChC,iDAAiD;IACjD,kBAAkB,CAAC,EAAE,eAAe,CAAA;IACpC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB,4BAq0GA"}
|
|
@@ -39,6 +39,7 @@ import { OverlayAbove } from '../components/OverlayAbove.js';
|
|
|
39
39
|
import { PromptInput } from '../components/PromptInput.js';
|
|
40
40
|
import { GoalTodoPanel } from '../components/GoalTodoPanel.js';
|
|
41
41
|
import { AutoRecapRow } from '../components/AutoRecapRow.js';
|
|
42
|
+
import { BalanceReportRow } from '../components/BalanceReportRow.js';
|
|
42
43
|
import { LoadedContextPanel } from '../components/LoadedContextPanel.js';
|
|
43
44
|
import { StatusLine } from './StatusLine.js';
|
|
44
45
|
import { WorkingSpinner, useThinkingStatus } from '../components/WorkingSpinner.js';
|
|
@@ -108,22 +109,6 @@ const NO_ROWS = [];
|
|
|
108
109
|
function capitalize(text) {
|
|
109
110
|
return text.length === 0 ? text : text[0].toUpperCase() + text.slice(1);
|
|
110
111
|
}
|
|
111
|
-
/**
|
|
112
|
-
* CC's built-in skill commands, driven through the DSH skill system: each
|
|
113
|
-
* submits an activation prompt the model resolves via its skill catalog/load
|
|
114
|
-
* tools (the corresponding SKILL.md ships under ~/.dsh/skills with dsh-tui).
|
|
115
|
-
*/
|
|
116
|
-
// i18n keys, not resolved strings: module scope evaluates before apply()'s
|
|
117
|
-
// setLang, so t() must run at the call site to follow the active language.
|
|
118
|
-
const SKILL_PROMPTS = {
|
|
119
|
-
audit: 'skill-audit-prompt',
|
|
120
|
-
bug: 'skill-bug-prompt',
|
|
121
|
-
practice: 'skill-practice-prompt',
|
|
122
|
-
review: 'skill-review-prompt',
|
|
123
|
-
pr_comments: 'skill-pr-comments-prompt',
|
|
124
|
-
'release-notes': 'skill-release-notes-prompt',
|
|
125
|
-
'vuln-check': 'skill-vuln-check-prompt',
|
|
126
|
-
};
|
|
127
112
|
/** Terminal-title spinner frames (CC's TITLE_ANIMATION_FRAMES). */
|
|
128
113
|
const TITLE_ANIMATION_FRAMES = ['⠂', '⠐'];
|
|
129
114
|
/** Searchable transcript text for one row (`/` incsearch, CC semantics:
|
|
@@ -349,6 +334,25 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
349
334
|
recapAbortRef.current = null;
|
|
350
335
|
setRecap(null);
|
|
351
336
|
};
|
|
337
|
+
/** /balance report (`BalanceReportRow`): pure UI state like /recap — the
|
|
338
|
+
* result never enters the transcript or session log. Clicking the row
|
|
339
|
+
* re-queries (refreshing keeps the stale summary visible); a session
|
|
340
|
+
* switch retires the report. */
|
|
341
|
+
const [balance, setBalance] = React.useState(null);
|
|
342
|
+
const balanceSeqRef = React.useRef(0);
|
|
343
|
+
const runBalance = React.useCallback(() => {
|
|
344
|
+
const seq = ++balanceSeqRef.current;
|
|
345
|
+
setBalance(prev => ({ result: prev?.result ?? null, refreshing: true }));
|
|
346
|
+
void channel.balanceInfo().then(result => {
|
|
347
|
+
if (balanceSeqRef.current !== seq)
|
|
348
|
+
return;
|
|
349
|
+
setBalance({ result, refreshing: false });
|
|
350
|
+
});
|
|
351
|
+
}, [channel]);
|
|
352
|
+
const balanceSessionId = channel.agentId;
|
|
353
|
+
React.useEffect(() => {
|
|
354
|
+
setBalance(null);
|
|
355
|
+
}, [balanceSessionId]);
|
|
352
356
|
// Auto-recap (`dsh-tui.recapOnOpen`): every time the session switches
|
|
353
357
|
// (mount = open/resume, rewind/fork included), summarize its tail into
|
|
354
358
|
// the dim AutoRecapRow. Failures stay silent in auto mode — `/recap`
|
|
@@ -1337,6 +1341,15 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
1337
1341
|
channel.pushLocal('/cost', lines);
|
|
1338
1342
|
return true;
|
|
1339
1343
|
}
|
|
1344
|
+
case 'balance': {
|
|
1345
|
+
// DeepSeek official account balance (free read-only endpoint): the
|
|
1346
|
+
// channel resolves DEEPSEEK_API_KEY through the credentials seam and
|
|
1347
|
+
// queries api.deepseek.com/user/balance. The result renders as the
|
|
1348
|
+
// interactive BalanceReportRow (hover for details, click to refresh).
|
|
1349
|
+
setHelpOpen(false);
|
|
1350
|
+
runBalance();
|
|
1351
|
+
return true;
|
|
1352
|
+
}
|
|
1340
1353
|
case 'settings': {
|
|
1341
1354
|
// Plugin settings screen (issue #165): opens immediately; the screen
|
|
1342
1355
|
// reads sections + namespaces from the channel itself.
|
|
@@ -1718,21 +1731,6 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
1718
1731
|
setHelpOpen(false);
|
|
1719
1732
|
channel.pushLocal('/connect', [t('connect-none')]);
|
|
1720
1733
|
return true;
|
|
1721
|
-
case 'audit':
|
|
1722
|
-
case 'bug':
|
|
1723
|
-
case 'practice':
|
|
1724
|
-
case 'review':
|
|
1725
|
-
case 'pr_comments':
|
|
1726
|
-
case 'release-notes':
|
|
1727
|
-
case 'vuln-check': {
|
|
1728
|
-
// CC's skill commands: drive the DSH skill system by sending the
|
|
1729
|
-
// activation prompt to the model (it loads the skill via its skill
|
|
1730
|
-
// catalog/load tools when the SKILL.md ships in ~/.dsh/skills).
|
|
1731
|
-
const key = SKILL_PROMPTS[name];
|
|
1732
|
-
if (key)
|
|
1733
|
-
channel.submit(t(key));
|
|
1734
|
-
return true;
|
|
1735
|
-
}
|
|
1736
1734
|
default: {
|
|
1737
1735
|
// Plugin-registered command (DSH command registry): dispatch through
|
|
1738
1736
|
// the channel, whose execution logs command/run + command/done (the
|
|
@@ -2737,7 +2735,23 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2737
2735
|
// double-press exit when the input is empty; ctrl+d keeps the
|
|
2738
2736
|
// time-based double-press exit regardless.
|
|
2739
2737
|
if (channel.working) {
|
|
2740
|
-
|
|
2738
|
+
// First press while working only interrupts. If that abort is still
|
|
2739
|
+
// converging (cancelPending) the next press is the user insisting on
|
|
2740
|
+
// leaving: go straight to the exit funnel. Without this, a stuck turn
|
|
2741
|
+
// (long tool call that never settles, silent stream) swallows every
|
|
2742
|
+
// Ctrl+C forever — raw mode keeps the launcher's SIGINT escape
|
|
2743
|
+
// unreachable until the TUI exits.
|
|
2744
|
+
if (channel.cancelPending) {
|
|
2745
|
+
onExit();
|
|
2746
|
+
}
|
|
2747
|
+
else {
|
|
2748
|
+
channel.cancel();
|
|
2749
|
+
// Interrupt replaces any previously armed exit: the next press
|
|
2750
|
+
// must re-confirm instead of exiting out from under the turn.
|
|
2751
|
+
exitPendingRef.current = false;
|
|
2752
|
+
if (exitTimerRef.current)
|
|
2753
|
+
clearTimeout(exitTimerRef.current);
|
|
2754
|
+
}
|
|
2741
2755
|
}
|
|
2742
2756
|
else if (input === 'c' && promptControllerRef.current?.hasText()) {
|
|
2743
2757
|
promptControllerRef.current.clear();
|
|
@@ -2791,6 +2805,29 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2791
2805
|
// Working-activity line (spinner slot): context-pressure prefix shares the
|
|
2792
2806
|
// StatusLine thresholds (amber ≥ 80, red ≥ 95).
|
|
2793
2807
|
const activityWarnPct = contextPressurePct(channel.lastUsage, channel.contextWindow);
|
|
2808
|
+
// ── Interrupt lane ─────────────────────────────────────────────────────
|
|
2809
|
+
// The approval and ask_user_question panels park the agent until the user
|
|
2810
|
+
// answers, but they render inside the conversation layout — every screen
|
|
2811
|
+
// early-return below (plugin scene, browser, settings, subagent, trace)
|
|
2812
|
+
// used to win over them, leaving the session stuck with no visible cause.
|
|
2813
|
+
// While one is pending and a screen is up, the panel takes the whole
|
|
2814
|
+
// terminal INSTEAD of the screen. The screen's open flag survives, so the
|
|
2815
|
+
// decision lands back on the screen (remounted fresh — the same lifecycle
|
|
2816
|
+
// as closing and reopening it); keyboard exclusivity holds because the
|
|
2817
|
+
// covered screen is unmounted, exactly like the chat-state prompt slot.
|
|
2818
|
+
// The panel elements are shared with the prompt-slot chain below so the
|
|
2819
|
+
// two mount sites cannot drift.
|
|
2820
|
+
const approvalPanelNode = approvalSnapshot !== null ? (_jsx(ApprovalPanel, { approval: approvalSnapshot, onDecide: outcome => approvals.decide(outcome) }, approvalSnapshot.key)) : null;
|
|
2821
|
+
const questionPanelNode = questionSnapshot !== null ? (_jsx(AskUserQuestionPanel, { question: questionSnapshot.question, position: questionSnapshot.position, total: questionSnapshot.total, answered: questionSnapshot.answered, initialDraft: questionSnapshot.draft, onAnswer: selection => questionStore.answerCurrent(selection), onCancel: () => questionStore.cancelCurrent(), onBack: questionSnapshot.canGoBack
|
|
2822
|
+
? draft => questionStore.backCurrent(draft)
|
|
2823
|
+
: undefined }, questionSnapshot.key)) : null;
|
|
2824
|
+
const interruptPanel = approvalPanelNode ?? questionPanelNode;
|
|
2825
|
+
const screenOpen = channel.pluginScene !== undefined || browserOpen || settingsOpen
|
|
2826
|
+
|| subagentDetailId !== null || subagentDashboardOpen || sceneOpen;
|
|
2827
|
+
if (interruptPanel !== null && screenOpen) {
|
|
2828
|
+
const node = (_jsx(Box, { flexDirection: "column", width: "100%", paddingX: 1, children: interruptPanel }));
|
|
2829
|
+
return fullscreen ? node : _jsx(AlternateScreen, { children: node });
|
|
2830
|
+
}
|
|
2794
2831
|
// A plugin scene (dsh-tui-scenes) takes the whole terminal the same way
|
|
2795
2832
|
// the trajectory scene does, and sits at the TOP of this return chain:
|
|
2796
2833
|
// an open() landing while the session browser or the trajectory scene is
|
|
@@ -2925,7 +2962,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2925
2962
|
// transcript mount batches (and the first wheel events) for the
|
|
2926
2963
|
// frame budget right when the user wants to read history. Fresh
|
|
2927
2964
|
// sessions keep the full intro; restored ones settle instantly.
|
|
2928
|
-
skipIntro: channel.rows.length > 30 }, logoNonce), loadedContextVisible && (_jsx(LoadedContextPanel, { context: channel.loadedContext, open: loadedContextOpen, onToggle: toggleLoadedContext })), _jsx(MessageList, { rows: channel.rows, failureHintRowId: failureHintRowId, failureHint: t('traj-hint-failure', { key: `${modLabel}t` }), expanded: expanded, expandedRows: expandedRows, selectedId: selectionActive ? selectedId : null, onToggleRow: toggleRowExpanded, streamFoldedRows: streamFoldedRows, onToggleStreamFold: toggleStreamFolded, model: channel.model, diffLayout: channel.diffLayout, thinkingFold: channel.thinkingFold, toolBackground: channel.toolBackground, activityFrames: channel.activityFrames, showAll: showAllMessages, thinkingVisible: thinkingVisible, historyPaintEnabled: !fullscreen, onToggleAll: () => { setShowAllMessages(previous => !previous); }, onLoadOlder: () => channel.loadOlder(), registerRowRef: registerRowRef, scrollHandle: handle, forceMountRowId: forceMountRowId, newSinceRowId: isSticky ? null : lastSeenRowIdRef.current, onUnseenCount: setUnseenCount, onTimeline: setTimeline, onOpenSubagent: (agentId) => setSubagentDetailId(agentId), onOpenFile: openFileActions })] }), (() => {
|
|
2965
|
+
skipIntro: channel.rows.length > 30 }, logoNonce), loadedContextVisible && (_jsx(LoadedContextPanel, { context: channel.loadedContext, open: loadedContextOpen, onToggle: toggleLoadedContext })), _jsx(MessageList, { rows: channel.rows, failureHintRowId: failureHintRowId, failureHint: t('traj-hint-failure', { key: `${modLabel}t` }), expanded: expanded, expandedRows: expandedRows, selectedId: selectionActive ? selectedId : null, onToggleRow: toggleRowExpanded, streamFoldedRows: streamFoldedRows, onToggleStreamFold: toggleStreamFolded, model: channel.model, diffLayout: channel.diffLayout, thinkingFold: channel.thinkingFold, toolBackground: channel.toolBackground, foldTerminalCommand: channel.foldTerminalCommand, activityFrames: channel.activityFrames, showAll: showAllMessages, thinkingVisible: thinkingVisible, historyPaintEnabled: !fullscreen, onToggleAll: () => { setShowAllMessages(previous => !previous); }, onLoadOlder: () => channel.loadOlder(), registerRowRef: registerRowRef, scrollHandle: handle, forceMountRowId: forceMountRowId, newSinceRowId: isSticky ? null : lastSeenRowIdRef.current, onUnseenCount: setUnseenCount, onTimeline: setTimeline, onOpenSubagent: (agentId) => setSubagentDetailId(agentId), onOpenFile: openFileActions })] }), (() => {
|
|
2929
2966
|
// Gutter mode (settings `dsh-tui.scrollGutter`): the timeline
|
|
2930
2967
|
// rail (default), the proportional scrollbar, or nothing. The
|
|
2931
2968
|
// slot keeps its 2 columns in both rendered modes (Qwen's
|
|
@@ -2948,7 +2985,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2948
2985
|
// the animated chars/4 estimate, matching the classic
|
|
2949
2986
|
// spinner's counter (the suffix used raw chars before,
|
|
2950
2987
|
// inflating the reading next to a real upload number).
|
|
2951
|
-
suffix: `${lastUploadTokens > 0 ? ` · ↑ ${formatTokens(lastUploadTokens)}` : ''} · ↓ ${formatTokens(Math.round(channel.responseChars / 4))} tokens` }) })) : (_jsx(WorkingSpinner, { mode: channel.spinnerMode, hasActiveTools: channel.activeToolCount > 0, responseLengthRef: responseLengthRef, uploadTokensRef: uploadTokensRef, loadingStartTimeRef: loadingStartTimeRef, totalPausedMsRef: totalPausedMsRef, pauseStartTimeRef: pauseStartTimeRef, thinkingStatus: thinkingStatus }))), _jsx(GoalTodoPanel, { channel: channel, collapsed: todoCollapsed, onToggle: () => setTodoCollapsed(previous => !previous) }), recap !== null && recap.auto && !recap.expanded && (_jsx(AutoRecapRow, { summary: recap.summary, streaming: !recap.done, onExpand: () => setRecap(prev => (prev ? { ...prev, expanded: true } : prev)), onDismiss: () => closeRecap() })), statusEntries.length > 0 && (_jsx(Text, { dimColor: true, wrap: "truncate", children: statusEntries.map(entry => entry.text).join(' · ') })),
|
|
2988
|
+
suffix: `${lastUploadTokens > 0 ? ` · ↑ ${formatTokens(lastUploadTokens)}` : ''} · ↓ ${formatTokens(Math.round(channel.responseChars / 4))} tokens` }) })) : (_jsx(WorkingSpinner, { mode: channel.spinnerMode, hasActiveTools: channel.activeToolCount > 0, responseLengthRef: responseLengthRef, uploadTokensRef: uploadTokensRef, loadingStartTimeRef: loadingStartTimeRef, totalPausedMsRef: totalPausedMsRef, pauseStartTimeRef: pauseStartTimeRef, thinkingStatus: thinkingStatus }))), _jsx(GoalTodoPanel, { channel: channel, collapsed: todoCollapsed, onToggle: () => setTodoCollapsed(previous => !previous) }), recap !== null && recap.auto && !recap.expanded && (_jsx(AutoRecapRow, { summary: recap.summary, streaming: !recap.done, onExpand: () => setRecap(prev => (prev ? { ...prev, expanded: true } : prev)), onDismiss: () => closeRecap() })), balance !== null && (_jsx(BalanceReportRow, { result: balance.result, refreshing: balance.refreshing, tokens: channel.tokens, model: channel.model, onRefresh: runBalance, onDismiss: () => setBalance(null) })), statusEntries.length > 0 && (_jsx(Text, { dimColor: true, wrap: "truncate", children: statusEntries.map(entry => entry.text).join(' · ') })), approvalPanelNode !== null ? (approvalPanelNode) : dialogSnapshot !== null ? (_jsx(ExtensionDialog, { dialog: dialogSnapshot, onDecide: value => dialogs.decide(dialogSnapshot.key, value), onCancel: () => dialogs.cancel(dialogSnapshot.key) }, dialogSnapshot.key)) : overlay.kind === 'tips' ? (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(TipsPanel, { onClose: () => dispatchOverlay({ type: 'close-if', kind: 'tips' }) }) })) : recap !== null && (!recap.auto || recap.expanded) ? (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(RecapPanel, { summary: recap.summary, title: recap.title, error: recap.error, streaming: !recap.done, titleApplied: recap.titleApplied, onClose: () => {
|
|
2952
2989
|
// An expanded auto recap collapses back to its dim row;
|
|
2953
2990
|
// a manual /recap closes outright.
|
|
2954
2991
|
if (recap.auto) {
|
|
@@ -2971,9 +3008,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2971
3008
|
void setClipboard(btw.answer ?? '').then(raw => { if (raw)
|
|
2972
3009
|
writeRaw?.(raw); });
|
|
2973
3010
|
channel.notify(t('copied-chars', { n: (btw.answer ?? '').length }), { timeoutMs: 1500 });
|
|
2974
|
-
} }) })) :
|
|
2975
|
-
? draft => questionStore.backCurrent(draft)
|
|
2976
|
-
: undefined }, questionSnapshot.key)) : (_jsx(PromptInput, { channel: channel, helpOpen: helpOpen, onToggleHelp: () => { setHelpOpen(previous => !previous); }, onRunCommand: runCommand, selectionActive: promptSelectionActive, fillText: historyFill, onFillConsumed: () => { setHistoryFill(null); }, onRewindRequest: openRewind, controllerRef: promptControllerRef })), _jsx(StatusLine, { channel: channel, selectionActive: selectionActive, helpOpen: helpOpen, wake: wakeBand === undefined
|
|
3011
|
+
} }) })) : questionPanelNode !== null ? (questionPanelNode) : (_jsx(PromptInput, { channel: channel, helpOpen: helpOpen, onToggleHelp: () => { setHelpOpen(previous => !previous); }, onRunCommand: runCommand, selectionActive: promptSelectionActive, fillText: historyFill, onFillConsumed: () => { setHistoryFill(null); }, onRewindRequest: openRewind, controllerRef: promptControllerRef })), _jsx(StatusLine, { channel: channel, selectionActive: selectionActive, helpOpen: helpOpen, wake: wakeBand === undefined
|
|
2977
3012
|
? undefined
|
|
2978
3013
|
: {
|
|
2979
3014
|
band: wakeBand,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionBrowser.d.ts","sourceRoot":"","sources":["../../../src/screens/SessionBrowser.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"SessionBrowser.d.ts","sourceRoot":"","sources":["../../../src/screens/SessionBrowser.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAwBzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAoDxD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,IAAI,EACJ,WAAW,EACX,OAAO,GACR,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAA;IACZ,4EAA4E;IAC5E,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAA;IAC9C,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,GAAG,KAAK,CAAC,SAAS,CAiiBlB"}
|
|
@@ -10,22 +10,23 @@ import { useTerminalFocus } from '../ink/hooks/use-terminal-focus.js';
|
|
|
10
10
|
import { isMod, isPlainReturn, modLabel } from '../utils/modifiers.js';
|
|
11
11
|
import { formatProject, spreadRow, tailWidth, truncateWidth } from '../sessions/format.js';
|
|
12
12
|
import { stringWidth } from '../ink/stringWidth.js';
|
|
13
|
+
import { TICK, MULTIPLICATION_X } from '../cc/figures.js';
|
|
13
14
|
import { anchorTop, buildView, DEFAULT_FILTERS, moveSelection, seekSelectable, sessionAt, windowEnd, } from '../sessions/view.js';
|
|
14
15
|
import { t } from '../i18n.js';
|
|
15
16
|
/**
|
|
16
|
-
* Rows the layout cannot do without: the header, the search
|
|
17
|
-
*
|
|
17
|
+
* Rows the layout cannot do without: the header, the bordered search card
|
|
18
|
+
* (three rows: top border, input, bottom border), the notice slot, and the
|
|
19
|
+
* hints. Everything else — the rule, the list itself — yields before these do.
|
|
18
20
|
*/
|
|
19
|
-
const MANDATORY_LINES =
|
|
21
|
+
const MANDATORY_LINES = 6;
|
|
20
22
|
/**
|
|
21
|
-
* The
|
|
23
|
+
* The one remaining horizontal rule, above the hints.
|
|
22
24
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* row of content, or the hint line telling the user which keys exist, is not.
|
|
25
|
+
* The search card's own border separates it from the header and the list, so
|
|
26
|
+
* the two rules that used to flank it are gone; what remains lifts the hints
|
|
27
|
+
* off the content — decoration, and the first thing a short terminal drops.
|
|
27
28
|
*/
|
|
28
|
-
const RULE_PRIORITY = [
|
|
29
|
+
const RULE_PRIORITY = [2];
|
|
29
30
|
/** Terminal width below which the preview replaces the list instead of joining it. */
|
|
30
31
|
const SPLIT_MIN_COLUMNS = 100;
|
|
31
32
|
/** A thrown value's message, for a notification that has to say something. */
|
|
@@ -217,6 +218,16 @@ export function SessionBrowser({ channel, home, sameProject, onClose, }) {
|
|
|
217
218
|
if (landed !== undefined)
|
|
218
219
|
setFocusId(landed.id);
|
|
219
220
|
};
|
|
221
|
+
/**
|
|
222
|
+
* Mouse wheel over the list walks the cursor (the window is cursor-follow,
|
|
223
|
+
* so rolling IS scrolling; the preview pane rides along). Confirm/rename
|
|
224
|
+
* seats keep the keyboard as sole owner.
|
|
225
|
+
*/
|
|
226
|
+
const handleWheel = (event) => {
|
|
227
|
+
if (mode !== 'list')
|
|
228
|
+
return;
|
|
229
|
+
step(event.deltaY >= 0 ? 1 : -1);
|
|
230
|
+
};
|
|
220
231
|
// Preview follows the cursor. Keyed on the id so arrowing past a row does
|
|
221
232
|
// not refetch the one it came from, and guarded on unmount so a slow read
|
|
222
233
|
// landing after the cursor moved cannot overwrite a newer preview.
|
|
@@ -247,14 +258,16 @@ export function SessionBrowser({ channel, home, sameProject, onClose, }) {
|
|
|
247
258
|
const previewWidth = splitPreview ? Math.min(56, Math.floor(columns * 0.42)) : columns;
|
|
248
259
|
const listWidth = Math.max(20, columns - (splitPreview ? previewWidth : 0));
|
|
249
260
|
// Height is distributed, never assumed. Mandatory rows first, then a row
|
|
250
|
-
// for each region the current state actually needs, then the
|
|
261
|
+
// for each region the current state actually needs, then the rule while
|
|
251
262
|
// rows remain, and the list gets what is left — which may be nothing.
|
|
252
263
|
//
|
|
253
264
|
// The arithmetic below is the whole vertical layout: the regions sum to
|
|
254
265
|
// exactly `rows` at every height down to MANDATORY_LINES. Anything that
|
|
255
266
|
// assumed a fixed chrome would overflow on a short terminal, and the row
|
|
256
267
|
// that falls off the bottom is always the last one — the hints.
|
|
257
|
-
|
|
268
|
+
// The notice slot is mandatory (permanent): a delete/rename report must
|
|
269
|
+
// never shift the list by arriving.
|
|
270
|
+
const extraLines = mode === 'list' ? 0 : 1;
|
|
258
271
|
const ruleBudget = Math.max(0, Math.min(RULE_PRIORITY.length, rows - MANDATORY_LINES - extraLines));
|
|
259
272
|
const rules = new Set(RULE_PRIORITY.slice(0, ruleBudget));
|
|
260
273
|
const listHeight = Math.max(0, rows - MANDATORY_LINES - extraLines - rules.size);
|
|
@@ -469,12 +482,14 @@ export function SessionBrowser({ channel, home, sameProject, onClose, }) {
|
|
|
469
482
|
t('session-hint-list-mid', { mod: modLabel }),
|
|
470
483
|
t('session-hint-list-short'),
|
|
471
484
|
], inputBudget);
|
|
472
|
-
return (_jsxs(Box, { flexDirection: "column", width: columns, height: rows, children: [_jsxs(Box, { flexShrink: 0, children: [_jsx(Text, { color: "remember", bold: true, children: header.left }), _jsx(Text, { dimColor: true, children: `${' '.repeat(header.gap)}${header.right}` })] }),
|
|
485
|
+
return (_jsxs(Box, { flexDirection: "column", width: columns, height: rows, children: [_jsxs(Box, { flexShrink: 0, children: [_jsx(Text, { color: "remember", bold: true, children: header.left }), _jsx(Text, { dimColor: true, children: `${' '.repeat(header.gap)}${header.right}` })] }), _jsx(Box, { flexShrink: 0, children: _jsx(SearchBox, { query: tailWidth(filters.query, inputBudget), isFocused: mode === 'list', isTerminalFocused: isTerminalFocused, placeholder: truncateWidth(t('session-search-placeholder', { scope }), inputBudget) }) }), _jsxs("ink-box", { style: { flexDirection: 'row', flexGrow: 1, flexShrink: 1, overflow: 'hidden' }, onWheel: handleWheel, children: [!soloPreview && (_jsxs(Box, { flexDirection: "column", width: listWidth, height: listHeight, flexShrink: 0, children: [!loaded && (_jsx(Text, { dimColor: true, italic: true, children: ` ${truncateWidth(t('session-loading'), listWidth - 2)}` })), loaded && view.rows.length === 0 && (_jsx(Text, { dimColor: true, italic: true, children: ` ${truncateWidth(t('resume-none-in-cwd'), listWidth - 2)}` })), visible.map((row, index) => row.kind === 'project' ? (_jsxs(Box, { flexShrink: 0, children: [_jsx(Text, { color: "planMode", children: truncateWidth(` ${formatProject(row.project, home)}`, listWidth - 6) }), _jsx(Text, { dimColor: true, children: ` ${row.count}` })] }, `project:${row.project}:${index}`)) : (_jsx(SessionListRow, { session: row.session, width: listWidth, depth: row.depth, focused: windowTop + index === focus, now: now,
|
|
473
486
|
// 点击行 = 聚焦 + 恢复该会话(与 Enter 同路径)
|
|
474
487
|
onClick: () => {
|
|
475
488
|
setFocusId(row.session.id);
|
|
476
489
|
resumeSession(row.session);
|
|
477
|
-
} }, row.session.id)))] })), (splitPreview || soloPreview) && focused !== undefined && (_jsx(SessionPreview, { session: focused, entries: preview, loading: previewLoading, width: previewWidth, height: listHeight, home: home, now: now }))] }),
|
|
490
|
+
} }, row.session.id)))] })), (splitPreview || soloPreview) && focused !== undefined && (_jsx(SessionPreview, { session: focused, entries: preview, loading: previewLoading, width: previewWidth, height: listHeight, home: home, now: now }))] }), _jsx(Box, { flexShrink: 0, children: _jsx(Text, { color: notice?.tone === 'error' ? 'error' : 'success', children: notice === undefined
|
|
491
|
+
? ' '
|
|
492
|
+
: ` ${notice.tone === 'error' ? MULTIPLICATION_X : TICK} ${truncateWidth(notice.text, Math.max(0, columns - 4))}` }) }), mode === 'confirm-delete' && focused !== undefined && (_jsx(Box, { flexShrink: 0, onClick: () => {
|
|
478
493
|
// 点击确认行 = 确认删除(与 Enter 同路径);确认屏本身就是
|
|
479
494
|
// 显式确认层,取消保留键盘 Esc,防误点
|
|
480
495
|
setMode('list');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionTree.d.ts","sourceRoot":"","sources":["../../../src/screens/SessionTree.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"SessionTree.d.ts","sourceRoot":"","sources":["../../../src/screens/SessionTree.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAYzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AA8IxD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,gBAAgB,EAChB,OAAO,EACP,aAAa,GACd,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,sEAAsE;IACtE,gBAAgB,EAAE,MAAM,CAAA;IACxB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,yEAAyE;IACzE,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACtC,GAAG,KAAK,CAAC,SAAS,CAyflB"}
|