@toddzheng024/dscode-bundle 0.7.24 → 0.7.26
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/package.json +2 -1
- package/plugins/openrouter/wire.mjs +3 -0
- package/plugins/session-metrics/index.mjs +16 -7
- package/plugins/session-metrics/rate.mjs +26 -61
- package/plugins/session-metrics/view.mjs +26 -12
- package/plugins/triggers/cli.mjs +155 -36
- package/plugins/triggers/commands.mjs +140 -0
- package/plugins/triggers/config.mjs +32 -13
- package/plugins/triggers/host.mjs +28 -21
- package/plugins/triggers/index.mjs +17 -47
- package/plugins/triggers/job-cli.mjs +110 -0
- package/plugins/triggers/jobs.mjs +156 -0
- package/plugins/triggers/lease.mjs +24 -0
- package/plugins/triggers/management.mjs +181 -0
- package/plugins/triggers/options.mjs +8 -0
- package/plugins/triggers/poll.mjs +12 -4
- package/plugins/triggers/run.mjs +1 -0
- package/plugins/triggers/schedule.mjs +40 -0
- package/plugins/triggers/scheduler-service.mjs +46 -0
- package/plugins/triggers/scheduler.mjs +90 -0
- package/plugins/triggers/session.mjs +43 -0
- package/plugins/triggers/source-emit.mjs +19 -0
- package/plugins/triggers/source-host.mjs +78 -0
- package/plugins/triggers/source-ingress.mjs +70 -0
- package/plugins/triggers/source-sandbox.mjs +35 -0
- package/plugins/triggers/sources.mjs +45 -0
- package/plugins/triggers/spool.mjs +23 -6
- package/plugins/triggers/tools.mjs +74 -0
- package/vendor/tui/lib/app.mjs +66 -87
- package/vendor/tui/lib/dscode/preset.mjs +18 -0
- package/vendor/tui/lib/dscode/telemetry.mjs +25 -9
- package/vendor/tui/lib/index.mjs +22 -78
- package/vendor/tui/lib/kernel-panels.mjs +3 -2
- package/vendor/tui/lib/locales/en.mjs +3 -2
- package/vendor/tui/lib/locales/zh.mjs +3 -2
- package/vendor/tui/lib/models.mjs +8 -0
- package/vendor/tui/lib/render/inspector.mjs +1 -1
- package/vendor/tui/lib/render/projection.mjs +11 -6
- package/vendor/tui/lib/render/status.mjs +39 -10
- package/vendor/tui/lib/startup.mjs +4 -5
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** Bounded, composer-safe panels for preset, session, and plugin kernel views. */
|
|
2
2
|
import { createElement, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { Box, Text, useInput, useStdout } from 'ink';
|
|
4
|
+
import { resolveModelEffort } from './models.mjs';
|
|
4
5
|
import { formatRelativeTime } from './session-directory.mjs';
|
|
5
6
|
import { panelViewport, revealRow } from './render/inspector.mjs';
|
|
6
7
|
import { markdownLines, textLines } from './render/lines.mjs';
|
|
@@ -893,8 +894,8 @@ export function EffortPanel({ row, current, select, back, onExit }) {
|
|
|
893
894
|
: hasDefaultRow
|
|
894
895
|
? [{ id: '', name: 'Default' }, ...advertised]
|
|
895
896
|
: advertised;
|
|
896
|
-
//
|
|
897
|
-
const effective =
|
|
897
|
+
// A different model's effort must not override this model's default.
|
|
898
|
+
const effective = resolveModelEffort(row, current) ?? '';
|
|
898
899
|
// The list opens ON the effective level (or the model's default row), so a
|
|
899
900
|
// quick re-pick never restarts the cursor from the top.
|
|
900
901
|
const wanted = effective === '' ? row.reasoning?.defaultEffort ?? '' : effective;
|
|
@@ -100,9 +100,10 @@ export const en = {
|
|
|
100
100
|
'cmd.help': 'show this overlay',
|
|
101
101
|
'cmd.model': 'switch the model and manage providers',
|
|
102
102
|
'cmd.effort': 'adjust reasoning effort for the current model',
|
|
103
|
+
'notice.modeLocked': 'DSCODE mode is fixed to dscode.',
|
|
103
104
|
'cmd.mode': 'inspect or select the agent preset (/mode [preset])',
|
|
104
105
|
'cmd.permission': 'inspect or select the permission preset (/permission [preset])',
|
|
105
|
-
'cmd.new': 'create and switch to a fresh session (/new
|
|
106
|
+
'cmd.new': 'create and switch to a fresh DSCODE session (/new)',
|
|
106
107
|
'cmd.fork': 'fork at the latest completed turn (/fork [event-seq])',
|
|
107
108
|
'cmd.resume': 'browse or switch root sessions (/resume [id|prefix])',
|
|
108
109
|
'cmd.search': 'full-text search across persisted sessions (/search [query])',
|
|
@@ -249,7 +250,7 @@ export const en = {
|
|
|
249
250
|
'status.label.cache': 'cache',
|
|
250
251
|
'status.label.in': 'in',
|
|
251
252
|
'status.label.out': 'out',
|
|
252
|
-
'status.label.mode': '
|
|
253
|
+
'status.label.mode': 'Mode',
|
|
253
254
|
'status.label.context': 'context',
|
|
254
255
|
'status.label.skills': 'skills',
|
|
255
256
|
// Frozen band
|
|
@@ -100,9 +100,10 @@ export const zh = {
|
|
|
100
100
|
'cmd.help': '显示本帮助',
|
|
101
101
|
'cmd.model': '切换模型并管理供应商',
|
|
102
102
|
'cmd.effort': '调整当前模型的推理档位',
|
|
103
|
+
'notice.modeLocked': 'DSCODE 已固定使用 dscode 模式。',
|
|
103
104
|
'cmd.mode': '查看或选择 Agent 预设(/mode [preset])',
|
|
104
105
|
'cmd.permission': '查看或选择权限预设(/permission [preset])',
|
|
105
|
-
'cmd.new': '
|
|
106
|
+
'cmd.new': '新建并切换到 DSCODE 会话(/new)',
|
|
106
107
|
'cmd.fork': '从最近的完成回合分叉(/fork [event-seq])',
|
|
107
108
|
'cmd.resume': '浏览或恢复历史会话(/resume [id|前缀])',
|
|
108
109
|
'cmd.search': '跨历史会话全文检索(/search [关键词])',
|
|
@@ -249,7 +250,7 @@ export const zh = {
|
|
|
249
250
|
'status.label.cache': '缓存',
|
|
250
251
|
'status.label.in': '入',
|
|
251
252
|
'status.label.out': '出',
|
|
252
|
-
'status.label.mode': '
|
|
253
|
+
'status.label.mode': '模式',
|
|
253
254
|
'status.label.context': '上下文',
|
|
254
255
|
'status.label.skills': '技能',
|
|
255
256
|
// Frozen band
|
|
@@ -8,6 +8,14 @@
|
|
|
8
8
|
* @module @deepseek-ai/dsh-tui/models
|
|
9
9
|
*/
|
|
10
10
|
import { ReasoningEffortId, } from '@deepseek-ai/dsh-llm';
|
|
11
|
+
/** Preserve an advertised effort, otherwise use the target model's own default. */
|
|
12
|
+
export function resolveModelEffort(row, current) {
|
|
13
|
+
const reasoning = row.reasoning;
|
|
14
|
+
const offered = reasoning?.efforts ?? [];
|
|
15
|
+
if (current && offered.some(effort => effort.id === current))
|
|
16
|
+
return current;
|
|
17
|
+
return offered.find(effort => effort.id === reasoning?.defaultEffort)?.id;
|
|
18
|
+
}
|
|
11
19
|
/** Map an adapter's reasoning capability onto the panel's plain-id shape. */
|
|
12
20
|
export function mapReasoning(reasoning) {
|
|
13
21
|
return {
|
|
@@ -15,7 +15,7 @@ export function liveRegionBudget(chrome) {
|
|
|
15
15
|
const terminal = Math.max(1, Math.floor(chrome.terminalRows));
|
|
16
16
|
const editor = Math.max(1, Math.floor(chrome.composerRows));
|
|
17
17
|
const band = editor + 2;
|
|
18
|
-
const status = chrome.statusBarRows
|
|
18
|
+
const status = chrome.statusBarRows;
|
|
19
19
|
const menu = Math.max(0, Math.floor(chrome.menuRows));
|
|
20
20
|
const gutter = chrome.gutterRows;
|
|
21
21
|
const notice = chrome.notice ? 1 : 0;
|
|
@@ -247,6 +247,15 @@ function estimateTokens(text) {
|
|
|
247
247
|
}
|
|
248
248
|
return wide + Math.ceil(narrow / 4);
|
|
249
249
|
}
|
|
250
|
+
/** Recovery text shared by live events and replayed history. */
|
|
251
|
+
function failureRecovery(code) {
|
|
252
|
+
if (code === 'MISSING_CREDENTIAL')
|
|
253
|
+
return ' · open /model to add an API key';
|
|
254
|
+
if (code === 'CONTENT_POLICY' || code === 'CONTENT_FILTER') {
|
|
255
|
+
return ' · turn stopped by provider content filtering; review the request and context before continuing';
|
|
256
|
+
}
|
|
257
|
+
return '';
|
|
258
|
+
}
|
|
250
259
|
/** A fresh, empty transcript view. */
|
|
251
260
|
export function createTranscriptView() {
|
|
252
261
|
return {
|
|
@@ -695,9 +704,7 @@ export function projectEvent(view, event) {
|
|
|
695
704
|
const reason = event.data.reason;
|
|
696
705
|
const appended = [];
|
|
697
706
|
if (reason.kind === 'error') {
|
|
698
|
-
const recovery = reason.error.code
|
|
699
|
-
? ' · open /model to add an API key'
|
|
700
|
-
: '';
|
|
707
|
+
const recovery = failureRecovery(reason.error.code);
|
|
701
708
|
appended.push({ kind: 'error', text: `${reason.error.code}: ${reason.error.message}${recovery}` });
|
|
702
709
|
}
|
|
703
710
|
else {
|
|
@@ -1441,9 +1448,7 @@ export function replayProjectEvent(acc, event) {
|
|
|
1441
1448
|
acc.streamingReasoning = '';
|
|
1442
1449
|
acc.streaming = '';
|
|
1443
1450
|
if (reason.kind === 'error') {
|
|
1444
|
-
const recovery = reason.error.code
|
|
1445
|
-
? ' · open /model to add an API key'
|
|
1446
|
-
: '';
|
|
1451
|
+
const recovery = failureRecovery(reason.error.code);
|
|
1447
1452
|
appended.push({ kind: 'error', text: `${reason.error.code}: ${reason.error.message}${recovery}` });
|
|
1448
1453
|
}
|
|
1449
1454
|
else {
|
|
@@ -306,7 +306,7 @@ function buildCandidates(facts, stats, busy, enabled, contextWidth) {
|
|
|
306
306
|
push({ text: lead, tone: 'model' });
|
|
307
307
|
}
|
|
308
308
|
if (model !== '' && enabled.has('model')) {
|
|
309
|
-
const effort = safe(facts.effort ??
|
|
309
|
+
const effort = safe(facts.effort ?? '');
|
|
310
310
|
push({ text: effort === '' ? model : model + ' @ ' + effort, tone: 'accent' });
|
|
311
311
|
}
|
|
312
312
|
const cwd = safe(facts.cwd);
|
|
@@ -426,7 +426,7 @@ function buildCandidates(facts, stats, busy, enabled, contextWidth) {
|
|
|
426
426
|
},
|
|
427
427
|
],
|
|
428
428
|
},
|
|
429
|
-
rank: RANK2_SKILLS,
|
|
429
|
+
rank: facts.telemetryFigures === undefined ? RANK2_SKILLS : 100,
|
|
430
430
|
id: 'skills',
|
|
431
431
|
});
|
|
432
432
|
}
|
|
@@ -476,16 +476,26 @@ function buildCandidates(facts, stats, busy, enabled, contextWidth) {
|
|
|
476
476
|
if (facts.plan && enabled.has('plan')) {
|
|
477
477
|
row2.push({ group: { spans: [{ text: '⧉ plan', tone: 'accent' }] }, rank: RANK2_PLAN, id: 'plan' });
|
|
478
478
|
}
|
|
479
|
-
//
|
|
480
|
-
//
|
|
481
|
-
|
|
482
|
-
|
|
479
|
+
// Structured runtime figures sit on the left; finances are placed separately
|
|
480
|
+
// after fitting that row. Keep the flat form for older text-only callers.
|
|
481
|
+
if (facts.telemetryFigures !== undefined) {
|
|
482
|
+
const figures = facts.telemetryFigures;
|
|
483
|
+
for (const [id, text, rank] of [
|
|
484
|
+
['telemetry-current', figures.current, 95],
|
|
485
|
+
['telemetry-average', figures.average, 30],
|
|
486
|
+
['telemetry-context', figures.context, 94],
|
|
487
|
+
]) {
|
|
488
|
+
if (text !== '')
|
|
489
|
+
row2.push({ group: { spans: [{ text, tone: 'meta' }] }, rank, id });
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
else if (facts.telemetry !== undefined && facts.telemetry !== '') {
|
|
483
493
|
row2.push({ group: { spans: [{ text: facts.telemetry, tone: 'meta' }] }, rank: RANK2_TELEMETRY, id: 'telemetry' });
|
|
484
494
|
}
|
|
485
495
|
return { left, right, badge, row2 };
|
|
486
496
|
}
|
|
487
497
|
/**
|
|
488
|
-
* Compose the
|
|
498
|
+
* Compose the responsive footer layout under a column budget. Row 1 keeps the
|
|
489
499
|
* session identity, cwd, mode, branch, context, then the right-pinned permission
|
|
490
500
|
* badge and cycle hint. It drops hint, context, and permission before
|
|
491
501
|
* ellipsizing identity. Row 2 fits all secondary figures, the live telemetry
|
|
@@ -497,7 +507,7 @@ function buildCandidates(facts, stats, busy, enabled, contextWidth) {
|
|
|
497
507
|
* keeps mode hints idle-only); 'items' is the ordered enabled-item config
|
|
498
508
|
* from /statusline (defaults to the full catalog). Display order follows the
|
|
499
509
|
* config per side while the drop ladder keeps its fixed ranks.
|
|
500
|
-
* @returns the
|
|
510
|
+
* @returns the rows to render; row1.left is never empty.
|
|
501
511
|
*/
|
|
502
512
|
export function layoutStatusBar(facts, stats, columns, options = {}) {
|
|
503
513
|
const busy = options.busy === true;
|
|
@@ -517,7 +527,10 @@ export function layoutStatusBar(facts, stats, columns, options = {}) {
|
|
|
517
527
|
const byPosition = (a, b) => (position.get(a.id) ?? Number.MAX_SAFE_INTEGER) - (position.get(b.id) ?? Number.MAX_SAFE_INTEGER);
|
|
518
528
|
const orderedLeft = [left[0], ...left.slice(1).sort(byPosition)];
|
|
519
529
|
const orderedRight = right.slice().sort(byPosition);
|
|
520
|
-
const orderedRow2 = row2.slice().sort(byPosition)
|
|
530
|
+
const orderedRow2 = facts.telemetryFigures === undefined ? row2.slice().sort(byPosition) : [
|
|
531
|
+
...row2.filter(entry => entry.id.startsWith('telemetry-')),
|
|
532
|
+
...row2.filter(entry => !entry.id.startsWith('telemetry-')).sort(byPosition),
|
|
533
|
+
];
|
|
521
534
|
// The cycle hint keeps its columns reserved whether or not it is painted:
|
|
522
535
|
// the badge anchors the right edge, so a turn opening or closing must not
|
|
523
536
|
// change what the left clusters may occupy.
|
|
@@ -655,6 +668,21 @@ export function layoutStatusBar(facts, stats, columns, options = {}) {
|
|
|
655
668
|
}
|
|
656
669
|
row2Kept.splice(dropIndex, 1);
|
|
657
670
|
}
|
|
671
|
+
// Keep fees, balance, peak/off-peak and cache together. Move the group down
|
|
672
|
+
// before sacrificing left-side figures just to seat it on the same row.
|
|
673
|
+
const figures = facts.telemetryFigures;
|
|
674
|
+
let financial = [];
|
|
675
|
+
if (figures !== undefined) {
|
|
676
|
+
const parts = [figures.money, figures.turn, figures.cache].filter(Boolean);
|
|
677
|
+
let text = parts.join(STATUS_ITEM_SEPARATOR);
|
|
678
|
+
// The optional per-turn cost goes first on extremely narrow terminals.
|
|
679
|
+
if (visibleColumns(text) > row2Budget)
|
|
680
|
+
text = [figures.money, figures.cache].filter(Boolean).join(STATUS_ITEM_SEPARATOR);
|
|
681
|
+
financial = [{ text: truncateColumns(text, row2Budget), tone: 'meta', telemetry: true }];
|
|
682
|
+
}
|
|
683
|
+
const financialWidth = spansWidth(financial);
|
|
684
|
+
const financialWrap = financial.length > 0 && row2Kept.length > 0
|
|
685
|
+
&& row2Width() + LEFT_RIGHT_GAP + financialWidth > row2Budget;
|
|
658
686
|
return {
|
|
659
687
|
row1: {
|
|
660
688
|
left: leftKept.map(entry => ({ ...entry.group, id: entry.id })),
|
|
@@ -663,8 +691,9 @@ export function layoutStatusBar(facts, stats, columns, options = {}) {
|
|
|
663
691
|
},
|
|
664
692
|
row2: {
|
|
665
693
|
left: row2Kept.map(entry => ({ ...entry.group, id: entry.id })),
|
|
666
|
-
right: [],
|
|
694
|
+
right: financialWrap ? [] : financial,
|
|
667
695
|
hint: false,
|
|
668
696
|
},
|
|
697
|
+
...(financialWrap ? { row3: { left: [], right: financial, hint: false } } : {}),
|
|
669
698
|
};
|
|
670
699
|
}
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
*
|
|
21
21
|
* @module @deepseek-ai/dsh-tui/startup
|
|
22
22
|
*/
|
|
23
|
-
import { Command } from 'commander';
|
|
23
|
+
import { Command, Option } from 'commander';
|
|
24
|
+
import { requireDscodePreset } from './dscode/preset.mjs';
|
|
24
25
|
import { parseCmdline } from '@deepseek-ai/dsh-cmdline';
|
|
25
26
|
import { THEME_NAMES } from './theme.mjs';
|
|
26
27
|
/** Stable Cordis plugin name. */
|
|
@@ -38,8 +39,7 @@ export function resolveTuiStartup(options) {
|
|
|
38
39
|
throw new Error('--session needs an id');
|
|
39
40
|
if (options.resume === '')
|
|
40
41
|
throw new Error('--resume needs a session id or id prefix');
|
|
41
|
-
|
|
42
|
-
throw new Error('--mode needs a preset id');
|
|
42
|
+
requireDscodePreset(options.mode);
|
|
43
43
|
if (options.mode !== undefined && (options.resume !== undefined || options.continue === true)) {
|
|
44
44
|
throw new Error('--mode applies only to a new session; it cannot be combined with --resume or --continue');
|
|
45
45
|
}
|
|
@@ -72,7 +72,7 @@ function tuiCommand() {
|
|
|
72
72
|
.option('-r, --resume <session>', 'resume the persisted session with this id (or unique id prefix)')
|
|
73
73
|
.option('-c, --continue', 'resume the most recent persisted session for this working directory')
|
|
74
74
|
.option('--session <id>', 'create a new session under this explicit id')
|
|
75
|
-
.
|
|
75
|
+
.addOption(new Option('--mode <preset>', 'compatibility flag; only dscode is accepted').hideHelp())
|
|
76
76
|
.option('--theme <name>', 'color theme: dark (default), light, prismatic, rainbow, or auto')
|
|
77
77
|
.option('-i, --image <path>', 'attach an image to the initial prompt (repeatable)', (path, paths) => [...paths, path], [])
|
|
78
78
|
.argument('[prompt...]', 'initial prompt; sends immediately after startup')
|
|
@@ -81,7 +81,6 @@ Examples:
|
|
|
81
81
|
dsh --profile cli fresh session, minted id
|
|
82
82
|
dsh --profile cli --resume abc123 resume session by id prefix
|
|
83
83
|
dsh --profile cli --continue resume the latest local session
|
|
84
|
-
dsh --profile cli --mode minimal fresh session using the minimal preset
|
|
85
84
|
dsh --profile cli --theme light light palette for bright terminals
|
|
86
85
|
dsh --profile cli "explain this repo" start and send an initial prompt
|
|
87
86
|
dsh --profile cli -i diagram.png "review this diagram"
|