@deepseek-harness-tui/dsh-tui 0.8.6 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -3
- package/bin/dsh-tui.js +269 -218
- package/cordis.patch.yml +48 -22
- package/lib/types/cc/figures.d.ts.map +1 -1
- package/lib/types/cc/figures.js +14 -13
- package/lib/types/cc/syntaxRuns.d.ts +16 -0
- package/lib/types/cc/syntaxRuns.d.ts.map +1 -0
- package/lib/types/cc/syntaxRuns.js +79 -0
- package/lib/types/commands.d.ts +14 -0
- package/lib/types/commands.d.ts.map +1 -1
- package/lib/types/commands.js +20 -1
- package/lib/types/components/Chat/SubagentMessage.d.ts +19 -0
- package/lib/types/components/Chat/SubagentMessage.d.ts.map +1 -0
- package/lib/types/components/Chat/SubagentMessage.js +75 -0
- package/lib/types/components/EffortInputBorder.d.ts.map +1 -1
- package/lib/types/components/EffortInputBorder.js +2 -2
- package/lib/types/components/EffortTierBadge.js +1 -1
- package/lib/types/components/HelpMenu.d.ts +8 -1
- package/lib/types/components/HelpMenu.d.ts.map +1 -1
- package/lib/types/components/HelpMenu.js +15 -4
- package/lib/types/components/LogoV2.d.ts +3 -1
- package/lib/types/components/LogoV2.d.ts.map +1 -1
- package/lib/types/components/LogoV2.js +2 -2
- package/lib/types/components/MessageList.d.ts +6 -2
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +17 -6
- package/lib/types/components/ModelPicker.js +2 -2
- package/lib/types/components/PromptInput.d.ts +1 -1
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +75 -15
- package/lib/types/components/SkillsPicker.js +2 -2
- package/lib/types/components/SplitDiffView.d.ts +1 -13
- package/lib/types/components/SplitDiffView.d.ts.map +1 -1
- package/lib/types/components/SplitDiffView.js +6 -105
- package/lib/types/components/SubagentCard.d.ts +9 -0
- package/lib/types/components/SubagentCard.d.ts.map +1 -0
- package/lib/types/components/SubagentCard.js +26 -0
- package/lib/types/components/SubagentDashboard.d.ts +13 -0
- package/lib/types/components/SubagentDashboard.d.ts.map +1 -0
- package/lib/types/components/SubagentDashboard.js +50 -0
- package/lib/types/components/SubagentDetailScene.d.ts +16 -0
- package/lib/types/components/SubagentDetailScene.d.ts.map +1 -0
- package/lib/types/components/SubagentDetailScene.js +141 -0
- package/lib/types/components/SyntaxText.d.ts +15 -0
- package/lib/types/components/SyntaxText.d.ts.map +1 -0
- package/lib/types/components/SyntaxText.js +34 -0
- package/lib/types/components/ThinkingToggle.d.ts +3 -10
- package/lib/types/components/ThinkingToggle.d.ts.map +1 -1
- package/lib/types/components/ThinkingToggle.js +4 -9
- package/lib/types/components/design-system/ListItem.d.ts.map +1 -1
- package/lib/types/components/design-system/ListItem.js +1 -1
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantThinkingMessage.js +18 -7
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts +2 -0
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.js +42 -6
- package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
- package/lib/types/components/messages/UserPromptMessage.js +15 -2
- package/lib/types/dsh-adapter/channel.d.ts +53 -2
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +294 -7
- package/lib/types/dsh-adapter/contract.d.ts +27 -4
- package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
- package/lib/types/dsh-adapter/contract.js +56 -10
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +9 -3
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +38 -0
- package/lib/types/dsh-adapter/shortcuts.js +3 -3
- package/lib/types/dsh-adapter/subagents.d.ts +87 -0
- package/lib/types/dsh-adapter/subagents.d.ts.map +1 -0
- package/lib/types/dsh-adapter/subagents.js +204 -0
- package/lib/types/herdr.d.ts +28 -0
- package/lib/types/herdr.d.ts.map +1 -0
- package/lib/types/herdr.js +133 -0
- package/lib/types/i18n.d.ts +215 -31
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +65 -14
- package/lib/types/ink/ink.d.ts +4 -0
- package/lib/types/ink/ink.d.ts.map +1 -1
- package/lib/types/ink/ink.js +46 -15
- package/lib/types/minimalMode.d.ts +13 -0
- package/lib/types/minimalMode.d.ts.map +1 -0
- package/lib/types/minimalMode.js +17 -0
- package/lib/types/screens/Chat.d.ts +1 -1
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +94 -43
- package/lib/types/screens/StatusLine.d.ts.map +1 -1
- package/lib/types/screens/StatusLine.js +6 -2
- package/lib/types/screens/TrajectoryScene.d.ts.map +1 -1
- package/lib/types/screens/TrajectoryScene.js +4 -2
- package/lib/types/theme.d.ts +8 -0
- package/lib/types/theme.d.ts.map +1 -1
- package/lib/types/theme.js +38 -14
- package/lib/types/tips.js +3 -3
- package/lib/types/update.d.ts +18 -0
- package/lib/types/update.d.ts.map +1 -1
- package/lib/types/update.js +73 -2
- package/lib/types/utils/execFileNoThrow.d.ts +3 -20
- package/lib/types/utils/execFileNoThrow.d.ts.map +1 -1
- package/lib/types/utils/execFileNoThrow.js +53 -32
- package/lib/types/utils/externalEditor.d.ts +12 -11
- package/lib/types/utils/externalEditor.d.ts.map +1 -1
- package/lib/types/utils/externalEditor.js +11 -11
- package/package.json +64 -58
package/lib/types/theme.js
CHANGED
|
@@ -95,16 +95,16 @@ const darkTheme = {
|
|
|
95
95
|
toolDotWrite: rgb('#B3A0D4'), // soft violet — edit/write
|
|
96
96
|
toolDotWeb: rgb('#7DA1DE'), // mist blue — web search/fetch
|
|
97
97
|
toolDotTask: rgb('#D194AE'), // mist rose — subagent/jobs
|
|
98
|
-
syntaxKeyword: rgb('#
|
|
99
|
-
syntaxString: rgb('#
|
|
100
|
-
syntaxComment: rgb('#
|
|
101
|
-
syntaxNumber: rgb('#
|
|
102
|
-
syntaxFunction: rgb('#
|
|
103
|
-
syntaxType: rgb('#
|
|
98
|
+
syntaxKeyword: rgb('#78A0D6'), // muted anchor blue
|
|
99
|
+
syntaxString: rgb('#79AD91'), // mist green, distinct without neon saturation
|
|
100
|
+
syntaxComment: rgb('#74808D'), // neutral blue-grey
|
|
101
|
+
syntaxNumber: rgb('#C89B70'), // softened warm amber
|
|
102
|
+
syntaxFunction: rgb('#6FAEB5'), // muted cyan
|
|
103
|
+
syntaxType: rgb('#A98FBF'), // softened violet
|
|
104
104
|
syntaxVariable: rgb('#C9D1D9'), // near-text
|
|
105
105
|
syntaxOperator: rgb('#93A1B0'), // blue grey
|
|
106
106
|
syntaxPunctuation: rgb('#7A8694'), // dim blue grey
|
|
107
|
-
syntaxConstant: rgb('#
|
|
107
|
+
syntaxConstant: rgb('#C98291'), // softened rose
|
|
108
108
|
red_FOR_SUBAGENTS_ONLY: rgb('#D4685E'),
|
|
109
109
|
blue_FOR_SUBAGENTS_ONLY: rgb('#7496D6'),
|
|
110
110
|
green_FOR_SUBAGENTS_ONLY: rgb('#66B285'),
|
|
@@ -143,6 +143,14 @@ const darkTheme = {
|
|
|
143
143
|
rainbow_blue_shimmer: rgb('#AFBFE2'),
|
|
144
144
|
rainbow_indigo_shimmer: rgb('#BFB4DE'),
|
|
145
145
|
rainbow_violet_shimmer: rgb('#D1B4D1'),
|
|
146
|
+
subagentBullet: rgb('#D194AE'),
|
|
147
|
+
subagentDescription: rgb('#E8E6E0'),
|
|
148
|
+
subagentModel: rgb('#8D95A6'),
|
|
149
|
+
subagentElapsed: rgb('#8D95A6'),
|
|
150
|
+
subagentToolName: rgb('#7DA1DE'),
|
|
151
|
+
subagentStatusRunning: rgb('#7DA1DE'),
|
|
152
|
+
subagentStatusCompleted: rgb('#82B89D'),
|
|
153
|
+
subagentStatusFailed: rgb('#DA8A93'),
|
|
146
154
|
};
|
|
147
155
|
/**
|
|
148
156
|
* Gentle Mist Blue light theme — the strict original card. Blue carries
|
|
@@ -191,16 +199,16 @@ const lightTheme = {
|
|
|
191
199
|
toolDotWrite: rgb('#7A5CA8'),
|
|
192
200
|
toolDotWeb: rgb('#4A63A8'),
|
|
193
201
|
toolDotTask: rgb('#B04A5A'),
|
|
194
|
-
syntaxKeyword: rgb('#
|
|
195
|
-
syntaxString: rgb('#
|
|
196
|
-
syntaxComment: rgb('#
|
|
197
|
-
syntaxNumber: rgb('#
|
|
198
|
-
syntaxFunction: rgb('#
|
|
199
|
-
syntaxType: rgb('#
|
|
202
|
+
syntaxKeyword: rgb('#3F68B5'), // clear primary blue without neon saturation
|
|
203
|
+
syntaxString: rgb('#3F805F'), // readable muted green
|
|
204
|
+
syntaxComment: rgb('#7D858F'), // neutral blue-grey
|
|
205
|
+
syntaxNumber: rgb('#A7652B'), // warm amber accent
|
|
206
|
+
syntaxFunction: rgb('#2E7E8A'), // muted cyan
|
|
207
|
+
syntaxType: rgb('#7E55A4'), // softened violet
|
|
200
208
|
syntaxVariable: rgb('#343945'),
|
|
201
209
|
syntaxOperator: rgb('#5B6672'),
|
|
202
210
|
syntaxPunctuation: rgb('#9AA0A8'),
|
|
203
|
-
syntaxConstant: rgb('#
|
|
211
|
+
syntaxConstant: rgb('#A84472'), // muted rose accent
|
|
204
212
|
red_FOR_SUBAGENTS_ONLY: rgb('#BE5A52'),
|
|
205
213
|
blue_FOR_SUBAGENTS_ONLY: rgb('#3F6CC4'),
|
|
206
214
|
green_FOR_SUBAGENTS_ONLY: rgb('#4E9675'),
|
|
@@ -239,6 +247,14 @@ const lightTheme = {
|
|
|
239
247
|
rainbow_blue_shimmer: rgb('#A9BCE0'),
|
|
240
248
|
rainbow_indigo_shimmer: rgb('#B7AFD8'),
|
|
241
249
|
rainbow_violet_shimmer: rgb('#CFB0CC'),
|
|
250
|
+
subagentBullet: rgb('#C07A93'),
|
|
251
|
+
subagentDescription: rgb('#343945'),
|
|
252
|
+
subagentModel: rgb('#8991A0'),
|
|
253
|
+
subagentElapsed: rgb('#8991A0'),
|
|
254
|
+
subagentToolName: rgb('#3F6CC4'),
|
|
255
|
+
subagentStatusRunning: rgb('#3F6CC4'),
|
|
256
|
+
subagentStatusCompleted: rgb('#4E9675'),
|
|
257
|
+
subagentStatusFailed: rgb('#C65D6B'),
|
|
242
258
|
};
|
|
243
259
|
/**
|
|
244
260
|
* Dark ANSI theme using only the 16 standard ANSI colors, for terminals
|
|
@@ -337,6 +353,14 @@ const darkAnsiTheme = {
|
|
|
337
353
|
rainbow_blue_shimmer: 'ansi:cyanBright',
|
|
338
354
|
rainbow_indigo_shimmer: 'ansi:blueBright',
|
|
339
355
|
rainbow_violet_shimmer: 'ansi:magentaBright',
|
|
356
|
+
subagentBullet: 'ansi:magentaBright',
|
|
357
|
+
subagentDescription: 'ansi:whiteBright',
|
|
358
|
+
subagentModel: 'ansi:white',
|
|
359
|
+
subagentElapsed: 'ansi:white',
|
|
360
|
+
subagentToolName: 'ansi:cyanBright',
|
|
361
|
+
subagentStatusRunning: 'ansi:blueBright',
|
|
362
|
+
subagentStatusCompleted: 'ansi:greenBright',
|
|
363
|
+
subagentStatusFailed: 'ansi:redBright',
|
|
340
364
|
};
|
|
341
365
|
/**
|
|
342
366
|
* Resolve a theme name to its concrete color palette.
|
package/lib/types/tips.js
CHANGED
|
@@ -60,10 +60,10 @@ export const TIPS = [
|
|
|
60
60
|
en: 'In trajectory, / queries fields like tool:, err:, >10s, tok>1k',
|
|
61
61
|
},
|
|
62
62
|
{
|
|
63
|
-
id: 'keys-ctrl-
|
|
63
|
+
id: 'keys-ctrl-g',
|
|
64
64
|
group: 'keys',
|
|
65
|
-
zh: 'Ctrl+
|
|
66
|
-
en: 'Ctrl+
|
|
65
|
+
zh: 'Ctrl+G 用 $VISUAL/$EDITOR 编辑器编辑当前输入',
|
|
66
|
+
en: 'Ctrl+G edits your input in the $VISUAL/$EDITOR editor',
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
69
|
id: 'keys-ctrl-enter',
|
package/lib/types/update.d.ts
CHANGED
|
@@ -88,6 +88,24 @@ export declare function tuiUpdatePluginArgs(profile: string, targetVersion?: str
|
|
|
88
88
|
* token, so matching both keeps the retry from masking real failures.
|
|
89
89
|
*/
|
|
90
90
|
export declare function isTransientUpdateFailure(stderr: string): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Best-effort migrate the GLOBAL launcher to the delegating shim (0.8.7):
|
|
93
|
+
* after a successful profile update, copy this package's `bin/dsh-tui.js`
|
|
94
|
+
* and `package.json` over the global install so the launcher can never lag
|
|
95
|
+
* the profile again — the shim delegates all logic to the profile copy it
|
|
96
|
+
* just updated. Single-file-safe by contract: the new bin imports nothing
|
|
97
|
+
* from lib/ (see its header), so overwriting it inside an older global
|
|
98
|
+
* install cannot dangle a missing helper.
|
|
99
|
+
*
|
|
100
|
+
* Locating the global dir relies on argv[1] being the global `dsh-tui.js`
|
|
101
|
+
* (true when booted through the `dsh-tui` command). Source checkouts and
|
|
102
|
+
* direct `dsh --profile` boots resolve nothing — the migration is a silent
|
|
103
|
+
* no-op there. Write failures (permissions, locked files) are equally
|
|
104
|
+
* silent: the launcher-alignment warning remains the fallback diagnosis.
|
|
105
|
+
*
|
|
106
|
+
* @returns true when the global launcher files were replaced.
|
|
107
|
+
*/
|
|
108
|
+
export declare function migrateGlobalLauncher(): boolean;
|
|
91
109
|
/**
|
|
92
110
|
* Update the installed dsh-tui package and restart the same launcher while
|
|
93
111
|
* preserving the active session. The TUI must already be unmounted before
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/update.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAIlD,OAAO,EAAE,UAAU,EAAE,CAAA;AAQrB,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;CACf;AAED,4DAA4D;AAC5D,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3E;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAA;AAEvB,MAAM,WAAW,eAAe;IAC9B,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,gFAAgF;AAChF,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,SAAS,CAiBxD;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,GAAE,SAAS,MAAM,EAAiB,GAAG,MAAM,GAAG,SAAS,CAahG;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAW5C;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAIzE;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAG7D;AA4BD;;;;;;;;;;;;GAYG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,eAAe,CAAC,CAcvE;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAG5E;AA6DD,gFAAgF;AAChF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAIrF;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEhE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/update.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAIlD,OAAO,EAAE,UAAU,EAAE,CAAA;AAQrB,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;CACf;AAED,4DAA4D;AAC5D,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3E;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAA;AAEvB,MAAM,WAAW,eAAe;IAC9B,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,gFAAgF;AAChF,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,SAAS,CAiBxD;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,GAAE,SAAS,MAAM,EAAiB,GAAG,MAAM,GAAG,SAAS,CAahG;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAW5C;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAIzE;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAG7D;AA4BD;;;;;;;;;;;;GAYG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,eAAe,CAAC,CAcvE;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAG5E;AA6DD,gFAAgF;AAChF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAIrF;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEhE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CA2C/C;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,eAAe,CAAC,CA+E1B"}
|
package/lib/types/update.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { readFileSync, realpathSync, renameSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
|
-
import { dirname, join } from 'node:path';
|
|
4
|
+
import { dirname, join, resolve } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { gte, gt, lt, valid } from 'semver';
|
|
7
7
|
import { shellQuote } from './utils/shellQuote.js';
|
|
@@ -225,6 +225,70 @@ export function tuiUpdatePluginArgs(profile, targetVersion) {
|
|
|
225
225
|
export function isTransientUpdateFailure(stderr) {
|
|
226
226
|
return /ENOENT|EPERM|EBUSY/i.test(stderr) && /_tmp_\d+/i.test(stderr);
|
|
227
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* Best-effort migrate the GLOBAL launcher to the delegating shim (0.8.7):
|
|
230
|
+
* after a successful profile update, copy this package's `bin/dsh-tui.js`
|
|
231
|
+
* and `package.json` over the global install so the launcher can never lag
|
|
232
|
+
* the profile again — the shim delegates all logic to the profile copy it
|
|
233
|
+
* just updated. Single-file-safe by contract: the new bin imports nothing
|
|
234
|
+
* from lib/ (see its header), so overwriting it inside an older global
|
|
235
|
+
* install cannot dangle a missing helper.
|
|
236
|
+
*
|
|
237
|
+
* Locating the global dir relies on argv[1] being the global `dsh-tui.js`
|
|
238
|
+
* (true when booted through the `dsh-tui` command). Source checkouts and
|
|
239
|
+
* direct `dsh --profile` boots resolve nothing — the migration is a silent
|
|
240
|
+
* no-op there. Write failures (permissions, locked files) are equally
|
|
241
|
+
* silent: the launcher-alignment warning remains the fallback diagnosis.
|
|
242
|
+
*
|
|
243
|
+
* @returns true when the global launcher files were replaced.
|
|
244
|
+
*/
|
|
245
|
+
export function migrateGlobalLauncher() {
|
|
246
|
+
const launcherBin = process.argv[1];
|
|
247
|
+
if (launcherBin === undefined || !launcherBin.endsWith('dsh-tui.js'))
|
|
248
|
+
return false;
|
|
249
|
+
// Walk up from the bin to the containing package; accept it only when it
|
|
250
|
+
// is OUR package and not the profile copy we are running from (junction
|
|
251
|
+
// layouts collapse both onto the same real path — copying onto ourselves
|
|
252
|
+
// would be a no-op at best).
|
|
253
|
+
let dir = dirname(resolve(launcherBin));
|
|
254
|
+
const ownDir = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
255
|
+
for (let depth = 0; depth < 4; depth++) {
|
|
256
|
+
const manifest = join(dir, 'package.json');
|
|
257
|
+
try {
|
|
258
|
+
const parsed = JSON.parse(readFileSync(manifest, 'utf8'));
|
|
259
|
+
if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)
|
|
260
|
+
&& parsed.name === PACKAGE_NAME) {
|
|
261
|
+
let same = false;
|
|
262
|
+
try {
|
|
263
|
+
same = realpathSync(dir) === realpathSync(ownDir);
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
same = resolve(dir) === resolve(ownDir);
|
|
267
|
+
}
|
|
268
|
+
if (same)
|
|
269
|
+
return false;
|
|
270
|
+
// tmp + rename keeps each file atomic; a crash mid-migration leaves
|
|
271
|
+
// either the old or the new file, never a truncated one.
|
|
272
|
+
const replace = (target, source) => {
|
|
273
|
+
const staged = `${target}.dsh-tui-migrate`;
|
|
274
|
+
writeFileSync(staged, readFileSync(source));
|
|
275
|
+
renameSync(staged, target);
|
|
276
|
+
};
|
|
277
|
+
replace(join(dir, 'bin', 'dsh-tui.js'), join(ownDir, 'bin', 'dsh-tui.js'));
|
|
278
|
+
replace(manifest, join(ownDir, 'package.json'));
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
// Unreadable manifest at this level — keep walking up.
|
|
284
|
+
}
|
|
285
|
+
const parent = dirname(dir);
|
|
286
|
+
if (parent === dir)
|
|
287
|
+
return false;
|
|
288
|
+
dir = parent;
|
|
289
|
+
}
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
228
292
|
/**
|
|
229
293
|
* Update the installed dsh-tui package and restart the same launcher while
|
|
230
294
|
* preserving the active session. The TUI must already be unmounted before
|
|
@@ -297,6 +361,13 @@ export async function updateTuiAndRestart(sessionId, profile, targetVersion) {
|
|
|
297
361
|
return { updateCode: 1, restartCode: 1 };
|
|
298
362
|
}
|
|
299
363
|
}
|
|
364
|
+
// Launcher migration (0.8.7): the freshly installed profile carries the
|
|
365
|
+
// delegating shim — stamp it over the global launcher so this is the LAST
|
|
366
|
+
// time the outer copy can lag. Best-effort; the alignment warning stays as
|
|
367
|
+
// the fallback when the copy is impossible.
|
|
368
|
+
if (migrateGlobalLauncher()) {
|
|
369
|
+
process.stderr.write('dsh-tui: global launcher aligned to the delegating shim (no manual npm i -g needed anymore).\n');
|
|
370
|
+
}
|
|
300
371
|
const restartCode = await runProcess(process.execPath, [...process.execArgv, ...process.argv.slice(1)], {
|
|
301
372
|
env: {
|
|
302
373
|
...process.env,
|
|
@@ -4,31 +4,14 @@ export interface ExecFileNoThrowResult {
|
|
|
4
4
|
stdout: string;
|
|
5
5
|
stderr: string;
|
|
6
6
|
}
|
|
7
|
-
/**
|
|
8
|
-
*
|
|
9
|
-
* working directory.
|
|
10
|
-
*/
|
|
7
|
+
/** Options for {@link execFileNoThrow}: stdin payload, timeout, and child
|
|
8
|
+
* working directory. */
|
|
11
9
|
export interface ExecFileNoThrowOptions {
|
|
12
|
-
/** Stdin payload (OSC 52 clipboard helpers and tmux load-buffer). */
|
|
13
10
|
input?: string;
|
|
14
|
-
/** Kill the child after this many milliseconds. */
|
|
15
11
|
timeout?: number;
|
|
16
|
-
/**
|
|
17
|
-
* Accepted for call-site compatibility with the original execa-based
|
|
18
|
-
* implementation; `false` (the only value the Ink core passes) matches this
|
|
19
|
-
* shim's behavior of running in the current working directory.
|
|
20
|
-
*/
|
|
21
12
|
useCwd?: boolean;
|
|
22
|
-
/** Working directory for the child; defaults to the parent's cwd. */
|
|
23
13
|
cwd?: string;
|
|
24
14
|
}
|
|
25
|
-
/**
|
|
26
|
-
* Run a command without throwing: resolves with `{ code, stdout, stderr }`
|
|
27
|
-
* even when the process exits non-zero or cannot spawn.
|
|
28
|
-
* @param file - The executable path to spawn.
|
|
29
|
-
* @param args - Command-line arguments; defaults to none.
|
|
30
|
-
* @param options - Spawn options (input, timeout, cwd).
|
|
31
|
-
* @returns The process outcome: exit code, captured stdout, and captured stderr.
|
|
32
|
-
*/
|
|
15
|
+
/** Run a command without throwing; child output is bounded for safety. */
|
|
33
16
|
export declare function execFileNoThrow(file: string, args?: readonly string[], options?: ExecFileNoThrowOptions): Promise<ExecFileNoThrowResult>;
|
|
34
17
|
//# sourceMappingURL=execFileNoThrow.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execFileNoThrow.d.ts","sourceRoot":"","sources":["../../../src/utils/execFileNoThrow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"execFileNoThrow.d.ts","sourceRoot":"","sources":["../../../src/utils/execFileNoThrow.ts"],"names":[],"mappings":"AAKA,qDAAqD;AACrD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAED;wBACwB;AACxB,MAAM,WAAW,sBAAsB;IACrC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AA6BD,0EAA0E;AAC1E,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,SAAS,MAAM,EAAO,EAC5B,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,qBAAqB,CAAC,CA+BhC"}
|
|
@@ -1,44 +1,65 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
import { extname } from 'node:path';
|
|
3
|
+
const MAX_CAPTURE_BYTES = 64 * 1024;
|
|
4
|
+
function appendBounded(chunks, chunk, total) {
|
|
5
|
+
if (total.value >= MAX_CAPTURE_BYTES)
|
|
6
|
+
return;
|
|
7
|
+
const remaining = MAX_CAPTURE_BYTES - total.value;
|
|
8
|
+
const part = chunk.subarray(0, remaining);
|
|
9
|
+
chunks.push(part);
|
|
10
|
+
total.value += part.length;
|
|
11
|
+
}
|
|
12
|
+
/** Quote one argument for the Windows command interpreter without flattening
|
|
13
|
+
* the caller's argv into an unquoted shell command. */
|
|
14
|
+
function quoteWindowsArg(value) {
|
|
15
|
+
const escaped = value.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\+)$/g, '$1$1');
|
|
16
|
+
return `"${escaped.replace(/%/g, '%%')}"`;
|
|
17
|
+
}
|
|
18
|
+
function spawnCommand(file, args, options) {
|
|
19
|
+
const isWindowsScript = process.platform === 'win32' && /\.(?:cmd|bat)$/iu.test(extname(file));
|
|
20
|
+
if (!isWindowsScript)
|
|
21
|
+
return spawn(file, args, { timeout: options?.timeout, cwd: options?.cwd });
|
|
22
|
+
const command = `"${[file, ...args].map(quoteWindowsArg).join(' ')}"`;
|
|
23
|
+
return spawn(process.env.ComSpec ?? 'cmd.exe', ['/d', '/s', '/c', command], {
|
|
24
|
+
timeout: options?.timeout,
|
|
25
|
+
cwd: options?.cwd,
|
|
26
|
+
windowsHide: true,
|
|
27
|
+
windowsVerbatimArguments: true,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
/** Run a command without throwing; child output is bounded for safety. */
|
|
31
|
+
export function execFileNoThrow(file, args = [], options) {
|
|
11
32
|
return new Promise(resolve => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
33
|
+
let child;
|
|
34
|
+
try {
|
|
35
|
+
child = spawnCommand(file, args, options);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
resolve({ code: 1, stdout: '', stderr: '' });
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
15
41
|
const stdoutChunks = [];
|
|
16
42
|
const stderrChunks = [];
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
// EPIPE/EOF belongs to that child outcome and must not crash the caller.
|
|
25
|
-
child.stdin.on('error', () => { });
|
|
26
|
-
child.on('error', () => {
|
|
27
|
-
resolve({
|
|
28
|
-
code: 1,
|
|
29
|
-
stdout: Buffer.concat(stdoutChunks).toString('utf8'),
|
|
30
|
-
stderr: Buffer.concat(stderrChunks).toString('utf8'),
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
child.on('close', code => {
|
|
43
|
+
const stdoutTotal = { value: 0 };
|
|
44
|
+
const stderrTotal = { value: 0 };
|
|
45
|
+
let settled = false;
|
|
46
|
+
const finish = (code) => {
|
|
47
|
+
if (settled)
|
|
48
|
+
return;
|
|
49
|
+
settled = true;
|
|
34
50
|
resolve({
|
|
35
51
|
code,
|
|
36
52
|
stdout: Buffer.concat(stdoutChunks).toString('utf8'),
|
|
37
53
|
stderr: Buffer.concat(stderrChunks).toString('utf8'),
|
|
38
54
|
});
|
|
39
|
-
}
|
|
55
|
+
};
|
|
56
|
+
child.stdout?.on('data', (chunk) => appendBounded(stdoutChunks, chunk, stdoutTotal));
|
|
57
|
+
child.stderr?.on('data', (chunk) => appendBounded(stderrChunks, chunk, stderrTotal));
|
|
58
|
+
child.stdin?.on('error', () => { });
|
|
59
|
+
child.on('error', () => finish(1));
|
|
60
|
+
child.on('close', code => finish(code));
|
|
40
61
|
if (options?.input !== undefined)
|
|
41
|
-
child.stdin
|
|
42
|
-
child.stdin
|
|
62
|
+
child.stdin?.write(options.input);
|
|
63
|
+
child.stdin?.end();
|
|
43
64
|
});
|
|
44
65
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* External editor round-trip for the prompt input (issue #123): Ctrl+
|
|
2
|
+
* External editor round-trip for the prompt input (issue #123): Ctrl+G dumps
|
|
3
3
|
* the current draft into a temp file, hands the terminal to `$VISUAL` /
|
|
4
4
|
* `$EDITOR` (nvim, vim, nano, `code --wait`, …), and returns the saved text
|
|
5
5
|
* for the input to adopt.
|
|
@@ -16,11 +16,12 @@
|
|
|
16
16
|
* failing restore never overrides the outcome.
|
|
17
17
|
*
|
|
18
18
|
* Editor resolution order mirrors readline's edit-and-execute-command:
|
|
19
|
-
* `$VISUAL` → `$EDITOR
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* the command line is split
|
|
19
|
+
* `$VISUAL` → `$EDITOR`. There is deliberately NO fallback editor: an
|
|
20
|
+
* unresolved editor reports `unavailable` and the UI asks the user to set
|
|
21
|
+
* `$VISUAL` or `$EDITOR` (dropping someone into an unconfigured `vi` is a
|
|
22
|
+
* trap for users who don't know how to quit it). The variable may carry
|
|
23
|
+
* arguments (`EDITOR="code --wait"`), so the command line is split
|
|
24
|
+
* quote-aware before spawning.
|
|
24
25
|
*
|
|
25
26
|
* Windows launch: libuv resolves bare names to `.exe` on PATH but will NOT
|
|
26
27
|
* execute `.cmd`/`.bat` shims (VS Code's `code` on PATH is `code.cmd`), and
|
|
@@ -37,7 +38,8 @@
|
|
|
37
38
|
* - `edited`: the saved content differs from the draft — adopt `text`
|
|
38
39
|
* - `unchanged`: the file matches the draft (modulo newline convention), or
|
|
39
40
|
* the editor exited non-zero (`:cq` abort semantics) — keep the draft
|
|
40
|
-
* - `unavailable`: no editor could be resolved (
|
|
41
|
+
* - `unavailable`: no editor could be resolved (neither `$VISUAL` nor
|
|
42
|
+
* `$EDITOR` is set)
|
|
41
43
|
* - `failed`: the editor process or the temp-file round-trip errored
|
|
42
44
|
* (`message` names the failed command or carries the fs error)
|
|
43
45
|
*/
|
|
@@ -59,11 +61,10 @@ export type EditorOutcome = {
|
|
|
59
61
|
export declare function splitEditorCommand(commandLine: string): string[];
|
|
60
62
|
/**
|
|
61
63
|
* Resolve the editor argv from the environment. `$VISUAL` wins over
|
|
62
|
-
* `$EDITOR` (readline convention);
|
|
63
|
-
*
|
|
64
|
-
* parameter so the Windows branch is unit-testable from CI's Linux runners.
|
|
64
|
+
* `$EDITOR` (readline convention); when neither is set there is no fallback
|
|
65
|
+
* editor — returns undefined and the caller reports `unavailable`.
|
|
65
66
|
*/
|
|
66
|
-
export declare function resolveEditorCommand(env?: NodeJS.ProcessEnv
|
|
67
|
+
export declare function resolveEditorCommand(env?: NodeJS.ProcessEnv): string[] | undefined;
|
|
67
68
|
/**
|
|
68
69
|
* Windows shim resolution: a bare command like `code` usually lives on PATH
|
|
69
70
|
* as `code.cmd`, which libuv refuses to execute directly. Walk PATH with
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"externalEditor.d.ts","sourceRoot":"","sources":["../../../src/utils/externalEditor.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"externalEditor.d.ts","sourceRoot":"","sources":["../../../src/utils/externalEditor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAUH;;;;;;;;;GASG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAEvC;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CA0BhE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,EAAE,GAAG,SAAS,CAOtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAqBtC;AAKD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,IAAI,CAAA;CAAE,CAalD;AA8CD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAsDhF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* External editor round-trip for the prompt input (issue #123): Ctrl+
|
|
2
|
+
* External editor round-trip for the prompt input (issue #123): Ctrl+G dumps
|
|
3
3
|
* the current draft into a temp file, hands the terminal to `$VISUAL` /
|
|
4
4
|
* `$EDITOR` (nvim, vim, nano, `code --wait`, …), and returns the saved text
|
|
5
5
|
* for the input to adopt.
|
|
@@ -16,11 +16,12 @@
|
|
|
16
16
|
* failing restore never overrides the outcome.
|
|
17
17
|
*
|
|
18
18
|
* Editor resolution order mirrors readline's edit-and-execute-command:
|
|
19
|
-
* `$VISUAL` → `$EDITOR
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* the command line is split
|
|
19
|
+
* `$VISUAL` → `$EDITOR`. There is deliberately NO fallback editor: an
|
|
20
|
+
* unresolved editor reports `unavailable` and the UI asks the user to set
|
|
21
|
+
* `$VISUAL` or `$EDITOR` (dropping someone into an unconfigured `vi` is a
|
|
22
|
+
* trap for users who don't know how to quit it). The variable may carry
|
|
23
|
+
* arguments (`EDITOR="code --wait"`), so the command line is split
|
|
24
|
+
* quote-aware before spawning.
|
|
24
25
|
*
|
|
25
26
|
* Windows launch: libuv resolves bare names to `.exe` on PATH but will NOT
|
|
26
27
|
* execute `.cmd`/`.bat` shims (VS Code's `code` on PATH is `code.cmd`), and
|
|
@@ -76,17 +77,16 @@ export function splitEditorCommand(commandLine) {
|
|
|
76
77
|
}
|
|
77
78
|
/**
|
|
78
79
|
* Resolve the editor argv from the environment. `$VISUAL` wins over
|
|
79
|
-
* `$EDITOR` (readline convention);
|
|
80
|
-
*
|
|
81
|
-
* parameter so the Windows branch is unit-testable from CI's Linux runners.
|
|
80
|
+
* `$EDITOR` (readline convention); when neither is set there is no fallback
|
|
81
|
+
* editor — returns undefined and the caller reports `unavailable`.
|
|
82
82
|
*/
|
|
83
|
-
export function resolveEditorCommand(env = process.env
|
|
83
|
+
export function resolveEditorCommand(env = process.env) {
|
|
84
84
|
const raw = (env.VISUAL ?? '').trim() || (env.EDITOR ?? '').trim();
|
|
85
85
|
if (raw !== '') {
|
|
86
86
|
const args = splitEditorCommand(raw);
|
|
87
87
|
return args.length > 0 ? args : undefined;
|
|
88
88
|
}
|
|
89
|
-
return
|
|
89
|
+
return undefined;
|
|
90
90
|
}
|
|
91
91
|
/**
|
|
92
92
|
* Windows shim resolution: a bare command like `code` usually lives on PATH
|