@sagmans/dsh-tui 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/.agents/skills/dsh-tui-update-models/SKILL.md +95 -17
- package/.agents/skills/dsh-tui-update-models/references/model-wiring.md +158 -28
- package/.agents/skills/dsh-tui-update-models/scripts/dump-model-catalog.mjs +152 -16
- package/README.md +55 -22
- package/lib/herdr/client.d.ts +8 -0
- package/lib/herdr/client.d.ts.map +1 -1
- package/lib/herdr/client.js +13 -1
- package/lib/herdr/client.js.map +1 -1
- package/lib/herdr/constants.d.ts +18 -0
- package/lib/herdr/constants.d.ts.map +1 -1
- package/lib/herdr/constants.js +18 -0
- package/lib/herdr/constants.js.map +1 -1
- package/lib/herdr/reporter.d.ts +20 -4
- package/lib/herdr/reporter.d.ts.map +1 -1
- package/lib/herdr/reporter.js +70 -20
- package/lib/herdr/reporter.js.map +1 -1
- package/lib/herdr/state.d.ts +10 -0
- package/lib/herdr/state.d.ts.map +1 -1
- package/lib/herdr/state.js +21 -4
- package/lib/herdr/state.js.map +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +5 -0
- package/lib/index.js.map +1 -1
- package/lib/install-skills.d.ts +20 -1
- package/lib/install-skills.d.ts.map +1 -1
- package/lib/install-skills.js +84 -9
- package/lib/install-skills.js.map +1 -1
- package/lib/surface/background-work.d.ts +2 -0
- package/lib/surface/background-work.d.ts.map +1 -1
- package/lib/surface/background-work.js +28 -2
- package/lib/surface/background-work.js.map +1 -1
- package/lib/surface/commands.d.ts +2 -0
- package/lib/surface/commands.d.ts.map +1 -1
- package/lib/surface/commands.js +6 -0
- package/lib/surface/commands.js.map +1 -1
- package/lib/surface/modal-input.d.ts +3 -2
- package/lib/surface/modal-input.d.ts.map +1 -1
- package/lib/surface/modal-input.js +14 -8
- package/lib/surface/modal-input.js.map +1 -1
- package/lib/surface/session-lifecycle.d.ts.map +1 -1
- package/lib/surface/session-lifecycle.js +3 -0
- package/lib/surface/session-lifecycle.js.map +1 -1
- package/lib/theme-files.d.ts +1 -1
- package/lib/theme-files.d.ts.map +1 -1
- package/lib/theme-files.js +1 -1
- package/lib/theme-files.js.map +1 -1
- package/lib/theme-settings.d.ts.map +1 -1
- package/lib/theme-settings.js +10 -2
- package/lib/theme-settings.js.map +1 -1
- package/lib/ui/view/tool-card.d.ts +13 -2
- package/lib/ui/view/tool-card.d.ts.map +1 -1
- package/lib/ui/view/tool-card.js +19 -3
- package/lib/ui/view/tool-card.js.map +1 -1
- package/lib/ui/view.d.ts +25 -3
- package/lib/ui/view.d.ts.map +1 -1
- package/lib/ui/view.js +54 -7
- package/lib/ui/view.js.map +1 -1
- package/package.json +1 -1
- package/themes/violet-orbit.yaml +7 -5
|
@@ -8,11 +8,23 @@
|
|
|
8
8
|
* invisible in the UI. This reads the same two inputs the resolver does - the
|
|
9
9
|
* owned catalog in the profile patch, and the installed pi-ai provider data -
|
|
10
10
|
* and names where each number came from: "installed" for the source's own
|
|
11
|
-
* entry, "template:<id>" for a clone, "
|
|
11
|
+
* entry, "template:<id>" for a clone, "route" for the protocol a sourceless
|
|
12
|
+
* route declares once for every model it serves, "metadata" for what the
|
|
13
|
+
* catalog declares.
|
|
14
|
+
*
|
|
12
15
|
* An entry the catalog spells out completely needs no installed entry at all,
|
|
13
|
-
* so a missing harness install must not hide it.
|
|
16
|
+
* so a missing harness install must not hide it. A `filter` route is the
|
|
17
|
+
* exception: its membership is the installed catalog's, so it cannot be read
|
|
18
|
+
* without that install. A declaration the plugin's resolver would refuse is
|
|
19
|
+
* reported as a refusal here too, because a catalog that cannot compose serves
|
|
20
|
+
* nothing.
|
|
21
|
+
*
|
|
22
|
+
* Usage: dump-model-catalog.mjs [--home <dsh home>] [--profile <name>]
|
|
23
|
+
* [--data <pi-ai data dir>] [--json]
|
|
14
24
|
*
|
|
15
|
-
*
|
|
25
|
+
* `--data` names the installed provider-data directory to inherit from, which
|
|
26
|
+
* is how a reading is checked where no harness is installed - a `filter` route
|
|
27
|
+
* and every template clone need one.
|
|
16
28
|
*/
|
|
17
29
|
import { execFileSync } from 'node:child_process'
|
|
18
30
|
import { readFileSync, realpathSync } from 'node:fs'
|
|
@@ -23,9 +35,15 @@ import { fileURLToPath } from 'node:url'
|
|
|
23
35
|
const LEVELS = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max']
|
|
24
36
|
/** Fields a catalog entry may inherit, and the layer each value came from. */
|
|
25
37
|
const INHERITED_FIELDS = ['contextWindow', 'maxTokens', 'cost', 'input', 'reasoning', 'thinkingLevelMap', 'api']
|
|
38
|
+
/** What a model with no installed sibling and no template must state itself. */
|
|
39
|
+
const REQUIRED_METADATA = ['api', 'reasoning', 'input', 'cost', 'contextWindow', 'maxTokens']
|
|
40
|
+
const COST_FIELDS = ['input', 'output', 'cacheRead', 'cacheWrite']
|
|
26
41
|
const INSTALLED = 'installed'
|
|
27
42
|
const METADATA = 'metadata'
|
|
43
|
+
const ROUTE = 'route'
|
|
28
44
|
const ABSENT = 'none'
|
|
45
|
+
/** The only wildcard a `filter` pattern carries; every other character is itself. */
|
|
46
|
+
const WILDCARD = '*'
|
|
29
47
|
|
|
30
48
|
/** The levels pi-ai offers: a null mapping removes one, and xhigh/max need one. */
|
|
31
49
|
export function supportedLevels(levelMap) {
|
|
@@ -38,12 +56,13 @@ export function supportedLevels(levelMap) {
|
|
|
38
56
|
}
|
|
39
57
|
|
|
40
58
|
function parseArgs(argv) {
|
|
41
|
-
const options = { home: process.env.DSH_HOME ?? join(homedir(), '.dsh'), profile: 'tui', json: false }
|
|
59
|
+
const options = { home: process.env.DSH_HOME ?? join(homedir(), '.dsh'), profile: 'tui', data: undefined, json: false }
|
|
42
60
|
for (let index = 0; index < argv.length; index += 1) {
|
|
43
61
|
const flag = argv[index]
|
|
44
62
|
if (flag === '--json') options.json = true
|
|
45
63
|
else if (flag === '--home') options.home = argv[++index]
|
|
46
64
|
else if (flag === '--profile') options.profile = argv[++index]
|
|
65
|
+
else if (flag === '--data') options.data = argv[++index]
|
|
47
66
|
else throw new Error('unknown argument ' + flag)
|
|
48
67
|
}
|
|
49
68
|
return options
|
|
@@ -74,7 +93,7 @@ export function catalogConfig(patch) {
|
|
|
74
93
|
}
|
|
75
94
|
|
|
76
95
|
export function providerData(directory, source) {
|
|
77
|
-
if (directory === undefined) return undefined
|
|
96
|
+
if (directory === undefined || source === undefined) return undefined
|
|
78
97
|
try {
|
|
79
98
|
return JSON.parse(readFileSync(join(directory, source + '.json'), 'utf8'))
|
|
80
99
|
} catch {
|
|
@@ -82,6 +101,28 @@ export function providerData(directory, source) {
|
|
|
82
101
|
}
|
|
83
102
|
}
|
|
84
103
|
|
|
104
|
+
/** Installed models in the order the source publishes them, one api map at a time. */
|
|
105
|
+
function installedModels(data) {
|
|
106
|
+
if (data === undefined) return []
|
|
107
|
+
return Object.entries(data).flatMap(([api, models]) => Object.entries(models)
|
|
108
|
+
.map(([id, model]) => ({ ...model, id, api: model.api ?? api })))
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Mirror the resolver's pattern rule so a filter reads the same here and there. */
|
|
112
|
+
function patternToRegExp(pattern) {
|
|
113
|
+
const escaped = pattern.split(WILDCARD).map(part => part.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
|
|
114
|
+
return new RegExp('^' + escaped.join('.*') + '$')
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** A filter keeps installed facts and order, then drops what exclude names. */
|
|
118
|
+
export function expandFilter(data, filter) {
|
|
119
|
+
const include = filter?.include === undefined ? undefined : filter.include.map(patternToRegExp)
|
|
120
|
+
const exclude = filter?.exclude === undefined ? [] : filter.exclude.map(patternToRegExp)
|
|
121
|
+
return installedModels(data)
|
|
122
|
+
.filter(model => (include === undefined || include.some(pattern => pattern.test(model.id)))
|
|
123
|
+
&& !exclude.some(pattern => pattern.test(model.id)))
|
|
124
|
+
}
|
|
125
|
+
|
|
85
126
|
/** Look one id up across a provider's api maps; an api in the spec disambiguates. */
|
|
86
127
|
function lookup(data, id, api) {
|
|
87
128
|
if (data === undefined) return undefined
|
|
@@ -91,8 +132,13 @@ function lookup(data, id, api) {
|
|
|
91
132
|
return undefined
|
|
92
133
|
}
|
|
93
134
|
|
|
135
|
+
function costOf(cost) {
|
|
136
|
+
if (cost === undefined) return undefined
|
|
137
|
+
return '$' + COST_FIELDS.map(field => cost[field]).join('/') + ' per 1M'
|
|
138
|
+
}
|
|
139
|
+
|
|
94
140
|
/** Resolve one catalog entry against the installed data it may inherit from. */
|
|
95
|
-
export function resolve(spec, data) {
|
|
141
|
+
export function resolve(spec, data, routeApi) {
|
|
96
142
|
const metadata = spec.metadata ?? {}
|
|
97
143
|
const declared = Object.keys(metadata).length > 0
|
|
98
144
|
const cloneOf = spec.template ?? spec.id
|
|
@@ -101,37 +147,88 @@ export function resolve(spec, data) {
|
|
|
101
147
|
return { error: 'no source entry for ' + cloneOf + '; declare a template or metadata' }
|
|
102
148
|
}
|
|
103
149
|
const merged = { ...base, ...metadata, id: spec.id, name: spec.name ?? base?.name ?? spec.id }
|
|
104
|
-
|
|
150
|
+
// A route that names no source states its protocol once, for every model.
|
|
151
|
+
if (merged.api === undefined && routeApi !== undefined) merged.api = routeApi
|
|
152
|
+
// Capacity and the request default are different numbers, and the resolver
|
|
153
|
+
// caps one by the other: folding them would hide the mistake it refuses.
|
|
154
|
+
const capacity = metadata.maxTokens ?? base?.maxTokens
|
|
155
|
+
const missing = base === undefined
|
|
156
|
+
? REQUIRED_METADATA.filter(field => field === 'api' ? merged.api === undefined : metadata[field] === undefined)
|
|
157
|
+
: []
|
|
158
|
+
if (missing.length > 0) return { error: 'unknown model requires complete metadata: missing ' + missing.join(', ') }
|
|
159
|
+
if (spec.defaultMaxTokens !== undefined && capacity !== undefined && spec.defaultMaxTokens > capacity) {
|
|
160
|
+
return { error: 'defaultMaxTokens ' + spec.defaultMaxTokens + ' exceeds model maxTokens ' + capacity }
|
|
161
|
+
}
|
|
105
162
|
const origins = {}
|
|
106
163
|
for (const field of INHERITED_FIELDS) {
|
|
107
|
-
|
|
108
|
-
if (
|
|
164
|
+
if (metadata[field] !== undefined) origins[field] = METADATA
|
|
165
|
+
else if (field === 'api' && base === undefined && routeApi !== undefined) origins[field] = ROUTE
|
|
109
166
|
else if (base === undefined) origins[field] = ABSENT
|
|
110
167
|
else origins[field] = spec.template === undefined ? INSTALLED : 'template:' + spec.template
|
|
111
168
|
}
|
|
112
|
-
return {
|
|
169
|
+
return {
|
|
170
|
+
model: { ...merged, maxTokens: capacity },
|
|
171
|
+
origins,
|
|
172
|
+
levels: supportedLevels(merged.thinkingLevelMap),
|
|
173
|
+
...(spec.defaultMaxTokens === undefined ? {} : { requestMax: spec.defaultMaxTokens }),
|
|
174
|
+
...(spec.aliases === undefined ? {} : { aliases: spec.aliases.join(',') }),
|
|
175
|
+
...(metadata.cost?.tiers === undefined ? {} : {
|
|
176
|
+
tiers: metadata.cost.tiers.map(tier => 'above ' + tier.inputTokensAbove + ': ' + costOf(tier)).join('; '),
|
|
177
|
+
}),
|
|
178
|
+
}
|
|
113
179
|
}
|
|
114
180
|
|
|
115
181
|
function rowsOf(catalog, directory) {
|
|
116
182
|
const rows = []
|
|
117
183
|
for (const provider of catalog.providers ?? []) {
|
|
118
184
|
const data = providerData(directory, provider.source)
|
|
185
|
+
const hasModels = 'models' in provider
|
|
186
|
+
const hasFilter = 'filter' in provider
|
|
187
|
+
// The resolver refuses both and neither; saying so here beats serving half.
|
|
188
|
+
if (hasModels === hasFilter) {
|
|
189
|
+
rows.push({ route: provider.id, error: 'declare exactly one of models or filter' })
|
|
190
|
+
continue
|
|
191
|
+
}
|
|
192
|
+
if (hasFilter) {
|
|
193
|
+
if (data === undefined) {
|
|
194
|
+
rows.push({
|
|
195
|
+
route: provider.id,
|
|
196
|
+
error: 'filter expands the installed catalog of source "' + provider.source + '"; no harness install found',
|
|
197
|
+
})
|
|
198
|
+
continue
|
|
199
|
+
}
|
|
200
|
+
for (const model of expandFilter(data, provider.filter)) {
|
|
201
|
+
rows.push({
|
|
202
|
+
route: provider.id + '/' + model.id,
|
|
203
|
+
name: model.name ?? model.id,
|
|
204
|
+
api: model.api,
|
|
205
|
+
contextWindow: model.contextWindow,
|
|
206
|
+
maxTokens: model.maxTokens,
|
|
207
|
+
cost: costOf(model.cost),
|
|
208
|
+
levels: supportedLevels(model.thinkingLevelMap).join(','),
|
|
209
|
+
origins: 'filter:' + (provider.filter.include ?? [WILDCARD]).join(',') + ' all installed',
|
|
210
|
+
})
|
|
211
|
+
}
|
|
212
|
+
continue
|
|
213
|
+
}
|
|
119
214
|
for (const spec of provider.models ?? []) {
|
|
120
|
-
const result = resolve(spec, data)
|
|
215
|
+
const result = resolve(spec, data, provider.api)
|
|
121
216
|
const route = provider.id + '/' + spec.id
|
|
122
217
|
if (result.error !== undefined) {
|
|
123
218
|
rows.push({ route, error: result.error })
|
|
124
219
|
continue
|
|
125
220
|
}
|
|
126
|
-
const cost = result.model.cost ?? {}
|
|
127
221
|
rows.push({
|
|
128
222
|
route,
|
|
129
223
|
name: result.model.name,
|
|
130
224
|
api: result.model.api,
|
|
131
225
|
contextWindow: result.model.contextWindow,
|
|
132
226
|
maxTokens: result.model.maxTokens,
|
|
133
|
-
cost:
|
|
227
|
+
cost: costOf(result.model.cost),
|
|
134
228
|
levels: result.levels.join(','),
|
|
229
|
+
...(result.requestMax === undefined ? {} : { requestMax: result.requestMax }),
|
|
230
|
+
...(result.aliases === undefined ? {} : { aliases: result.aliases }),
|
|
231
|
+
...(result.tiers === undefined ? {} : { tiers: result.tiers }),
|
|
135
232
|
origins: INHERITED_FIELDS
|
|
136
233
|
.map(field => [field, result.origins[field]])
|
|
137
234
|
.filter(([, origin]) => origin !== INSTALLED)
|
|
@@ -143,6 +240,39 @@ function rowsOf(catalog, directory) {
|
|
|
143
240
|
return rows
|
|
144
241
|
}
|
|
145
242
|
|
|
243
|
+
/**
|
|
244
|
+
* The default is part of the catalog, not a comment beside it: the resolver
|
|
245
|
+
* refuses a selection nothing serves, so a reading that skipped it would call a
|
|
246
|
+
* broken catalog readable.
|
|
247
|
+
*/
|
|
248
|
+
export function checkDefault(catalog, rows) {
|
|
249
|
+
const served = rows.filter(row => row.error === undefined)
|
|
250
|
+
const selection = catalog.default ?? null
|
|
251
|
+
if (served.length === 0) {
|
|
252
|
+
return selection === null ? [] : [{ route: 'default', error: 'an empty catalog requires default null' }]
|
|
253
|
+
}
|
|
254
|
+
if (selection === null || typeof selection !== 'object') {
|
|
255
|
+
return [{ route: 'default', error: 'a served catalog requires a default selection' }]
|
|
256
|
+
}
|
|
257
|
+
const alias = new Map()
|
|
258
|
+
for (const provider of catalog.providers ?? []) {
|
|
259
|
+
for (const model of provider.models ?? []) {
|
|
260
|
+
for (const name of [model.id, ...(model.aliases ?? [])]) alias.set(provider.id + '/' + name, model.id)
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
const route = selection.provider + '/' + selection.model
|
|
264
|
+
const canonical = alias.get(route)
|
|
265
|
+
const row = served.find(candidate => candidate.route === selection.provider + '/' + (canonical ?? selection.model))
|
|
266
|
+
if (row === undefined) {
|
|
267
|
+
return [{ route: 'default', error: 'provider/model is outside the managed selection: ' + route }]
|
|
268
|
+
}
|
|
269
|
+
const effort = selection.reasoningEffort
|
|
270
|
+
if (effort !== undefined && !String(row.levels).split(',').includes(effort)) {
|
|
271
|
+
return [{ route: 'default', error: 'effort is not supported by the selected model: ' + effort }]
|
|
272
|
+
}
|
|
273
|
+
return []
|
|
274
|
+
}
|
|
275
|
+
|
|
146
276
|
function main() {
|
|
147
277
|
const options = parseArgs(process.argv.slice(2))
|
|
148
278
|
const patch = join(options.home, 'profiles', options.profile, 'cordis.patch.yml')
|
|
@@ -152,11 +282,12 @@ function main() {
|
|
|
152
282
|
+ 'this profile wires models another way; see references/model-wiring.md\n')
|
|
153
283
|
process.exit(1)
|
|
154
284
|
}
|
|
155
|
-
const directory = dataDirectory()
|
|
285
|
+
const directory = options.data ?? dataDirectory()
|
|
156
286
|
if (directory === undefined) {
|
|
157
287
|
process.stderr.write('no harness install found; entries that inherit from it cannot be checked\n')
|
|
158
288
|
}
|
|
159
|
-
const
|
|
289
|
+
const served = rowsOf(catalog, directory)
|
|
290
|
+
const rows = [...served, ...checkDefault(catalog, served)]
|
|
160
291
|
const unresolved = rows.filter(row => row.error !== undefined).length
|
|
161
292
|
if (options.json) {
|
|
162
293
|
process.stdout.write(JSON.stringify({ default: catalog.default ?? null, rows }, null, 2) + '\n')
|
|
@@ -167,7 +298,12 @@ function main() {
|
|
|
167
298
|
continue
|
|
168
299
|
}
|
|
169
300
|
process.stdout.write(row.route + '\n ' + row.name + ' | ' + row.api + ' | ctx ' + row.contextWindow
|
|
170
|
-
+ ' | max ' + row.maxTokens
|
|
301
|
+
+ ' | max ' + row.maxTokens
|
|
302
|
+
+ (row.requestMax === undefined ? '' : ' | req ' + row.requestMax)
|
|
303
|
+
+ ' | ' + row.cost
|
|
304
|
+
+ (row.tiers === undefined ? '' : ' | tiers ' + row.tiers)
|
|
305
|
+
+ ' | efforts ' + row.levels
|
|
306
|
+
+ (row.aliases === undefined ? '' : ' | aliases ' + row.aliases) + '\n inherited: ' + row.origins + '\n')
|
|
171
307
|
}
|
|
172
308
|
process.stdout.write('default: ' + JSON.stringify(catalog.default ?? null) + '\n')
|
|
173
309
|
}
|
package/README.md
CHANGED
|
@@ -57,6 +57,20 @@ The command stages the new copy before replacement and restores the old
|
|
|
57
57
|
copy if replacement fails. If cleanup fails after replacement, the new copy
|
|
58
58
|
stays installed and the command reports the old backup path.
|
|
59
59
|
|
|
60
|
+
A started session compares every installed copy with the skills this build
|
|
61
|
+
ships and prints one line when they differ, because an agent loading a stale
|
|
62
|
+
skill is told the old wiring:
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
bundled skills changed since they were installed: dsh-tui-update-models · run dsh --profile tui install-skills --update
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The comparison reads content only, over the files this package ships: a
|
|
69
|
+
helper's execute bit is the installer's own doing, and a note kept beside a
|
|
70
|
+
skill stays unremarked. A skill that was never installed is not drift — a first
|
|
71
|
+
install is the prompt above — and a run that never opens the screen, like
|
|
72
|
+
`list-models`, prints nothing.
|
|
73
|
+
|
|
60
74
|
### Confirm the plugin mounted
|
|
61
75
|
|
|
62
76
|
The profile records its layers in `$DSH_HOME/profiles/tui/package.json` (`~/.dsh` by default). `@sagmans/dsh-tui` must appear in `dsh.profile.bundles`:
|
|
@@ -167,7 +181,7 @@ force, and the `keys:` section moves any of them — see [Keys](#keys).
|
|
|
167
181
|
| Ctrl+C | take back one thing at a time: the draft in the bar, the prompts waiting in the agent's inbox, the running turn, or a child's conversation; with a picker, an approval, a question, or the transcript search open it closes that instead. With nothing left to cancel it does nothing — it never leaves |
|
|
168
182
|
| Ctrl+D | leave and print the resume command, when the bar holds no text and nothing is open; a running turn is cancelled first |
|
|
169
183
|
| Ctrl+O | open every tool card: its header plus every retained row. Folded, a card is one line, and a shell card keeps its command plus the last 20 rows of output with a hint naming what it dropped |
|
|
170
|
-
| Ctrl+Y | show or hide the calls a PTC program dispatched: one two-space-indented row per call under its `run_code` card, named and argued from the tool's own header and cut at the screen edge; clicking one row opens that call in full — the change it declared, then what it produced — for every tool, a failed call included;
|
|
184
|
+
| Ctrl+Y | show or hide the calls a PTC program dispatched: one two-space-indented row per call under its `run_code` card, named and argued from the tool's own header and cut at the screen edge; clicking the card's own header does the same for that card alone, and one level only — the program's own rows stay under `Ctrl+O`; clicking one call's row opens that call in full — the change it declared, then what it produced — for every tool, a failed call included; hidden by default |
|
|
171
185
|
| Shift+Tab | expand or fold every thought behind the answers: folded, the row names itself, its token count, and the key; opened, it adds the thought, laid out as markdown; a click decides for one thought instead |
|
|
172
186
|
| Ctrl+T | pick the reasoning effort for the next step |
|
|
173
187
|
| Ctrl+R | reverse-search recorded prompts: the list opens filtered by whatever is in the bar, `enter` puts one back, `esc` keeps the draft |
|
|
@@ -370,8 +384,8 @@ code. Released hosts with section APIs store preferences in
|
|
|
370
384
|
|
|
371
385
|
```yaml
|
|
372
386
|
dsh-tui:
|
|
373
|
-
theme:
|
|
374
|
-
subcalls:
|
|
387
|
+
theme: deepseek-blue # restyle the whole surface by name (default: violet-orbit)
|
|
388
|
+
subcalls: inline # draw the calls a PTC program dispatched (default collapsed)
|
|
375
389
|
mermaid: streaming # draw a reply's mermaid fences: off, final, or streaming (default streaming)
|
|
376
390
|
tools:
|
|
377
391
|
default: { collapsed: true, output: hidden } # how every tool's card starts
|
|
@@ -462,11 +476,12 @@ keymap on the next press, and `/theme` shows each element's effective value and
|
|
|
462
476
|
whether it came from an override, the palette, or the default.
|
|
463
477
|
|
|
464
478
|
|
|
465
|
-
The section is not only shades. By default
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
479
|
+
The section is not only shades. By default a PTC program's card arrives alone,
|
|
480
|
+
and `subcalls: inline` draws one row per call it dispatched under that card
|
|
481
|
+
instead — or one click on the card's own header, for that card alone.
|
|
482
|
+
`Ctrl+Y` toggles the same choice for the current session, and an edit to the
|
|
483
|
+
document re-seeds it. An unknown key or value is refused with a notice naming
|
|
484
|
+
it, so a typo cannot quietly do nothing.
|
|
470
485
|
|
|
471
486
|
The `tools` block decides how each tool's cards draw. `collapsed` starts a
|
|
472
487
|
tool folded to one header row (default `true`), and `output` is `hidden`
|
|
@@ -480,8 +495,11 @@ profile mounts. Clicking a card opens or folds that one message, and a dispatche
|
|
|
480
495
|
call's row opens on the same click to what the tool itself drew for it — an
|
|
481
496
|
edit's diff in the diff colours, a read's numbered lines, a command and its
|
|
482
497
|
output — followed by the outcome it produced; a call that failed opens to the
|
|
483
|
-
reason it reported instead of rows for work that never happened.
|
|
484
|
-
|
|
498
|
+
reason it reported instead of rows for work that never happened. A program's
|
|
499
|
+
card opens one level at a time: its own row draws the calls, and the rows below
|
|
500
|
+
them — what the program returned — are the card's, so a click on each answers
|
|
501
|
+
for what it drew. `Ctrl+O` still decides for every message nobody clicked, and
|
|
502
|
+
`Ctrl+Y` for every program whose own header nobody clicked.
|
|
485
503
|
|
|
486
504
|
The `history` block tunes the prompt history. `enabled: false` stops recording
|
|
487
505
|
and offering it; `ghost: false` keeps reverse search but stops the dimmed
|
|
@@ -520,9 +538,9 @@ leaving a gap, and `NO_COLOR` draws the fence as plain text. `/export` and the
|
|
|
520
538
|
session file still keep the fence exactly as the model wrote it.
|
|
521
539
|
|
|
522
540
|
A theme restyles the whole surface by name, and a theme is a file. The package
|
|
523
|
-
ships two: `
|
|
524
|
-
|
|
525
|
-
|
|
541
|
+
ships two: `violet-orbit`, a port of pi's theme of that name — its palette, plus
|
|
542
|
+
the elements it draws its own way — and `deepseek-blue`, the table written out
|
|
543
|
+
in full in the colours the project answers to. `violet-orbit` is also what a
|
|
526
544
|
document naming no theme draws, so the default look is a file you can read, list,
|
|
527
545
|
and copy rather than a table compiled in. Your own themes live in
|
|
528
546
|
`$DSH_HOME/themes/`, which the surface creates at start-up and watches, so saving
|
|
@@ -712,7 +730,7 @@ The fold is durable-only: the live stream decorates the row that is still being
|
|
|
712
730
|
|
|
713
731
|
Tool cards are folded by default: a card draws one header row — the tool, its argument clipped to the configured budget, and the facts the result measured — so a long read, diff, or search cannot bury the conversation. A call that has not answered yet names itself in the running colour, `tool.running.title`, and ends that row with the whole seconds it has been waiting, in `tool.running.elapsed`, once it has waited one, so a reader can tell the call they are watching from the one below it that already finished; both give way to the measured facts the moment the result lands. A call that failed names itself in the failed colour, `tool.failed.title` — including a shell whose command exited non-zero or died on a signal, which is a failure whether or not the tool that ran it said so. A shell card's row also carries the exit status and the count of output rows waiting behind the fold, because its output is the answer the reader asked for and a fold that left no trace of it would read as a call that produced nothing. Clicking a card opens or folds that one message; `Ctrl+O` opens or folds every card at once, and `tools:` in the [settings](#settings) decides how each tool starts and whether a fold hides its rows or keeps a `tail` of them.
|
|
714
732
|
|
|
715
|
-
A PTC card is the one card with children: every call the `run_code` program dispatched hangs off the card that made it, and each draws under the header as the tool's own name and argument, on one row cut at the screen edge whether the card itself is open or folded — a program's work must stay legible without opening its card. Each of those rows names its own call in the colour of what that call is doing — `tool.subcall.running` while the program is waiting on it, `tool.failed.title` when it failed, and `tool.subcall.title` once it is back — and a settled row keeps the one line the tool itself drew about its outcome, in `tool.terminal.status` where that tool declares one. A shell call therefore reads `bash pnpm test · exit 0` when it worked and the same row in red, with `exit 1`, when it did not, so a program's work reads row by row without opening the card. The program's own row is the one card that shows no mark: its timer is what says it is still running, and it is also what the card keeps when the program answers — the total it ran for, drawn in `tool.elapsed.done`, dimmed and italic, because the work it measured is over. Clicking one of those rows opens that call's argument in full and leaves its neighbours and the card as they were; a shell call also brings back the rows it printed, because the program's return value is all the card itself keeps. `Ctrl+Y` hides or shows them all, and `subcalls: collapsed
|
|
733
|
+
A PTC card is the one card with children: every call the `run_code` program dispatched hangs off the card that made it, and once shown, each draws under the header as the tool's own name and argument, on one row cut at the screen edge whether the card itself is open or folded — a program's work must stay legible without opening its card. Those rows start folded, because a program can dispatch hundreds of calls and what a reader came for is the answer they produced: one click on the card's own header draws them for that card and for that card alone, `Ctrl+Y` draws them for every card at once, and `subcalls:` decides what a session starts with. Nothing else arrives with that click: the program's own rows are the level below, and `Ctrl+O` is what opens them. Each of those rows names its own call in the colour of what that call is doing — `tool.subcall.running` while the program is waiting on it, `tool.failed.title` when it failed, and `tool.subcall.title` once it is back — and a settled row keeps the one line the tool itself drew about its outcome, in `tool.terminal.status` where that tool declares one. A shell call therefore reads `bash pnpm test · exit 0` when it worked and the same row in red, with `exit 1`, when it did not, so a program's work reads row by row without opening the card. The program's own row is the one card that shows no mark: its timer is what says it is still running, and it is also what the card keeps when the program answers — the total it ran for, drawn in `tool.elapsed.done`, dimmed and italic, because the work it measured is over. Clicking one of those rows opens that call's argument in full and leaves its neighbours and the card as they were; a shell call also brings back the rows it printed, because the program's return value is all the card itself keeps. `Ctrl+Y` hides or shows them all, and `subcalls: collapsed`, the shipped default, starts every session with them hidden; see [Settings](#settings).
|
|
716
734
|
|
|
717
735
|
A card's header names the tool, then the argument the call was made with — a path or a command — in the `tool.args` colour, then the facts the result measured: a read reports its line range, line count, and token size; a file change that carried no prior content to compare against reports its lines and tokens; one that did reports added, changed, and removed lines as `+n ~n -n` in green, yellow, and red. Each stat is its own token, so any of them can be recoloured or hidden independently, and so are the elements a call in flight is drawn with — hiding `tool.running.elapsed` leaves the name in its running colour, hiding `tool.running.title` leaves the seconds counting, hiding `tool.elapsed.done` takes the total off a program's settled row, and a dispatched row is toned the same way per state with `tool.subcall.running` and `tool.subcall.title`. A state is only how a name is painted, so hiding one of those colours leaves the name in the colour a call with no state is read in rather than taking the name away.
|
|
718
736
|
|
|
@@ -751,15 +769,29 @@ The list the dock and `/todo` draw follows the same lifetime every other surface
|
|
|
751
769
|
|---|---|
|
|
752
770
|
| the screen is taken, before any session opens | `idle`, claiming the pane's agent row |
|
|
753
771
|
| the agent's driver starts, including a run of turns chained through pending work | `working` |
|
|
754
|
-
|
|
|
755
|
-
| the
|
|
756
|
-
| the
|
|
772
|
+
| a subagent or background job remains live after the driver stops | `working` until the last one settles |
|
|
773
|
+
| an approval or a question takes the keyboard | `blocked`, with that card's title sent along, and set as the `blocked` display label |
|
|
774
|
+
| the decision settles | `working` if the driver or background work is running, otherwise `idle` |
|
|
775
|
+
| the agent's driver stops with no live subagent or job | `idle` |
|
|
757
776
|
| a session opens, resumes, forks, or is switched to | its id and reason, plus the `dsh_session` / `dsh_cwd` pane tokens |
|
|
758
777
|
| exit, signal, or boot failure | `herdr pane release-agent`, so no row is left waiting on a process that is gone |
|
|
759
778
|
|
|
760
|
-
A
|
|
779
|
+
A picker is deliberately absent from that table. Herdr answers a transition into `blocked` with a needs-attention notification and its sound, and 0.9.1 plays it for the focused pane of the active tab as well as for a background one, so a menu the reader opened themselves would ring for their own navigation — once per menu, on the model picker and the reasoning picker behind it — and the row would read as an agent stuck on a decision it never asked for. A gate is the opposite case: the agent asked, and may have asked somebody who walked away.
|
|
780
|
+
|
|
781
|
+
A wait outranks running work: an agent waiting on a human is not making progress, and the wait is the only thing worth acting on from a wall of panes. The pane follows the agent's driver and the live subagents and jobs it owns. The harness chains turns through a pending inbox inside one driver run, and reporting each turn's end would read as done between two turns of an agent that is still working. A parent driver can also stop while a delegated child or job continues, so its idle transition alone does not make the pane done. The job registry announces settlement before its completion notice wakes the parent, so the pane checks for idle after that handoff instead of briefly announcing done in the middle. Reports are sequenced per source, so a delivery that arrives late cannot undo the state the surface already moved past, and a state Herdr is already showing is not sent again. A report is only counted as made when Herdr acknowledges it: one that failed is tried again — soon after, then with a growing wait — and a session identity Herdr never confirmed travels with the next report of any kind. The retry cannot wait for another state change, because the pane may have nothing left to say: a driver that stopped while the socket was down produces no further event. States still waiting to be sent are collapsed into the newest one, so a socket that was down for a minute is told where the pane is rather than where it has been. The release carries the next number in that same sequence for the same reason: Herdr reads one that cannot beat the pane's last report as stale, and a stale release leaves the row waiting on a process that is gone. It also stops reporting first — a claim landing after the release would take the row back for a process that is leaving — and the report already on the wire is waited for before the row goes back, because Herdr ignores the release of a pane nothing has claimed yet and that late report would then claim it. What is still waiting behind it is dropped rather than sent.
|
|
782
|
+
|
|
783
|
+
Herdr persists a session reference only for its own built-in integrations, so this pane's session identity travels as metadata tokens instead: a script or a companion plugin reads them back with `herdr pane get <id>` and resumes that exact conversation with `dsh --profile tui --resume=<id>`. Herdr holds a token value up to 80 characters and shortens anything longer, so a session id or directory that cannot be sent whole has its token cleared instead: a shortened path would read as a different directory, and a pane must not claim one. What Herdr cannot do is identify the process itself — its detection table and its screen rules both name built-in agents only — so a pane that has not reported yet reads as an ordinary pane, and is not yet a target: `herdr agent wait` on it fails with `agent_not_found` until the first report lands. Herdr 0.9.1 keeps the title that accompanies a `blocked` state without drawing it anywhere, so the same title is sent again as that state's display label — the one Herdr's sidebar renders through its `state_text` token. The complete default agent rows do not include it:
|
|
784
|
+
|
|
785
|
+
```toml
|
|
786
|
+
[ui.sidebar.agents]
|
|
787
|
+
rows = [
|
|
788
|
+
["state_icon", "machine", "workspace", "tab"],
|
|
789
|
+
["state_text"],
|
|
790
|
+
["agent"],
|
|
791
|
+
]
|
|
792
|
+
```
|
|
761
793
|
|
|
762
|
-
|
|
794
|
+
With that row present, a pane waiting on a decision names the tool that asked instead of showing a colour alone. A label longer than the 80 characters Herdr holds whole is cut here rather than server-side, so the ellipsis lands where this surface put it; the message that rides the state report keeps its own, longer bound.
|
|
763
795
|
|
|
764
796
|
## Development
|
|
765
797
|
|
|
@@ -776,6 +808,7 @@ pnpm run build
|
|
|
776
808
|
node tools/pty-drive.mjs --prompt 'Reply with exactly: pong'
|
|
777
809
|
node tools/pty-drive.mjs --prompt 'Run: echo hi' --approve 20 # answer the approval gate
|
|
778
810
|
node tools/pty-drive.mjs --home /tmp/scratch-home --seconds 20 # no credentials: proves failures are visible
|
|
811
|
+
node tools/pty-drive.mjs --prompt 'Run: echo hi' --click 20:12 # press the left button at row 12
|
|
779
812
|
```
|
|
780
813
|
|
|
781
814
|
Keep verification off your real home: install the profile into a throwaway one and copy only the credentials it needs.
|
|
@@ -805,11 +838,11 @@ The automated checks drive a real PTY, but they run on this machine's terminal.
|
|
|
805
838
|
| `NO_COLOR=1 dsh --profile tui` | no styling anywhere, layout unchanged |
|
|
806
839
|
| `dsh --profile tui --no-bell` | a turn that runs for minutes still ends silently |
|
|
807
840
|
| `dsh --profile tui --preset ptc`, then a turn | the status line names `ptc`, and the agent reaches its tools through one TypeScript program rather than one shell call at a time |
|
|
808
|
-
| a PTC turn | one row per
|
|
841
|
+
| a PTC turn | the `run_code` card arrives alone, whatever the program dispatched; `ctrl+y` draws one row per call two spaces indented under it without opening it, and a click on the card's own header does the same for that card — and for that card alone, one level, with the program's own rows still behind `ctrl+o` |
|
|
809
842
|
| that turn, then a click on one of those rows | that call unfolds in full at the same indent: its argument, then what the tool itself drew — an edit's diff in the diff colours, a read's lines, a shell's output — and its neighbours and the card stay as they were |
|
|
810
843
|
| a PTC turn in which a dispatched call failed, then a click on that red row | the row opens to the reason the call reported, and a click on those rows folds it back |
|
|
811
|
-
| that same turn, then `ctrl+y` | the rows
|
|
812
|
-
| `dsh-tui: { subcalls:
|
|
844
|
+
| that same turn, then `ctrl+y` | the rows draw under the folded card; `ctrl+y` again folds them away, and one click on the card's own header does the same for that card alone |
|
|
845
|
+
| `dsh-tui: { subcalls: inline }` in `$DSH_HOME/settings.yaml`, then a PTC turn | the one-line calls draw under the card; deleting the key folds them away |
|
|
813
846
|
| a thought, folded | a click on the row opens the thought under its summary; a click on the body folds it back, and the other thoughts keep their own state |
|
|
814
847
|
| a bash card, then a click on it | the row opens to its command, its retained output, and its exit status; a click folds it back to one row |
|
|
815
848
|
| a bash command that exits non-zero | the same row as any other failure: the tool's name in the failed colour, with the `exit 1` it ended on |
|
package/lib/herdr/client.d.ts
CHANGED
|
@@ -29,6 +29,14 @@ export interface HerdrClient {
|
|
|
29
29
|
reportState(report: StateReport): Promise<boolean>;
|
|
30
30
|
reportSession(report: SessionReport): Promise<boolean>;
|
|
31
31
|
reportMetadata(tokens: Readonly<Record<string, string | undefined>>): Promise<boolean>;
|
|
32
|
+
/**
|
|
33
|
+
* What Herdr writes for a blocked row, or the request to forget that label.
|
|
34
|
+
*
|
|
35
|
+
* A separate channel from the state report because Herdr keeps a wait's
|
|
36
|
+
* message without rendering it: the display label is the one its sidebar
|
|
37
|
+
* reads, so naming the decision the reader owes needs both.
|
|
38
|
+
*/
|
|
39
|
+
reportStateLabel(label: string | undefined): Promise<boolean>;
|
|
32
40
|
/** Stop accepting reports and drop the ones still waiting. */
|
|
33
41
|
stop(): void;
|
|
34
42
|
/** Wait until the transport has finished everything it took on. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/herdr/client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/herdr/client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAaL,KAAK,UAAU,EACf,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAA;AAEvB,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;AAE3E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;CACvC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAA;CACpC;AAED,MAAM,WAAW,WAAW;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAClD,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACtD,cAAc,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACtF;;;;;;OAMG;IACH,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7D,8DAA8D;IAC9D,IAAI,IAAI,IAAI,CAAA;IACZ,mEAAmE;IACnE,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACxB;AAsBD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,gBAA8B,EAAE,OAAO,GAAE,kBAAuB,GAAG,WAAW,CAwHpH;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAMlH;AAED,iDAAiD;AACjD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD"}
|
package/lib/herdr/client.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* off stdout and stderr — the alternate screen owns both.
|
|
8
8
|
*/
|
|
9
9
|
import { createConnection } from 'node:net';
|
|
10
|
-
import { DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT_MS, HERDR_AGENT, HERDR_ENV_FLAG, HERDR_ENV_VAR, HERDR_PANE_ID_VAR, HERDR_SOCKET_PATH_VAR, HERDR_SOURCE, MAX_METADATA_VALUE_CHARS, MAX_RESPONSE_BYTES, RESPONSE_DELIMITER, } from "./constants.js";
|
|
10
|
+
import { DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT_MS, HERDR_AGENT, HERDR_ENV_FLAG, HERDR_ENV_VAR, HERDR_PANE_ID_VAR, HERDR_SOCKET_PATH_VAR, HERDR_SOURCE, HERDR_STATES, MAX_METADATA_VALUE_CHARS, MAX_RESPONSE_BYTES, RESPONSE_DELIMITER, } from "./constants.js";
|
|
11
11
|
/**
|
|
12
12
|
* Create the client for one pane.
|
|
13
13
|
*
|
|
@@ -99,6 +99,18 @@ export function createHerdrClient(env = process.env, options = {}) {
|
|
|
99
99
|
tokens: acceptedTokens(tokens),
|
|
100
100
|
}, false);
|
|
101
101
|
},
|
|
102
|
+
reportStateLabel(label) {
|
|
103
|
+
// Not coalescing on purpose: a coalescing entry supersedes every coalescing
|
|
104
|
+
// one already queued, so a label riding that channel would silently drop a
|
|
105
|
+
// state report still waiting to be sent. The label is display-only and the
|
|
106
|
+
// queue is serial, so arrival order is all the ordering it needs.
|
|
107
|
+
return enqueue('pane.report_metadata', {
|
|
108
|
+
applies_to_source: HERDR_SOURCE,
|
|
109
|
+
...(label === undefined
|
|
110
|
+
? { clear_state_labels: true }
|
|
111
|
+
: { state_labels: { [HERDR_STATES.blocked]: label } }),
|
|
112
|
+
}, false);
|
|
113
|
+
},
|
|
102
114
|
stop() {
|
|
103
115
|
// Nothing still waiting is sent once the pane stops being an agent: Herdr
|
|
104
116
|
// ignores the release of a pane nothing has claimed, so a report that
|
package/lib/herdr/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/herdr/client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAC3C,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,WAAW,EACX,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EACrB,YAAY,EACZ,wBAAwB,EACxB,kBAAkB,EAClB,kBAAkB,GAGnB,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/herdr/client.ts"],"names":[],"mappings":"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"}
|
package/lib/herdr/constants.d.ts
CHANGED
|
@@ -60,6 +60,8 @@ export declare const DEFAULT_ATTEMPTS = 2;
|
|
|
60
60
|
export declare const DEFAULT_TIMEOUT_MS = 500;
|
|
61
61
|
/** A release on the way out cannot outlive the process that owes it. */
|
|
62
62
|
export declare const EXIT_RELEASE_TIMEOUT_MS = 250;
|
|
63
|
+
/** The CLI to release through when the one Herdr exported cannot be spawned. */
|
|
64
|
+
export declare const FALLBACK_HERDR_BIN = "herdr";
|
|
63
65
|
/** The first wait before a report Herdr did not acknowledge is sent again. */
|
|
64
66
|
export declare const RETRY_BASE_MS = 250;
|
|
65
67
|
/** The longest that wait can grow to, so a down socket is still noticed. */
|
|
@@ -83,6 +85,22 @@ export declare const MAX_METADATA_VALUE_CHARS = 80;
|
|
|
83
85
|
* whole.
|
|
84
86
|
*/
|
|
85
87
|
export declare const MAX_BLOCKED_MESSAGE_CHARS = 120;
|
|
88
|
+
/**
|
|
89
|
+
* The longest state label Herdr holds whole.
|
|
90
|
+
*
|
|
91
|
+
* Herdr shortens a longer one at its own limit, and a cut made server-side is one
|
|
92
|
+
* this surface can neither see nor test: bounding the label here keeps the
|
|
93
|
+
* ellipsis where the title meant it rather than wherever the multiplexer stopped.
|
|
94
|
+
*/
|
|
95
|
+
export declare const MAX_STATE_LABEL_CHARS = 80;
|
|
96
|
+
/**
|
|
97
|
+
* The key a gate's wait is held under.
|
|
98
|
+
*
|
|
99
|
+
* Waits are keyed rather than counted because one modal slot can be taken over
|
|
100
|
+
* while it is still open: a count would then be incremented twice and given back
|
|
101
|
+
* once, and a row left blocked names a decision nobody owes any more.
|
|
102
|
+
*/
|
|
103
|
+
export declare const GATE_WAIT_KEY = "gate";
|
|
86
104
|
/**
|
|
87
105
|
* Reports are sequenced in microseconds.
|
|
88
106
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/herdr/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,wEAAwE;AACxE,eAAO,MAAM,cAAc,MAAM,CAAA;AAEjC,eAAO,MAAM,aAAa,cAAc,CAAA;AACxC,eAAO,MAAM,iBAAiB,kBAAkB,CAAA;AAChD,eAAO,MAAM,qBAAqB,sBAAsB,CAAA;AACxD,eAAO,MAAM,kBAAkB,mBAAmB,CAAA;AAElD,iFAAiF;AACjF,eAAO,MAAM,WAAW,QAAQ,CAAA;AAEhC;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,mBAAmB,CAAA;AAE5C,gDAAgD;AAChD,eAAO,MAAM,YAAY;;;;CAAoE,CAAA;AAC7F,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAA;AAEzE;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB;;;;;CAAoF,CAAA;AACtH,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,OAAO,qBAAqB,CAAC,CAAA;AAEnG;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe;;;CAAsD,CAAA;AAElF,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB,IAAI,CAAA;AACjC,eAAO,MAAM,kBAAkB,MAAM,CAAA;AAErC,wEAAwE;AACxE,eAAO,MAAM,uBAAuB,MAAM,CAAA;AAE1C,8EAA8E;AAC9E,eAAO,MAAM,aAAa,MAAM,CAAA;AAEhC,4EAA4E;AAC5E,eAAO,MAAM,YAAY,OAAQ,CAAA;AAEjC,2DAA2D;AAC3D,eAAO,MAAM,kBAAkB,QAAY,CAAA;AAC3C,eAAO,MAAM,kBAAkB,OAAO,CAAA;AAEtC;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,KAAK,CAAA;AAE1C;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,MAAM,CAAA;AAE5C;;;;;GAKG;AACH,eAAO,MAAM,cAAc,OAAO,CAAA"}
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/herdr/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,wEAAwE;AACxE,eAAO,MAAM,cAAc,MAAM,CAAA;AAEjC,eAAO,MAAM,aAAa,cAAc,CAAA;AACxC,eAAO,MAAM,iBAAiB,kBAAkB,CAAA;AAChD,eAAO,MAAM,qBAAqB,sBAAsB,CAAA;AACxD,eAAO,MAAM,kBAAkB,mBAAmB,CAAA;AAElD,iFAAiF;AACjF,eAAO,MAAM,WAAW,QAAQ,CAAA;AAEhC;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,mBAAmB,CAAA;AAE5C,gDAAgD;AAChD,eAAO,MAAM,YAAY;;;;CAAoE,CAAA;AAC7F,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAA;AAEzE;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB;;;;;CAAoF,CAAA;AACtH,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,OAAO,qBAAqB,CAAC,CAAA;AAEnG;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe;;;CAAsD,CAAA;AAElF,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB,IAAI,CAAA;AACjC,eAAO,MAAM,kBAAkB,MAAM,CAAA;AAErC,wEAAwE;AACxE,eAAO,MAAM,uBAAuB,MAAM,CAAA;AAE1C,gFAAgF;AAChF,eAAO,MAAM,kBAAkB,UAAU,CAAA;AAEzC,8EAA8E;AAC9E,eAAO,MAAM,aAAa,MAAM,CAAA;AAEhC,4EAA4E;AAC5E,eAAO,MAAM,YAAY,OAAQ,CAAA;AAEjC,2DAA2D;AAC3D,eAAO,MAAM,kBAAkB,QAAY,CAAA;AAC3C,eAAO,MAAM,kBAAkB,OAAO,CAAA;AAEtC;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,KAAK,CAAA;AAE1C;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,MAAM,CAAA;AAE5C;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,KAAK,CAAA;AAEvC;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,SAAS,CAAA;AAEnC;;;;;GAKG;AACH,eAAO,MAAM,cAAc,OAAO,CAAA"}
|
package/lib/herdr/constants.js
CHANGED
|
@@ -46,6 +46,8 @@ export const DEFAULT_ATTEMPTS = 2;
|
|
|
46
46
|
export const DEFAULT_TIMEOUT_MS = 500;
|
|
47
47
|
/** A release on the way out cannot outlive the process that owes it. */
|
|
48
48
|
export const EXIT_RELEASE_TIMEOUT_MS = 250;
|
|
49
|
+
/** The CLI to release through when the one Herdr exported cannot be spawned. */
|
|
50
|
+
export const FALLBACK_HERDR_BIN = 'herdr';
|
|
49
51
|
/** The first wait before a report Herdr did not acknowledge is sent again. */
|
|
50
52
|
export const RETRY_BASE_MS = 250;
|
|
51
53
|
/** The longest that wait can grow to, so a down socket is still noticed. */
|
|
@@ -69,6 +71,22 @@ export const MAX_METADATA_VALUE_CHARS = 80;
|
|
|
69
71
|
* whole.
|
|
70
72
|
*/
|
|
71
73
|
export const MAX_BLOCKED_MESSAGE_CHARS = 120;
|
|
74
|
+
/**
|
|
75
|
+
* The longest state label Herdr holds whole.
|
|
76
|
+
*
|
|
77
|
+
* Herdr shortens a longer one at its own limit, and a cut made server-side is one
|
|
78
|
+
* this surface can neither see nor test: bounding the label here keeps the
|
|
79
|
+
* ellipsis where the title meant it rather than wherever the multiplexer stopped.
|
|
80
|
+
*/
|
|
81
|
+
export const MAX_STATE_LABEL_CHARS = 80;
|
|
82
|
+
/**
|
|
83
|
+
* The key a gate's wait is held under.
|
|
84
|
+
*
|
|
85
|
+
* Waits are keyed rather than counted because one modal slot can be taken over
|
|
86
|
+
* while it is still open: a count would then be incremented twice and given back
|
|
87
|
+
* once, and a row left blocked names a decision nobody owes any more.
|
|
88
|
+
*/
|
|
89
|
+
export const GATE_WAIT_KEY = 'gate';
|
|
72
90
|
/**
|
|
73
91
|
* Reports are sequenced in microseconds.
|
|
74
92
|
*
|