@dsh-blue/herdr-agent-state 0.1.0 → 0.2.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/README.md +123 -18
- package/package.json +1 -1
- package/src/index.js +38 -8
- package/src/state.js +63 -0
- package/src/transport.js +51 -5
package/README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# @dsh-blue/herdr-agent-state
|
|
2
2
|
|
|
3
3
|
A DeepSeek Harness (`dsh`) plugin that reports a pane's agent state — `working`,
|
|
4
|
-
`blocked`, `idle` — and its session
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
`blocked`, `idle` — its session reference, and its session title (as the Herdr
|
|
5
|
+
pane title) to [Herdr](https://herdr.dev/) through Herdr's pane socket
|
|
6
|
+
integration. It lets Herdr's sidebar show where the agent actually is, surface
|
|
7
|
+
waiting agents, name panes after the conversation, and expose the session for
|
|
8
|
+
restore, **without any change to Herdr** (Herdr's [custom
|
|
9
|
+
integration](https://herdr.dev/docs/integrations/#integrate-your-own-agent)
|
|
8
10
|
path).
|
|
9
11
|
|
|
10
12
|
It works in **any dsh frontend** — TUIs, the web app, and headless — because it
|
|
@@ -21,14 +23,15 @@ dsh plugin --profile <profile> add @dsh-blue/herdr-agent-state
|
|
|
21
23
|
```
|
|
22
24
|
|
|
23
25
|
It inserts a row labelled `herdr-agent-state`. To change the Herdr agent label
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
a frontend reports, patch the same row id in the profile's `cordis.patch.yml`
|
|
27
|
+
(an id-targeted patch replaces that row's whole `config`; the schema defaults
|
|
28
|
+
fill any field you omit):
|
|
26
29
|
|
|
27
30
|
```yaml
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
# ~/.dsh/profiles/<profile>/cordis.patch.yml
|
|
32
|
+
- id: herdr-agent-state
|
|
33
|
+
config:
|
|
34
|
+
agent: blue # default dsh; this frontend's own label
|
|
32
35
|
```
|
|
33
36
|
|
|
34
37
|
The plugin is a strict no-op outside a Herdr pane (`HERDR_ENV=1` plus
|
|
@@ -66,16 +69,118 @@ The plugin releases the pane's lifecycle authority on unload and process exit,
|
|
|
66
69
|
and re-reports on `agent/session-start` so a reload does not leave Herdr with a
|
|
67
70
|
stale authority.
|
|
68
71
|
|
|
72
|
+
## How it reports the title
|
|
73
|
+
|
|
74
|
+
The plugin mirrors the dsh session title — the first-prompt fallback, the
|
|
75
|
+
LLM-generated refinement, or a title pinned with `/rename` — as the Herdr pane
|
|
76
|
+
title through Herdr's display-only `pane.report_metadata` channel:
|
|
77
|
+
|
|
78
|
+
- Titles are observed on the same `session/title` session-log feed the dsh TUI
|
|
79
|
+
itself renders, filtered to the session the pane's agent is currently
|
|
80
|
+
running (subagent sessions in the same process are skipped).
|
|
81
|
+
- A resumed session's existing title is read directly at `agent/session-start`
|
|
82
|
+
(past title events are replay seeds that never re-enter the live feed), so a
|
|
83
|
+
restored pane is named immediately.
|
|
84
|
+
- The report carries the same `source` and `agent` as the state reports plus
|
|
85
|
+
an `applies_to_source` guard, so the title is accepted exactly while this
|
|
86
|
+
reporter holds the pane's lifecycle authority. Herdr checks that guard when
|
|
87
|
+
the report arrives (not continuously), so the reporter also clears the title
|
|
88
|
+
when it releases the pane's authority. A title never affects waits,
|
|
89
|
+
notifications, or rollups, and is not restored across a Herdr server
|
|
90
|
+
restart.
|
|
91
|
+
- Herdr trims and caps the text; after a `/clear` the previous title stays
|
|
92
|
+
until the new session produces its first title (usually seconds).
|
|
93
|
+
|
|
69
94
|
## Configuration
|
|
70
95
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
|
74
|
-
|
|
75
|
-
| `
|
|
76
|
-
| `
|
|
77
|
-
| `
|
|
78
|
-
| `
|
|
96
|
+
### Configuration reference
|
|
97
|
+
|
|
98
|
+
| Field | Type | Default | Meaning |
|
|
99
|
+
|---|---|---|---|
|
|
100
|
+
| `agent` | string | `'dsh'` | The Herdr agent label reported for the pane. Set a frontend's own name (e.g. `blue`) so Herdr's sidebar groups it under that label. |
|
|
101
|
+
| `source` | string | `'herdr:dsh-agent-state'` | Stable, unique integration source. Herdr attributes the pane's lifecycle authority to this source. **Keep it constant.** Changing it makes Herdr treat the pane as a *different* authority mid-session. |
|
|
102
|
+
| `transport` | `'socket'` \| `'cli'` | `'socket'` | How to report to Herdr. Only `socket` is implemented (speaks the pane socket directly). `cli` is declared but not yet implemented — it throws **at load**, so don't set it. |
|
|
103
|
+
| `reportSession` | boolean | `true` | Report the pane's session reference (`agent_session_id`) so Herdr can expose it for restore. Set `false` to suppress session reporting. |
|
|
104
|
+
| `title` | `'session'` \| `'none'` | `'session'` | Which title to publish as the Herdr pane title (display-only metadata). `session` mirrors the dsh session title — first-prompt fallback, LLM-generated, or pinned by `/rename`; `none` disables title reporting. |
|
|
105
|
+
| `message` | `'tool'` \| `'none'` | `'tool'` | Whether to attach a human label to `blocked` reports. `tool` sends the tool name / question summary; `none` sends `blocked` with no message. |
|
|
106
|
+
| `enabled` | boolean | `true` | Kill-switch. Set `false` to disable the reporter in this tree — useful to coexist with another reporter. |
|
|
107
|
+
|
|
108
|
+
### How to configure it
|
|
109
|
+
|
|
110
|
+
The plugin is a bundle row labelled `herdr-agent-state`, so it is inserted
|
|
111
|
+
automatically when you `dsh plugin add`. Because its `Config` schema gives every
|
|
112
|
+
field a default, you only set what you want to change; the schema fills the
|
|
113
|
+
rest. A profile's `cordis.patch.yml` is a **top-level YAML array of loader patch
|
|
114
|
+
entries**, so you target the row by `id` and replace its `config`:
|
|
115
|
+
|
|
116
|
+
```yaml
|
|
117
|
+
# ~/.dsh/profiles/<profile>/cordis.patch.yml
|
|
118
|
+
- id: herdr-agent-state
|
|
119
|
+
config:
|
|
120
|
+
agent: blue
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The patch replaces the row's whole `config`, so the schema defaults supply any
|
|
124
|
+
field you don't set. Include `name` as a guard — if it ever mismatches the row,
|
|
125
|
+
the patch is skipped with a warning instead of silently applying:
|
|
126
|
+
|
|
127
|
+
```yaml
|
|
128
|
+
- id: herdr-agent-state
|
|
129
|
+
name: '@dsh-blue/herdr-agent-state'
|
|
130
|
+
config:
|
|
131
|
+
agent: blue
|
|
132
|
+
source: herdr:dsh-agent-state
|
|
133
|
+
transport: socket
|
|
134
|
+
reportSession: true
|
|
135
|
+
title: session
|
|
136
|
+
message: tool
|
|
137
|
+
enabled: true
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Examples
|
|
141
|
+
|
|
142
|
+
Set the Herdr label to `blue` when Blue hosts the pane (all other fields
|
|
143
|
+
default):
|
|
144
|
+
|
|
145
|
+
```yaml
|
|
146
|
+
- id: herdr-agent-state
|
|
147
|
+
config:
|
|
148
|
+
agent: blue
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Disable session reporting and verbose blocked messages:
|
|
152
|
+
|
|
153
|
+
```yaml
|
|
154
|
+
- id: herdr-agent-state
|
|
155
|
+
config:
|
|
156
|
+
reportSession: false
|
|
157
|
+
message: none
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Disable title reporting (keep state and session reports):
|
|
161
|
+
|
|
162
|
+
```yaml
|
|
163
|
+
- id: herdr-agent-state
|
|
164
|
+
config:
|
|
165
|
+
title: none
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Notes
|
|
169
|
+
|
|
170
|
+
- **Changing `source`** re-attributes the pane's authority in Herdr. Keep it at
|
|
171
|
+
the default unless you are deliberately running two reporters in the same
|
|
172
|
+
tree — then give each a distinct `source`, and use `enabled: false` on the one
|
|
173
|
+
you want silent.
|
|
174
|
+
- **`transport: 'cli'` is not implemented.** Setting it throws during plugin
|
|
175
|
+
load (fail-fast), so leave it as `socket`.
|
|
176
|
+
- **`config` is validated** against the schemastery schema at load; an invalid
|
|
177
|
+
value (for example a `transport` that isn't `socket`/`cli`) is rejected, and
|
|
178
|
+
the plugin fails to load rather than running half-configured.
|
|
179
|
+
- The pane title rides the same `source` and `agent` guards as the state
|
|
180
|
+
reports; changing `source` mid-session affects the title the same way it
|
|
181
|
+
affects lifecycle authority.
|
|
182
|
+
- Because a patch replaces the row's whole `config`, any field you don't set
|
|
183
|
+
comes from the schema default — you do not need to copy every field.
|
|
79
184
|
|
|
80
185
|
## Version compatibility
|
|
81
186
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-blue/herdr-agent-state",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "dsh plugin: report agent state (working/blocked/idle) and session reference to Herdr via its pane socket integration. Works in any dsh profile — TUIs, web, headless.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
package/src/index.js
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
* Herdr agent-state reporter for any dsh frontend.
|
|
3
3
|
*
|
|
4
4
|
* A Cordis function plugin that, when loaded inside a Herdr pane, reports the
|
|
5
|
-
* pane's semantic state (working / blocked / idle)
|
|
6
|
-
* Herdr's pane socket. It depends
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* pane's semantic state (working / blocked / idle), session reference, and
|
|
6
|
+
* session title (as the Herdr pane title) to Herdr's pane socket. It depends
|
|
7
|
+
* only on documented dsh extension points — agent lifecycle events, the
|
|
8
|
+
* approval and user-question waterfalls, and the session-log event feed — so
|
|
9
|
+
* it works in TUI, web, and headless profiles alike. Outside a Herdr pane it
|
|
10
|
+
* is a strict no-op.
|
|
10
11
|
*
|
|
11
12
|
* Ships as plain ESM JavaScript (no build step) so `dsh plugin add` from a git
|
|
12
13
|
* repo loads it directly without `prepare`/`lib`.
|
|
@@ -16,7 +17,7 @@
|
|
|
16
17
|
|
|
17
18
|
import z from '@deepseek-ai/schemastery'
|
|
18
19
|
|
|
19
|
-
import { AgentStateModel } from './state.js'
|
|
20
|
+
import { AgentStateModel, SessionTitleModel } from './state.js'
|
|
20
21
|
import { HerdrReporter, herdrEnabled } from './transport.js'
|
|
21
22
|
|
|
22
23
|
export const name = 'herdr-agent-state'
|
|
@@ -44,6 +45,12 @@ export const Config = z.object({
|
|
|
44
45
|
transport: z.union([z.const('socket'), z.const('cli')]).default('socket'),
|
|
45
46
|
/** Report the pane's session reference so Herdr can expose it for restore. */
|
|
46
47
|
reportSession: z.boolean().default(true),
|
|
48
|
+
/**
|
|
49
|
+
* Which title to publish as the Herdr pane title (display-only metadata).
|
|
50
|
+
* `session` mirrors the dsh session title — first-prompt fallback,
|
|
51
|
+
* LLM-generated, or pinned by `/rename`; `none` disables title reporting.
|
|
52
|
+
*/
|
|
53
|
+
title: z.union([z.const('session'), z.const('none')]).default('session'),
|
|
47
54
|
/** Whether to attach a human label to blocked reports. */
|
|
48
55
|
message: z.union([z.const('tool'), z.const('none')]).default('tool'),
|
|
49
56
|
/** Kill-switch for coexisting with another reporter in the same tree. */
|
|
@@ -60,7 +67,7 @@ function questionLabel(questions) {
|
|
|
60
67
|
/**
|
|
61
68
|
* Drive one pane's reporter from the live dsh event stream.
|
|
62
69
|
* @param {import('@deepseek-ai/cordis').Context} ctx
|
|
63
|
-
* @param {{ agent: string, source: string, transport: 'socket' | 'cli', reportSession: boolean, message: 'tool' | 'none', enabled: boolean }} config
|
|
70
|
+
* @param {{ agent: string, source: string, transport: 'socket' | 'cli', reportSession: boolean, title: 'session' | 'none', message: 'tool' | 'none', enabled: boolean }} config
|
|
64
71
|
*/
|
|
65
72
|
export function apply(ctx, config) {
|
|
66
73
|
if (!config.enabled) return
|
|
@@ -75,9 +82,11 @@ export function apply(ctx, config) {
|
|
|
75
82
|
source: config.source,
|
|
76
83
|
agent: config.agent,
|
|
77
84
|
reportSession: config.reportSession,
|
|
85
|
+
reportTitle: config.title !== 'none',
|
|
78
86
|
env,
|
|
79
87
|
})
|
|
80
88
|
const model = new AgentStateModel()
|
|
89
|
+
const titleModel = new SessionTitleModel()
|
|
81
90
|
|
|
82
91
|
const publish = (force = false) => {
|
|
83
92
|
const report = model.desired()
|
|
@@ -123,12 +132,33 @@ export function apply(ctx, config) {
|
|
|
123
132
|
})
|
|
124
133
|
|
|
125
134
|
ctx.on('agent/session-start', (payload) => {
|
|
126
|
-
|
|
135
|
+
const session = payload.agent?.session
|
|
136
|
+
const sessionId = session?.header?.id ?? undefined
|
|
137
|
+
reporter.setSessionId(sessionId)
|
|
127
138
|
reporter.reportSession(payload.source)
|
|
139
|
+
// A resumed session's past titles are constructor-seed log events that
|
|
140
|
+
// never reach the session/event feed, so read the current one directly.
|
|
141
|
+
let initialTitle
|
|
142
|
+
try {
|
|
143
|
+
initialTitle = ctx.get('sessionTitle')?.get(session)?.title
|
|
144
|
+
} catch {
|
|
145
|
+
// Service not mounted or session not live: the feed covers the rest.
|
|
146
|
+
}
|
|
147
|
+
reporter.reportTitle(titleModel.setSession(sessionId, initialTitle))
|
|
128
148
|
model.setRunning(payload.agent, false)
|
|
129
149
|
publish(true)
|
|
130
150
|
})
|
|
131
151
|
|
|
152
|
+
// Post-commit feed of appended session-log events; keep only title commits
|
|
153
|
+
// for the tracked session (child/subagent sessions in this process are
|
|
154
|
+
// skipped by the session-id match inside the model).
|
|
155
|
+
ctx.on('session/event', (session, event) => {
|
|
156
|
+
if (event.type !== 'session/title') return
|
|
157
|
+
const title = event.data?.title
|
|
158
|
+
if (typeof title !== 'string') return
|
|
159
|
+
reporter.reportTitle(titleModel.observeTitle(session?.header?.id ?? session?.id, title))
|
|
160
|
+
})
|
|
161
|
+
|
|
132
162
|
ctx.effect(
|
|
133
163
|
() => () => reporter.release(),
|
|
134
164
|
'herdr-agent-state: release pane lifecycle authority on unload',
|
package/src/state.js
CHANGED
|
@@ -55,3 +55,66 @@ export class AgentStateModel {
|
|
|
55
55
|
return { state: 'idle' }
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Tracks which session's title is current and the latest applicable title,
|
|
61
|
+
* deciding when a title observation should be published.
|
|
62
|
+
*/
|
|
63
|
+
export class SessionTitleModel {
|
|
64
|
+
constructor() {
|
|
65
|
+
/** Session identity from the latest agent/session-start. */
|
|
66
|
+
this.sessionId = undefined
|
|
67
|
+
/** Latest applicable title for that session. */
|
|
68
|
+
this.title = undefined
|
|
69
|
+
/** Last title this model told the caller to publish (change tracking). */
|
|
70
|
+
this.lastReported = undefined
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* The tracked session changed (agent/session-start). Adopts the new identity
|
|
75
|
+
* and any pre-existing title (a resumed session's title predates the plugin),
|
|
76
|
+
* resetting change tracking so an identical title re-publishes.
|
|
77
|
+
* @param {string | undefined} sessionId
|
|
78
|
+
* @param {string | undefined} [initialTitle]
|
|
79
|
+
* @returns {string | undefined} the title to publish now, if any
|
|
80
|
+
*/
|
|
81
|
+
setSession(sessionId, initialTitle) {
|
|
82
|
+
this.sessionId = sessionId
|
|
83
|
+
this.title = initialTitle
|
|
84
|
+
this.lastReported = undefined
|
|
85
|
+
return this.takePublishable()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* One session/title observation from the session/event firehose. Ignores
|
|
90
|
+
* other sessions' titles and unchanged text; adopts the first observed
|
|
91
|
+
* session when none was recorded (plugin reloaded mid-session).
|
|
92
|
+
* @param {string | undefined} sessionId
|
|
93
|
+
* @param {string} title
|
|
94
|
+
* @returns {string | undefined} the title to publish now, if changed
|
|
95
|
+
*/
|
|
96
|
+
observeTitle(sessionId, title) {
|
|
97
|
+
if (this.sessionId === undefined) this.sessionId = sessionId
|
|
98
|
+
if (sessionId === undefined || sessionId !== this.sessionId) return undefined
|
|
99
|
+
this.title = title
|
|
100
|
+
return this.takePublishable()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The report derived from the current inputs.
|
|
105
|
+
* @returns {{ title: string } | undefined}
|
|
106
|
+
*/
|
|
107
|
+
desired() {
|
|
108
|
+
return typeof this.title === 'string' && this.title.trim() !== ''
|
|
109
|
+
? { title: this.title }
|
|
110
|
+
: undefined
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Consume the desired report once, tracking it as reported. */
|
|
114
|
+
takePublishable() {
|
|
115
|
+
const report = this.desired()
|
|
116
|
+
if (report === undefined || report.title === this.lastReported) return undefined
|
|
117
|
+
this.lastReported = report.title
|
|
118
|
+
return report.title
|
|
119
|
+
}
|
|
120
|
+
}
|
package/src/transport.js
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Mirrors Herdr's own bundled Pi integration wire contract: one newline-delimited
|
|
5
5
|
* JSON request per `pane.report_agent` / `pane.report_agent_session` /
|
|
6
|
-
* `pane.release_agent` call
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* `pane.release_agent` call — plus the display-only `pane.report_metadata` for
|
|
7
|
+
* the pane title — a fresh single connection per request, a short timeout plus
|
|
8
|
+
* one longer retry, and a failure that never rejects into the host process
|
|
9
|
+
* (Herdr being absent must not disturb the dsh frontend).
|
|
9
10
|
*
|
|
10
11
|
* Only `node:net` is used.
|
|
11
12
|
* @module @dsh-blue/herdr-agent-state/transport
|
|
@@ -74,12 +75,13 @@ export function sendRequest(request, endpoint, timeoutMs = 500, retryMs = 1500)
|
|
|
74
75
|
*/
|
|
75
76
|
export class HerdrReporter {
|
|
76
77
|
/**
|
|
77
|
-
* @param {{ source: string, agent: string, reportSession: boolean, env: Record<string, string | undefined> }} options
|
|
78
|
+
* @param {{ source: string, agent: string, reportSession: boolean, reportTitle?: boolean, env: Record<string, string | undefined> }} options
|
|
78
79
|
*/
|
|
79
80
|
constructor(options) {
|
|
80
81
|
this.source = options.source
|
|
81
82
|
this.agent = options.agent
|
|
82
83
|
this.reportSessionRef = options.reportSession
|
|
84
|
+
this.reportTitleRef = options.reportTitle ?? false
|
|
83
85
|
this.endpoint = socketEndpoint(options.env)
|
|
84
86
|
this.paneId = options.env.HERDR_PANE_ID ?? ''
|
|
85
87
|
// Wall-clock base keeps seq strictly increasing across process restarts.
|
|
@@ -88,6 +90,7 @@ export class HerdrReporter {
|
|
|
88
90
|
this.sendInFlight = false
|
|
89
91
|
this.queued = undefined
|
|
90
92
|
this.lastSent = undefined
|
|
93
|
+
this.lastSentTitle = undefined
|
|
91
94
|
}
|
|
92
95
|
|
|
93
96
|
/** Record the session reference to attach to subsequent reports. */
|
|
@@ -139,8 +142,51 @@ export class HerdrReporter {
|
|
|
139
142
|
})
|
|
140
143
|
}
|
|
141
144
|
|
|
142
|
-
/**
|
|
145
|
+
/**
|
|
146
|
+
* Report the dsh session title as display-only Herdr pane metadata. The
|
|
147
|
+
* `agent` and `applies_to_source` guards scope the report to exactly the
|
|
148
|
+
* moments this reporter holds the pane's lifecycle authority; `release()`
|
|
149
|
+
* clears the title explicitly when that authority is given up.
|
|
150
|
+
* @param {string | undefined} title
|
|
151
|
+
*/
|
|
152
|
+
reportTitle(title) {
|
|
153
|
+
if (!this.reportTitleRef) return
|
|
154
|
+
if (typeof title !== 'string' || title.trim() === '') return
|
|
155
|
+
if (title === this.lastSentTitle) return
|
|
156
|
+
this.lastSentTitle = title
|
|
157
|
+
void this.send({
|
|
158
|
+
id: `${this.source}:title:${Date.now()}:${Math.random().toString(36).slice(2)}`,
|
|
159
|
+
method: 'pane.report_metadata',
|
|
160
|
+
params: {
|
|
161
|
+
pane_id: this.paneId,
|
|
162
|
+
source: this.source,
|
|
163
|
+
agent: this.agent,
|
|
164
|
+
applies_to_source: this.source,
|
|
165
|
+
title,
|
|
166
|
+
seq: this.nextSeq(),
|
|
167
|
+
},
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Release this pane's lifecycle authority (on unload or process exit). The
|
|
173
|
+
* guard on a reported title is checked at acceptance time, not continuously,
|
|
174
|
+
* so a title this reporter set is cleared explicitly alongside the release.
|
|
175
|
+
*/
|
|
143
176
|
release() {
|
|
177
|
+
if (this.reportTitleRef && this.lastSentTitle !== undefined) {
|
|
178
|
+
this.lastSentTitle = undefined
|
|
179
|
+
void this.send({
|
|
180
|
+
id: `${this.source}:title-clear:${Date.now()}:${Math.random().toString(36).slice(2)}`,
|
|
181
|
+
method: 'pane.report_metadata',
|
|
182
|
+
params: {
|
|
183
|
+
pane_id: this.paneId,
|
|
184
|
+
source: this.source,
|
|
185
|
+
clear_title: true,
|
|
186
|
+
seq: this.nextSeq(),
|
|
187
|
+
},
|
|
188
|
+
})
|
|
189
|
+
}
|
|
144
190
|
void this.send({
|
|
145
191
|
id: `${this.source}:release:${Date.now()}:${Math.random().toString(36).slice(2)}`,
|
|
146
192
|
method: 'pane.release_agent',
|