@banbolee/dsh-fish-shell 0.7.0 → 0.8.0
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/CHANGELOG.md +74 -0
- package/README.md +310 -13
- package/README.zh.md +99 -4
- package/THIRD-PARTY-NOTICES.md +91 -0
- package/cordis.patch.yml +56 -0
- package/node_modules/@deepseek-ai/cosmokit/LICENSE +21 -0
- package/node_modules/@deepseek-ai/cosmokit/README.md +30 -0
- package/node_modules/@deepseek-ai/cosmokit/lib/index.js +418 -0
- package/node_modules/@deepseek-ai/cosmokit/lib/types/array.d.ts +15 -0
- package/node_modules/@deepseek-ai/cosmokit/lib/types/array.d.ts.map +1 -0
- package/node_modules/@deepseek-ai/cosmokit/lib/types/index.d.ts +13 -0
- package/node_modules/@deepseek-ai/cosmokit/lib/types/index.d.ts.map +1 -0
- package/node_modules/@deepseek-ai/cosmokit/lib/types/misc.d.ts +41 -0
- package/node_modules/@deepseek-ai/cosmokit/lib/types/misc.d.ts.map +1 -0
- package/node_modules/@deepseek-ai/cosmokit/lib/types/string.d.ts +89 -0
- package/node_modules/@deepseek-ai/cosmokit/lib/types/string.d.ts.map +1 -0
- package/node_modules/@deepseek-ai/cosmokit/lib/types/time.d.ts +19 -0
- package/node_modules/@deepseek-ai/cosmokit/lib/types/time.d.ts.map +1 -0
- package/node_modules/@deepseek-ai/cosmokit/lib/types/types.d.ts +42 -0
- package/node_modules/@deepseek-ai/cosmokit/lib/types/types.d.ts.map +1 -0
- package/node_modules/@deepseek-ai/cosmokit/lib/types/volatile.d.ts +40 -0
- package/node_modules/@deepseek-ai/cosmokit/lib/types/volatile.d.ts.map +1 -0
- package/node_modules/@deepseek-ai/cosmokit/package.json +32 -0
- package/node_modules/@deepseek-ai/cosmokit/src/array.ts +42 -0
- package/node_modules/@deepseek-ai/cosmokit/src/index.ts +12 -0
- package/node_modules/@deepseek-ai/cosmokit/src/misc.ts +78 -0
- package/node_modules/@deepseek-ai/cosmokit/src/string.ts +113 -0
- package/node_modules/@deepseek-ai/cosmokit/src/time.ts +92 -0
- package/node_modules/@deepseek-ai/cosmokit/src/types.ts +168 -0
- package/node_modules/@deepseek-ai/cosmokit/src/volatile.ts +86 -0
- package/node_modules/@deepseek-ai/dsh-tool-terminal/LICENSE +21 -0
- package/node_modules/@deepseek-ai/dsh-tool-terminal/README.i18n.yaml +100 -0
- package/node_modules/@deepseek-ai/dsh-tool-terminal/README.md +186 -0
- package/node_modules/@deepseek-ai/dsh-tool-terminal/README.zh.md +186 -0
- package/node_modules/@deepseek-ai/dsh-tool-terminal/lib/index.js +646 -0
- package/node_modules/@deepseek-ai/dsh-tool-terminal/lib/types/background.d.ts +20 -0
- package/node_modules/@deepseek-ai/dsh-tool-terminal/lib/types/index.d.ts +32 -0
- package/node_modules/@deepseek-ai/dsh-tool-terminal/lib/types/render.d.ts +81 -0
- package/node_modules/@deepseek-ai/dsh-tool-terminal/package.json +63 -0
- package/node_modules/@deepseek-ai/schemastery/LICENSE +21 -0
- package/node_modules/@deepseek-ai/schemastery/README.md +393 -0
- package/node_modules/@deepseek-ai/schemastery/lib/index.cjs +635 -0
- package/node_modules/@deepseek-ai/schemastery/lib/index.mjs +635 -0
- package/node_modules/@deepseek-ai/schemastery/lib/types/index.d.ts +211 -0
- package/node_modules/@deepseek-ai/schemastery/lib/types/index.d.ts.map +1 -0
- package/node_modules/@deepseek-ai/schemastery/package.json +39 -0
- package/node_modules/@deepseek-ai/schemastery/src/index.ts +962 -0
- package/node_modules/@standard-schema/spec/LICENSE +21 -0
- package/node_modules/@standard-schema/spec/README.md +198 -0
- package/node_modules/@standard-schema/spec/dist/index.cjs +18 -0
- package/node_modules/@standard-schema/spec/dist/index.d.cts +119 -0
- package/node_modules/@standard-schema/spec/dist/index.d.ts +119 -0
- package/node_modules/@standard-schema/spec/dist/index.js +0 -0
- package/node_modules/@standard-schema/spec/package.json +52 -0
- package/package.json +17 -3
- package/terminal-tools.js +259 -0
- package/terminal.js +297 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { isNullable } from './misc.ts'
|
|
2
|
+
import { isVolatile } from './volatile.ts'
|
|
3
|
+
|
|
4
|
+
type GlobalConstructorNames = keyof {
|
|
5
|
+
[K in keyof typeof globalThis as typeof globalThis[K] extends abstract new (...args: any) => any ? K : never]: K
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** Create a predicate for a global constructor name. */
|
|
9
|
+
export function is<K extends GlobalConstructorNames>(type: K): (value: any) => value is InstanceType<typeof globalThis[K]>
|
|
10
|
+
/** Test whether a value matches a global constructor name. */
|
|
11
|
+
export function is<K extends GlobalConstructorNames>(type: K, value: any): value is InstanceType<typeof globalThis[K]>
|
|
12
|
+
/** Test values using `instanceof` with a `toStringTag` fallback. */
|
|
13
|
+
export function is<K extends GlobalConstructorNames>(type: K, value?: any): any {
|
|
14
|
+
if (arguments.length === 1) return (value: any) => is(type, value)
|
|
15
|
+
return type in globalThis && value instanceof (globalThis[type] as any)
|
|
16
|
+
|| Object.prototype.toString.call(value).slice(8, -1) === type
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function isArrayBufferLike(value: any): value is ArrayBufferLike {
|
|
20
|
+
return is('ArrayBuffer', value) || is('SharedArrayBuffer', value)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function isArrayBufferSource(value: any): value is Binary.Source {
|
|
24
|
+
return isArrayBufferLike(value) || ArrayBuffer.isView(value)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Binary source detection and base64/hex conversion helpers. */
|
|
28
|
+
export namespace Binary {
|
|
29
|
+
export type Source<T extends ArrayBufferLike = ArrayBufferLike> = T | ArrayBufferView<T>
|
|
30
|
+
|
|
31
|
+
export const is = isArrayBufferLike
|
|
32
|
+
export const isSource = isArrayBufferSource
|
|
33
|
+
|
|
34
|
+
export function fromSource<T extends ArrayBufferLike>(source: Source<T>): T {
|
|
35
|
+
if (ArrayBuffer.isView(source)) {
|
|
36
|
+
// https://stackoverflow.com/questions/8609289/convert-a-binary-nodejs-buffer-to-javascript-arraybuffer#answer-31394257
|
|
37
|
+
return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength) as T
|
|
38
|
+
} else {
|
|
39
|
+
return source
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function toBase64(source: Source) {
|
|
44
|
+
source = fromSource(source)
|
|
45
|
+
if (typeof Buffer !== 'undefined') {
|
|
46
|
+
return Buffer.from(source).toString('base64')
|
|
47
|
+
}
|
|
48
|
+
let binary = ''
|
|
49
|
+
const bytes = new Uint8Array(source)
|
|
50
|
+
for (let i = 0; i < bytes.byteLength; i++) {
|
|
51
|
+
binary += String.fromCharCode(bytes[i])
|
|
52
|
+
}
|
|
53
|
+
return btoa(binary)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function fromBase64(source: string) {
|
|
57
|
+
if (typeof Buffer !== 'undefined') return fromSource(Buffer.from(source, 'base64'))
|
|
58
|
+
return Uint8Array.from(atob(source), c => c.charCodeAt(0))
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function toHex(source: Source) {
|
|
62
|
+
source = fromSource(source)
|
|
63
|
+
if (typeof Buffer !== 'undefined') return Buffer.from(source).toString('hex')
|
|
64
|
+
return Array.from(new Uint8Array(source), byte => byte.toString(16).padStart(2, '0')).join('')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function fromHex(source: string) {
|
|
68
|
+
if (typeof Buffer !== 'undefined') return fromSource(Buffer.from(source, 'hex'))
|
|
69
|
+
const hex = source.length % 2 === 0 ? source : source.slice(0, source.length - 1)
|
|
70
|
+
const buffer: number[] = []
|
|
71
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
72
|
+
buffer.push(parseInt(`${hex[i]}${hex[i + 1]}`, 16))
|
|
73
|
+
}
|
|
74
|
+
return Uint8Array.from(buffer).buffer
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Decode a base64 string into binary data. */
|
|
79
|
+
export const base64ToArrayBuffer = Binary.fromBase64
|
|
80
|
+
/** Encode binary data as base64. */
|
|
81
|
+
export const arrayBufferToBase64 = Binary.toBase64
|
|
82
|
+
/** Decode a hex string into binary data. */
|
|
83
|
+
export const hexToArrayBuffer = Binary.fromHex
|
|
84
|
+
/** Encode binary data as hex. */
|
|
85
|
+
export const arrayBufferToHex = Binary.toHex
|
|
86
|
+
|
|
87
|
+
/** Deep-clone common JavaScript values while preserving prototypes. */
|
|
88
|
+
export function clone<T>(source: T): T
|
|
89
|
+
/** Deep-clone common JavaScript values while preserving prototypes and cycles. */
|
|
90
|
+
export function clone(source: any, refs = new Map<any, any>()) {
|
|
91
|
+
if (!source || typeof source !== 'object') return source
|
|
92
|
+
if (is('Date', source)) return new Date(source.valueOf())
|
|
93
|
+
if (is('RegExp', source)) return new RegExp(source.source, source.flags)
|
|
94
|
+
if (isArrayBufferLike(source)) return source.slice(0)
|
|
95
|
+
if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength)
|
|
96
|
+
const cached = refs.get(source)
|
|
97
|
+
if (cached) return cached
|
|
98
|
+
if (Array.isArray(source)) {
|
|
99
|
+
const result: any[] = []
|
|
100
|
+
refs.set(source, result)
|
|
101
|
+
source.forEach((value, index) => {
|
|
102
|
+
result[index] = Reflect.apply(clone, null, [value, refs])
|
|
103
|
+
})
|
|
104
|
+
return result
|
|
105
|
+
}
|
|
106
|
+
const result = Object.create(Object.getPrototypeOf(source))
|
|
107
|
+
refs.set(source, result)
|
|
108
|
+
for (const key of Reflect.ownKeys(source)) {
|
|
109
|
+
const descriptor = { ...Reflect.getOwnPropertyDescriptor(source, key) }
|
|
110
|
+
if ('value' in descriptor) {
|
|
111
|
+
descriptor.value = Reflect.apply(clone, null, [descriptor.value, refs])
|
|
112
|
+
}
|
|
113
|
+
Reflect.defineProperty(result, key, descriptor)
|
|
114
|
+
}
|
|
115
|
+
return result
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Compare values recursively, treating two volatile references as equal regardless of value.
|
|
120
|
+
* Strict comparison distinguishes null/undefined, treats opaque objects by identity,
|
|
121
|
+
* compares URLs by normalized href, treats array holes as undefined, and considers distinct cyclic structures unequal.
|
|
122
|
+
* @param a - first value.
|
|
123
|
+
* @param b - second value.
|
|
124
|
+
* @param strict - whether to require strict data equality outside volatile references.
|
|
125
|
+
* @returns whether the values compare equal.
|
|
126
|
+
*/
|
|
127
|
+
export function deepEqual(a: any, b: any, strict?: boolean): boolean {
|
|
128
|
+
const ancestors = new Set<object>()
|
|
129
|
+
function compare(a: any, b: any): boolean {
|
|
130
|
+
if (a === b) return true
|
|
131
|
+
if (isVolatile(a) || isVolatile(b)) return isVolatile(a) && isVolatile(b)
|
|
132
|
+
if (!strict && isNullable(a) && isNullable(b)) return true
|
|
133
|
+
if (typeof a !== typeof b || typeof a !== 'object' || !a || !b) return false
|
|
134
|
+
if (ancestors.has(a)) return false
|
|
135
|
+
|
|
136
|
+
function check<T>(test: (x: any) => x is T, then: (a: T, b: T) => boolean) {
|
|
137
|
+
return test(a) ? test(b) ? then(a, b) : false : test(b) ? false : undefined
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
ancestors.add(a)
|
|
141
|
+
try {
|
|
142
|
+
return check(Array.isArray, (a, b) => {
|
|
143
|
+
if (a.length !== b.length) return false
|
|
144
|
+
for (let index = 0; index < a.length; index++) {
|
|
145
|
+
if (!compare(a[index], b[index])) return false
|
|
146
|
+
}
|
|
147
|
+
return true
|
|
148
|
+
})
|
|
149
|
+
?? check(is('Date'), (a, b) => a.valueOf() === b.valueOf())
|
|
150
|
+
?? check(is('URL'), (a, b) => a.href === b.href)
|
|
151
|
+
?? check(is('RegExp'), (a, b) => a.source === b.source && a.flags === b.flags)
|
|
152
|
+
?? check(isArrayBufferLike, (a, b) => {
|
|
153
|
+
if (a.byteLength !== b.byteLength) return false
|
|
154
|
+
const viewA = new Uint8Array(a)
|
|
155
|
+
const viewB = new Uint8Array(b)
|
|
156
|
+
for (let i = 0; i < viewA.length; i++) {
|
|
157
|
+
if (viewA[i] !== viewB[i]) return false
|
|
158
|
+
}
|
|
159
|
+
return true
|
|
160
|
+
})
|
|
161
|
+
?? ((!strict || [a, b].every(value => Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null))
|
|
162
|
+
&& Object.keys({ ...a, ...b }).every(key => compare(a[key], b[key])))
|
|
163
|
+
} finally {
|
|
164
|
+
ancestors.delete(a)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return compare(a, b)
|
|
168
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/** Shared config references used by schema validators and plugin runtimes. */
|
|
2
|
+
|
|
3
|
+
const write = Symbol.for('cosmokit.volatile.write')
|
|
4
|
+
|
|
5
|
+
/** Recursively readonly data returned by a volatile config reference. */
|
|
6
|
+
export type VolatileSnapshot<T> = T extends object ? { readonly [K in keyof T]: VolatileSnapshot<T[K]> } : T
|
|
7
|
+
|
|
8
|
+
/** A stable reference; keep the reference, or capture its value for one operation only. */
|
|
9
|
+
export interface Volatile<T> {
|
|
10
|
+
/** @returns the current immutable snapshot, including undefined for an absent value. */
|
|
11
|
+
get(): VolatileSnapshot<T>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface WritableVolatile extends Volatile<unknown> {
|
|
15
|
+
[write](value: unknown): void
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function snapshot(value: unknown, ancestors = new Set<object>()): unknown {
|
|
19
|
+
if (typeof value === 'function') throw new TypeError('volatile config cannot contain functions')
|
|
20
|
+
if (value === null || typeof value !== 'object') return value
|
|
21
|
+
if (ancestors.has(value)) throw new TypeError('volatile config cannot contain cycles')
|
|
22
|
+
ancestors.add(value)
|
|
23
|
+
try {
|
|
24
|
+
if (Array.isArray(value)) return Object.freeze(value.map(item => snapshot(item, ancestors)))
|
|
25
|
+
if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
|
|
26
|
+
throw new TypeError('volatile config objects must be plain objects or arrays')
|
|
27
|
+
}
|
|
28
|
+
return Object.freeze(Object.fromEntries(Object.entries(value).map(([key, item]) => [key, snapshot(item, ancestors)])))
|
|
29
|
+
} finally {
|
|
30
|
+
ancestors.delete(value)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Create a detached reference containing an immutable copy of the supplied data.
|
|
36
|
+
* @param value - validated config data; class instances and functions are unsupported.
|
|
37
|
+
* @returns a reference whose value is updated only by its owning runtime.
|
|
38
|
+
*/
|
|
39
|
+
export function createVolatile<T>(value: T): Volatile<T> {
|
|
40
|
+
let current = snapshot(value)
|
|
41
|
+
return Object.freeze({
|
|
42
|
+
get: () => current,
|
|
43
|
+
[write]: (value: unknown) => { current = value },
|
|
44
|
+
}) as Volatile<T>
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Identify references across ESM/CJS copies of the shared library.
|
|
49
|
+
* @param value - a parsed config value.
|
|
50
|
+
* @returns whether the value implements the shared reference protocol.
|
|
51
|
+
*/
|
|
52
|
+
export function isVolatile(value: unknown): value is Volatile<unknown> {
|
|
53
|
+
return typeof value === 'object' && value !== null && write in value
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Collect config references without descending into their snapshots or opaque objects.
|
|
58
|
+
* @internal
|
|
59
|
+
* @param value - parsed config; cyclic ordinary fields are visited once per path.
|
|
60
|
+
* @returns references and their object-key paths, including an empty path for a root reference.
|
|
61
|
+
*/
|
|
62
|
+
export function volatileEntries(value: unknown): { path: string[]; ref: Volatile<unknown> }[] {
|
|
63
|
+
const ancestors = new Set<object>()
|
|
64
|
+
function visit(value: unknown, path: string[]): { path: string[]; ref: Volatile<unknown> }[] {
|
|
65
|
+
if (isVolatile(value)) return [{ path, ref: value }]
|
|
66
|
+
if (!value || typeof value !== 'object' || ancestors.has(value)) return []
|
|
67
|
+
if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) return []
|
|
68
|
+
ancestors.add(value)
|
|
69
|
+
try {
|
|
70
|
+
return Object.entries(value).flatMap(([key, child]) => visit(child, [...path, key]))
|
|
71
|
+
} finally {
|
|
72
|
+
ancestors.delete(value)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return visit(value, [])
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Commit an already validated immutable snapshot from another reference.
|
|
80
|
+
* @internal
|
|
81
|
+
* @param target - the owning plugin's stable reference.
|
|
82
|
+
* @param source - a newly parsed candidate reference.
|
|
83
|
+
*/
|
|
84
|
+
export function updateVolatile(target: Volatile<unknown>, source: Volatile<unknown>): void {
|
|
85
|
+
;(target as WritableVolatile)[write](source.get())
|
|
86
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
|
|
2
|
+
# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
|
|
3
|
+
# After editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/terminal/tool-terminal/README.md
|
|
5
|
+
/:
|
|
6
|
+
en: fc74eecdf1f2ad5b
|
|
7
|
+
zh: dc9c2a28ce96ce67
|
|
8
|
+
/deepseek-ai-dsh-tool-terminal:
|
|
9
|
+
en: 47fa84b67ff171b9
|
|
10
|
+
zh: bbd625bbf85694e1
|
|
11
|
+
/deepseek-ai-dsh-tool-terminal/summary:
|
|
12
|
+
en: c0e810d4279333a5
|
|
13
|
+
zh: 7e79b6a63fa10029
|
|
14
|
+
/deepseek-ai-dsh-tool-terminal/table-of-contents:
|
|
15
|
+
en: d152484eb41ac6b4
|
|
16
|
+
zh: 09388d293f9be9cb
|
|
17
|
+
/deepseek-ai-dsh-tool-terminal/use-this-package:
|
|
18
|
+
en: dcc6b2ac23494026
|
|
19
|
+
zh: f5b755ec75994458
|
|
20
|
+
/deepseek-ai-dsh-tool-terminal/use-this-package/the-six-tools:
|
|
21
|
+
en: 3e9b6211dd72ec64
|
|
22
|
+
zh: aa4cd15195cb43d6
|
|
23
|
+
/deepseek-ai-dsh-tool-terminal/use-this-package/composition:
|
|
24
|
+
en: 4ce2a232b60ff77d
|
|
25
|
+
zh: 3a8a0f13371ca6b9
|
|
26
|
+
/deepseek-ai-dsh-tool-terminal/use-this-package/configuration:
|
|
27
|
+
en: 0af09df923fcb322
|
|
28
|
+
zh: 6d9d766c24c530bc
|
|
29
|
+
/deepseek-ai-dsh-tool-terminal/use-this-package/background-sends:
|
|
30
|
+
en: 2ad49d4f69deb06d
|
|
31
|
+
zh: 5f29972b5feec7e3
|
|
32
|
+
/deepseek-ai-dsh-tool-terminal/use-this-package/observable-outcomes-and-failures:
|
|
33
|
+
en: 321a982fdbbf4ada
|
|
34
|
+
zh: 8c2636e5379815e1
|
|
35
|
+
/deepseek-ai-dsh-tool-terminal/understand-the-implementation:
|
|
36
|
+
en: 6302fca8fef89136
|
|
37
|
+
zh: 6327d56edb798ab2
|
|
38
|
+
/deepseek-ai-dsh-tool-terminal/understand-the-implementation/design-concept:
|
|
39
|
+
en: dc500eeff749a06f
|
|
40
|
+
zh: 9402f5005d7ca338
|
|
41
|
+
/deepseek-ai-dsh-tool-terminal/understand-the-implementation/source-map:
|
|
42
|
+
en: a59f4e76dc926bed
|
|
43
|
+
zh: 24813cb1bd8fbf32
|
|
44
|
+
/deepseek-ai-dsh-tool-terminal/understand-the-implementation/result-bounding:
|
|
45
|
+
en: c1953779a1617d09
|
|
46
|
+
zh: cc6a4a6e76fa021c
|
|
47
|
+
/deepseek-ai-dsh-tool-terminal/understand-the-implementation/ui-render-intents:
|
|
48
|
+
en: 03e5bb37f0c3aada
|
|
49
|
+
zh: 8d51eeb758eabe9c
|
|
50
|
+
/deepseek-ai-dsh-tool-terminal/further-exploration:
|
|
51
|
+
en: 45a0c33ed8104fb1
|
|
52
|
+
zh: ae50c9e583ef4867
|
|
53
|
+
/deepseek-ai-dsh-tool-terminal/model-experience:
|
|
54
|
+
en: 215e7ba838619b7b
|
|
55
|
+
zh: a311da3843709f90
|
|
56
|
+
/deepseek-ai-dsh-tool-terminal/model-experience/system-prompt:
|
|
57
|
+
en: cf78b9dd5596495f
|
|
58
|
+
zh: bd44560f8c2435e8
|
|
59
|
+
/deepseek-ai-dsh-tool-terminal/model-experience/system-prompt/what-the-model-sees:
|
|
60
|
+
en: 99887ae1de81aaeb
|
|
61
|
+
zh: 4846a1d3ea8a3dc3
|
|
62
|
+
/deepseek-ai-dsh-tool-terminal/model-experience/system-prompt/what-the-model-sees/terminal-guidance:
|
|
63
|
+
en: 3ab4211f41e40211
|
|
64
|
+
zh: b730cc3f278be17c
|
|
65
|
+
/deepseek-ai-dsh-tool-terminal/model-experience/system-prompt/token-effect:
|
|
66
|
+
en: c9d6d1a8238b74ab
|
|
67
|
+
zh: 7f4b12d6180b9bac
|
|
68
|
+
/deepseek-ai-dsh-tool-terminal/model-experience/system-prompt/kv-cache-effect:
|
|
69
|
+
en: 7fdc10b826aeeb51
|
|
70
|
+
zh: 998c86c09efe43bd
|
|
71
|
+
/deepseek-ai-dsh-tool-terminal/model-experience/tool-schemas:
|
|
72
|
+
en: 3039bc5e7a796b21
|
|
73
|
+
zh: 6b7a9eaf69c9ea53
|
|
74
|
+
/deepseek-ai-dsh-tool-terminal/model-experience/tool-schemas/what-the-model-sees:
|
|
75
|
+
en: 32127d768242d8c4
|
|
76
|
+
zh: 3095d987d6011f44
|
|
77
|
+
/deepseek-ai-dsh-tool-terminal/model-experience/tool-schemas/token-effect:
|
|
78
|
+
en: 824644a1f5fe76df
|
|
79
|
+
zh: b34c7dd78c5ce3cd
|
|
80
|
+
/deepseek-ai-dsh-tool-terminal/model-experience/tool-schemas/kv-cache-effect:
|
|
81
|
+
en: c8cbbef533bdb90f
|
|
82
|
+
zh: c0b00813b8419f46
|
|
83
|
+
/deepseek-ai-dsh-tool-terminal/model-experience/tool-results-and-task-context:
|
|
84
|
+
en: 54e0c8a019f02479
|
|
85
|
+
zh: 7331b10d1a455d59
|
|
86
|
+
/deepseek-ai-dsh-tool-terminal/model-experience/tool-results-and-task-context/what-the-model-sees:
|
|
87
|
+
en: cc1e88a508d0679e
|
|
88
|
+
zh: a219be277705c0ab
|
|
89
|
+
/deepseek-ai-dsh-tool-terminal/model-experience/tool-results-and-task-context/token-effect:
|
|
90
|
+
en: e4746b7b386944df
|
|
91
|
+
zh: be52cd2fd38276b5
|
|
92
|
+
/deepseek-ai-dsh-tool-terminal/model-experience/tool-results-and-task-context/kv-cache-effect:
|
|
93
|
+
en: ac583ab16185a93c
|
|
94
|
+
zh: 78df55a519b2ec1f
|
|
95
|
+
/deepseek-ai-dsh-tool-terminal/known-limitations-and-deferred-work:
|
|
96
|
+
en: ba974b703d6ed0bc
|
|
97
|
+
zh: 655810d5d338343c
|
|
98
|
+
/deepseek-ai-dsh-tool-terminal/known-limitations-and-deferred-work/dev-note:
|
|
99
|
+
en: a4c4901129addb49
|
|
100
|
+
zh: 78f339ece6da423b
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Six model-facing persistent terminal tools with owner isolation, bounded results, and optional background sends for agents that need cross-call terminal state."
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @deepseek-ai/dsh-tool-terminal
|
|
7
|
+
|
|
8
|
+
English | [中文](README.zh.md)
|
|
9
|
+
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
Use `dsh-tool-terminal` when an agent needs persistent terminal state or interactive input across calls. It can open, send to, read, signal, close, and list terminal sessions while preventing one agent from operating another agent's sessions. Sends may wait for bounded foreground output or return a background job id for later collection or interruption. `maxResultBytes` caps each result, which remains in session history until compaction. The model is guided to prefer one-shot tools for bounded work.
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Use this package](#use-this-package)
|
|
17
|
+
- [Understand the implementation](#understand-the-implementation)
|
|
18
|
+
- [Further Exploration](#further-exploration)
|
|
19
|
+
- [Model Experience](#model-experience)
|
|
20
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
21
|
+
- [Dev Note](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## Use this package
|
|
27
|
+
|
|
28
|
+
Enable these tools when the composition mounts a terminal backend and the model should be able to use terminal state across calls — stepping a debugger, exploring in a REPL, or returning to a shell after interrupting a foreground command. The guidance section steers the model toward the one-shot bash, read, write, and edit tools for bounded operations.
|
|
29
|
+
|
|
30
|
+
### The six tools
|
|
31
|
+
|
|
32
|
+
| Tool | What it does | Result |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `terminal_open` | Creates an owner-scoped session from a backend type | Session id, name, type, pid, status, and bounded startup output |
|
|
35
|
+
| `terminal_send` | Writes text, optionally submitting Enter, and waits for readiness — or starts a background job | Bounded output plus wait and session status, or a job id |
|
|
36
|
+
| `terminal_read` | Reads a bounded page of retained output without sending input | Text with line pagination metadata |
|
|
37
|
+
| `terminal_signal` | Delivers one allowed signal to the foreground process group | `delivered` plus the target process group id |
|
|
38
|
+
| `terminal_close` | Closes a session and waits for its process tree to end | Closed or already-closing outcome |
|
|
39
|
+
| `terminal_list` | Lists the caller's live sessions | Owner-scoped session summaries |
|
|
40
|
+
|
|
41
|
+
### Composition
|
|
42
|
+
|
|
43
|
+
```yaml
|
|
44
|
+
- name: '@deepseek-ai/dsh-terminal'
|
|
45
|
+
- name: '@deepseek-ai/dsh-terminal-bash'
|
|
46
|
+
- name: '@deepseek-ai/dsh-tool-terminal'
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The tools need `ctx.terminals` — a backend must be mounted — and the system-prompt service for the guidance section. Background sends additionally require the jobs service and its model-facing controller (`@deepseek-ai/dsh-tool-jobs`).
|
|
50
|
+
|
|
51
|
+
### Configuration
|
|
52
|
+
|
|
53
|
+
| Field | Default | Meaning |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `enableRunInBackground` | `true` | Expose and accept `run_in_background`; `false` removes the schema field and rejects the argument |
|
|
56
|
+
| `maxResultBytes` | `262144` | UTF-8 cap (minimum `64`) for each complete terminal result after wait, session, pagination, truncation, and job-status metadata |
|
|
57
|
+
|
|
58
|
+
The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-tool-terminal) and [tool catalog](../../../docs/tool-catalog.md#deepseek-aidsh-tool-terminal) are the exhaustive sources for config fields and schemas.
|
|
59
|
+
|
|
60
|
+
### Background sends
|
|
61
|
+
|
|
62
|
+
`terminal_send(run_in_background: true)` returns a job id immediately instead of waiting. The job is collected with `job_output`, which waits and reads incremental output, and stopped with `job_kill`, which delivers a real `SIGINT` to the foreground process group. Background mode fails before writing input when the jobs surface is absent.
|
|
63
|
+
|
|
64
|
+
### Observable outcomes and failures
|
|
65
|
+
|
|
66
|
+
A foreground send returns the terminal's new output plus `wait: <reason>` and the session status; `session_exit` means the top-level shell exited, while `inferred_idle` or `timeout` never proves the foreground command exited. Opening a session with an unregistered backend type fails. Results larger than `maxResultBytes` are truncated at a UTF-8 boundary with a marker.
|
|
67
|
+
|
|
68
|
+
-----
|
|
69
|
+
|
|
70
|
+
<a id="understand-the-implementation"></a>
|
|
71
|
+
## Understand the implementation
|
|
72
|
+
|
|
73
|
+
<details>
|
|
74
|
+
<summary>Implementation internals — click to expand</summary>
|
|
75
|
+
|
|
76
|
+
This section explains the design behind the tools and points at the code that realizes it; the observable behavior is covered in [Use this package](#use-this-package).
|
|
77
|
+
|
|
78
|
+
### Design concept
|
|
79
|
+
|
|
80
|
+
The package is a thin adapter: the six tools forward to `ctx.terminals` with the executing agent as the owner, and the presentation layer renders bounded results. Background sends register the in-flight operation on `ctx.jobs` so the generic job surface owns waiting, incremental reads, and `SIGINT` delivery.
|
|
81
|
+
|
|
82
|
+
### Source map
|
|
83
|
+
|
|
84
|
+
| File | Role |
|
|
85
|
+
|---|---|
|
|
86
|
+
| [`src/index.ts`](src/index.ts) | Six tool definitions, schemas, guidance section, background-job integration |
|
|
87
|
+
| [`src/render.ts`](src/render.ts) | Result rendering and the complete-result UTF-8 cap |
|
|
88
|
+
|
|
89
|
+
### Result bounding
|
|
90
|
+
|
|
91
|
+
Every terminal-owned single-text result is capped by `maxResultBytes` after normalized tool or pipeline errors, policy denials and short-circuits, replacements and blocks, and generic job-status text; cuts preserve UTF-8 boundaries and reserve room for a truncation marker. Structured multi-block policy results retain their shape. The minimum cap of 64 bytes keeps every registry-issued session or job id visible in its creation acknowledgement.
|
|
92
|
+
|
|
93
|
+
### UI render intents
|
|
94
|
+
|
|
95
|
+
Foreground sends use terminal call and result cards; background sends and the other five tools use generic `execute`, `read`, or `delete` cards. None of the tools emits source locations.
|
|
96
|
+
|
|
97
|
+
</details>
|
|
98
|
+
|
|
99
|
+
-----
|
|
100
|
+
|
|
101
|
+
<a id="further-exploration"></a>
|
|
102
|
+
## Further Exploration
|
|
103
|
+
|
|
104
|
+
Read these pages when the package-level contract is not enough. They move from the generated schemas to the service contract, the backend, and the background-job surface.
|
|
105
|
+
|
|
106
|
+
- [Tool catalog](../../../docs/tool-catalog.md#deepseek-aidsh-tool-terminal) — the six generated schemas and result shapes.
|
|
107
|
+
- [Terminal subsystem reference](../../../docs/subsystems/terminal.md) — the service contract and shared types behind the tools.
|
|
108
|
+
- [terminal service](../terminal/README.md) — session operations, owner fencing, and cleanup semantics.
|
|
109
|
+
- [terminal-bash backend](../terminal-bash/README.md) — the shipped shell backend that provides sessions.
|
|
110
|
+
- [jobs package map](../../jobs/README.md) — the background-job surface that collects and kills background sends.
|
|
111
|
+
- [Persistent PTY Agent Note](../../../.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md) — the capability design and deferred boundaries.
|
|
112
|
+
|
|
113
|
+
-----
|
|
114
|
+
|
|
115
|
+
<a id="model-experience"></a>
|
|
116
|
+
## Model Experience
|
|
117
|
+
|
|
118
|
+
### System prompt
|
|
119
|
+
|
|
120
|
+
#### What the model sees
|
|
121
|
+
|
|
122
|
+
The plugin contributes this fixed guidance section:
|
|
123
|
+
|
|
124
|
+
##### Terminal guidance
|
|
125
|
+
|
|
126
|
+
```markdown
|
|
127
|
+
Use a terminal session only when work needs persistent terminal state or interactive stdin; prefer shell/read/write/edit for bounded one-shot operations. Track every terminal session id and close sessions that no longer matter. An inferred_idle or timeout result does not prove the foreground command exited.
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### Token effect
|
|
131
|
+
|
|
132
|
+
Small fixed input cost on every request while the plugin is active.
|
|
133
|
+
|
|
134
|
+
#### KV Cache effect
|
|
135
|
+
|
|
136
|
+
Prefix-stable while the registration scope and guidance text are unchanged.
|
|
137
|
+
|
|
138
|
+
### Tool schemas
|
|
139
|
+
|
|
140
|
+
#### What the model sees
|
|
141
|
+
|
|
142
|
+
The six generated schemas are listed in the [`dsh-tool-terminal` catalog section](../../../docs/tool-catalog.md#deepseek-aidsh-tool-terminal). Their fixed schema tokens are present whenever this plugin is active; agent-scoped tool filtering may hide them.
|
|
143
|
+
|
|
144
|
+
#### Token effect
|
|
145
|
+
|
|
146
|
+
Fixed schema cost on requests where the tools are visible.
|
|
147
|
+
|
|
148
|
+
#### KV Cache effect
|
|
149
|
+
|
|
150
|
+
Prefix-stable while tool visibility and definitions are unchanged.
|
|
151
|
+
|
|
152
|
+
### Tool results and task context
|
|
153
|
+
|
|
154
|
+
#### What the model sees
|
|
155
|
+
|
|
156
|
+
Spawn returns the id and bounded startup output. Send and read return bounded terminal text plus readiness and history markers. Background mode returns a generic job id. Every terminal-owned single-text result is capped by `maxResultBytes`; results remain in session history until compaction, and incremental task reads do not repeat consumed output.
|
|
157
|
+
|
|
158
|
+
#### Token effect
|
|
159
|
+
|
|
160
|
+
Terminal-owned results are data-dependent and bounded by `maxResultBytes`; each returned result stays in history until compaction.
|
|
161
|
+
|
|
162
|
+
#### KV Cache effect
|
|
163
|
+
|
|
164
|
+
Append-only; new results follow the reusable request prefix.
|
|
165
|
+
|
|
166
|
+
## Known Limitations and Deferred Work
|
|
167
|
+
|
|
168
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
These limits define the model-facing surface that is absent. They are current package constraints, not a task backlog.
|
|
172
|
+
|
|
173
|
+
- **No TUI or key-sequence surface** — named key sequences, full-screen TUI interaction, BEL, resize, and auto-start are not exposed in any schema.
|
|
174
|
+
- **Background mode requires the jobs surface** — `run_in_background` needs both `@deepseek-ai/dsh-jobs` and its model-facing controller (`@deepseek-ai/dsh-tool-jobs`); without them the argument is rejected.
|
|
175
|
+
|
|
176
|
+
<a id="dev-note"></a>
|
|
177
|
+
### Dev Note
|
|
178
|
+
|
|
179
|
+
<details>
|
|
180
|
+
<summary>Working context for maintainers — click to expand</summary>
|
|
181
|
+
|
|
182
|
+
None.
|
|
183
|
+
|
|
184
|
+
</details>
|
|
185
|
+
|
|
186
|
+
**Runtime invariant:** No companion is published. This stateless adapter contributes tools and prompt guidance, while PTY lifecycle and background-job relationships remain owned by the services it composes.
|