@deepseek-ai/dsh-tmux-context 0.1.1-rc.2 → 0.1.2-alpha.2

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.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/context/tmux-context/README.md
5
- README.md: 006d4b1e6d824fd255d745cba2ae78ae86eed751
6
- README.zh.md: 0a1214a4b86aff3054d44f813fca08aa0b8232a9
5
+ README.md: d923502a990f28a4f5267b7f39a552dbaf7423aa
6
+ README.zh.md: d1636e62cd026f417a82f07542b31a89302ca081
package/README.md CHANGED
@@ -1,40 +1,98 @@
1
+ ---
2
+ description: "Opt-in per-turn tmux location context for users and maintainers enabling or tuning the agent's session, window, and pane awareness."
3
+ kind: "package-reference"
4
+ ---
5
+
1
6
  # @deepseek-ai/dsh-tmux-context
2
7
 
3
8
  English | [中文](README.zh.md)
4
9
 
5
- Opt-in durable context naming the tmux session, window, and pane this agent process runs in, plus the window's pane-tree layout. It is sampled once per turn during model-request preparation and is not part of the shipped Web/headless composition. Decision record: [the tmux-context Agent Note](../../../.agents/notes/implemented/feature/2026-07-27-tmux-location-context.md).
10
+ ## Summary
11
+
12
+ `dsh-tmux-context` tells the model where its agent process runs: on each turn whose tmux state changed, it appends a durable, source-attributed reading naming the tmux session, window, and pane plus the window's pane-tree layout. It is sampled once per turn during request preparation and only when the process genuinely lives inside the named pane — a terminal that merely inherited `$TMUX`/`$TMUX_PANE` from a tmux ancestor reads as not in tmux and adds nothing. An unchanged location adds nothing, and a failed query is a no-op, never a turn failure. The plugin is opt-in and not part of the shipped Web/headless composition.
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
+ Mount this plugin when the agent process runs inside tmux and the model benefits from knowing its window and pane location. Each reading is one additional user-role message in durable history; an unchanged location adds nothing, so long-running sessions accumulate little.
29
+
30
+ ### What the agent gets
6
31
 
7
- ## Config
32
+ On each turn whose tmux state changed, the model receives one source-tagged context message with the session name, window index and name, pane index and id, active flags, and the compact pane-tree layout. Readings happen on the first step of a turn only; a pane moved or resized mid-turn is reflected on the next turn. Pixel sizes are intentionally excluded, and the visible contents of sibling panes are never captured.
33
+
34
+ ### Configuration
35
+
36
+ The minimal mount needs no configuration. A positive `refreshIntervalMs` additionally suppresses injections that fall within that many milliseconds of the latest one; omission or `0` injects whenever the tmux state changed since the last injection.
8
37
 
9
38
  ```yaml
10
- - id: tmux-context
11
- name: '@deepseek-ai/dsh-tmux-context'
39
+ - name: '@deepseek-ai/dsh-tmux-context'
12
40
  config:
13
- refreshIntervalMs: 60000 # optional; omit or set to 0 to inject on every changed turn
41
+ refreshIntervalMs: 60000
14
42
  ```
15
43
 
16
- `refreshIntervalMs` must be a non-negative safe integer. Omission or `0` injects whenever the tmux state changed since the last injection. A positive value additionally suppresses injections that fall within that many milliseconds of the latest one.
44
+ | Field | Default | Meaning |
45
+ |---|---|---|
46
+ | `refreshIntervalMs` | `0` (every changed turn) | Minimum milliseconds between durable injections in one session |
17
47
 
18
- ## How it reads tmux
48
+ The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-tmux-context) is the exhaustive source for every accepted field and its JSDoc.
19
49
 
20
- The plugin prepends an `agent/pre-step` listener that runs only on the first step of each turn. When due, it runs one read-only command through the `ctx.shell` executor service:
50
+ ### When the location is known
21
51
 
22
- ```sh
23
- [ -n "$TMUX_PANE" ] || exit 1
24
- self_tty=$(ps -o tty= -p <pid> | tr -d ' ')
25
- pane_tty=$(tmux display-message -t "$TMUX_PANE" -p '#{pane_tty}') || exit 1
26
- [ "$pane_tty" = "/dev/$self_tty" ] || exit 1
27
- exec tmux display-message -t "$TMUX_PANE" -p '<format>'
28
- ```
52
+ The process counts as in tmux only when its controlling terminal matches the pane's `#{pane_tty}`; a terminal launched from a tmux shell (a VS Code integrated terminal, a desktop launcher) inherits the variables but not the pane, so it reads as not in tmux. A missing `ctx.shell`, an absent environment, or a malformed reading is a no-op, and an executor rejection is contained and logged as a warning rather than failing the turn.
53
+
54
+ -----
55
+
56
+ <a id="understand-the-implementation"></a>
57
+ ## Understand the implementation
58
+
59
+ <details>
60
+ <summary>Implementation internals — click to expand</summary>
61
+
62
+ This section explains the design of the plugin; the observable behavior is covered in [Use this package](#use-this-package).
29
63
 
30
- `$TMUX_PANE` alone is insufficient: a terminal launched from a tmux shell (a VS Code integrated terminal, a desktop launcher) **inherits** `$TMUX` and `$TMUX_PANE` from that ancestor, so the variables are present even though the process does not live in that pane. The command therefore also compares the pane's `#{pane_tty}` against this process's own controlling terminal (`ps -o tty=` for its pid): a genuine pane owns this process's tty, while an inherited environment names some other pane's tty. Running through `ctx.shell` applies the deployment's sandbox and policy; the plugin owns no subprocess code. When `ctx.shell` is absent, the process is not in a real tmux pane (`$TMUX_PANE` unset, or the tty does not match ⇒ nonzero exit), or the reading is malformed, the attempt is a no-op, never an error. The location is optional, so an executor rejection — a policy refusal from `resolve()` or an infrastructure failure from `run()` — is contained and logged as a warning rather than failing the turn.
64
+ ### Design concept
31
65
 
32
- State is pulled on every eligible turn — a moved, renamed, or re-laid-out pane is picked up without any tmux hook or background process. The plugin re-injects only when the rendered tmux state differs from its last injection, so an unchanged location adds nothing.
66
+ The plugin prepends an `agent/pre-step` listener that runs only on the first step of each turn. When due, it runs one read-only command through the `ctx.shell` executor service the deployment's sandbox and policy apply, and the plugin owns no subprocess code. The command compares `$TMUX_PANE`'s `#{pane_tty}` with this process's own controlling terminal before emitting tab-separated fields, so an inherited environment reads as not in tmux. The plugin re-injects only when the rendered state differs from its last injection.
33
67
 
34
- ## Timing semantics
68
+ ### Source map
35
69
 
36
- The plugin prepends an `agent/pre-step` listener. When an injection is due and the downstream decision enters the proposed step, it prepends one sourced `UserMessage` to the returned batch. AgentLoop records that context after `step/start` with source `{ kind: 'plugin', plugin: 'tmux-context' }`. Change suppression and interval scheduling scan the raw durable session events for the latest injection of this source, so the schedule survives compaction and resumed processes without process-local cache state; sessions schedule independently. A downstream pre-step listener that rejects or fails prevents the reading from being recorded.
70
+ | File | Role |
71
+ |---|---|
72
+ | [`src/index.ts`](src/index.ts) | Plugin entry: first-step listener, shell query, change suppression, scheduling |
73
+ | [`src/invariant.ts`](src/invariant.ts) | Invariant companion for the snapshot contract |
37
74
 
75
+ ### Main flow
76
+
77
+ At the first step of a turn, the listener checks whether an injection is due, queries the location through `ctx.shell`, and compares the rendered state with the latest durable injection of this source. Change suppression and interval scheduling scan the raw durable session events, so the schedule survives compaction and resumed processes without process-local cache state; sessions schedule independently. A downstream pre-step listener that rejects or fails prevents the reading from being recorded.
78
+
79
+ </details>
80
+
81
+ -----
82
+
83
+ <a id="further-exploration"></a>
84
+ ## Further Exploration
85
+
86
+ Read these pages when the package-level contract is not enough. They move from the design decision to the executor the query runs through and the exhaustive configuration.
87
+
88
+ - [Tmux location context decision record](../../../.agents/notes/implemented/feature/2026-07-27-tmux-location-context.md) — design rationale for the tty-based detection and reading shape.
89
+ - [Shell subsystem](../../../docs/subsystems/shell.md) — the executor service the read-only query runs through.
90
+ - [Context group map](../README.md) — sibling request-context packages.
91
+ - [Generated configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-tmux-context) — every accepted config field and its source declaration.
92
+
93
+ -----
94
+
95
+ <a id="model-experience"></a>
38
96
  ## Model Experience
39
97
 
40
98
  ### Preparation-time tmux location
@@ -53,7 +111,7 @@ window active=<0|1>, pane active=<0|1>, layout <window-layout>
53
111
 
54
112
  #### Token effect
55
113
 
56
- Each two-line reading accumulates until compaction shadows it. Unchanged locations and interval suppression add nothing.
114
+ Each three-line reading accumulates until compaction shadows it. Unchanged locations and interval suppression add nothing.
57
115
 
58
116
  #### KV Cache effect
59
117
 
@@ -61,8 +119,23 @@ Append-only; newly visible content follows the reusable request prefix and does
61
119
 
62
120
  ## Known Limitations and Deferred Work
63
121
 
122
+ <a id="known-limitations-and-deferred-work"></a>
123
+
124
+
125
+ These limits define when tmux location context is a poor fit. They are current package constraints.
126
+
64
127
  - **First step only** — a pane moved or resized mid-turn is reflected on the next turn, not between steps.
65
128
  - **Own location only** — the plugin never captures the visible text of sibling panes.
66
129
  - **Layout, not size** — pane/window pixel dimensions are omitted; only the layout tree and active flags are reported.
67
130
  - **Tab-delimited fields** — a tmux window name containing the literal two-character sequence `\t` would mis-split the reading and be skipped as malformed; ordinary names are unaffected.
68
131
  - **tty-based pane detection** — the process is considered "in tmux" only when its controlling terminal matches `$TMUX_PANE`'s `#{pane_tty}`. This deliberately excludes terminals that inherited `$TMUX`/`$TMUX_PANE` from a tmux ancestor (e.g. a VS Code integrated terminal). `ps -o tty=` is POSIX; the check is a no-op wherever it or `#{pane_tty}` is unavailable.
132
+
133
+ <a id="dev-note"></a>
134
+ ### Dev Note
135
+
136
+ <details>
137
+ <summary>Working context for maintainers — click to expand</summary>
138
+
139
+ None.
140
+
141
+ </details>
package/README.zh.md CHANGED
@@ -1,40 +1,98 @@
1
+ ---
2
+ description: "可选的按轮次 tmux 位置上下文,供启用或调优 agent 的 session、window 与 pane 感知的用户与维护者阅读。"
3
+ kind: "package-reference"
4
+ ---
5
+
1
6
  # @deepseek-ai/dsh-tmux-context
2
7
 
3
8
  [English](README.md) | 中文
4
9
 
5
- 可选启用的持久上下文,记录本 agent(智能体)进程所在的 tmux session、window、pane,以及该 window 的 pane 树布局。在准备模型请求时每轮采样一次;随附 Web/无头组合不包含它。决策记录见:[tmux-context Agent Note](../../../.agents/notes/implemented/feature/2026-07-27-tmux-location-context.zh.md)。
10
+ ## 概述
11
+
12
+ `dsh-tmux-context` 告诉模型它的 agent(智能体)进程运行在哪里:在 tmux 状态发生变化的每一轮,它追加一条持久、带来源的读数,命名 tmux session、window 与 pane,以及该 window 的 pane 树布局。它在准备模型请求时每轮采样一次,且仅当进程确实位于所指名的 pane 内时——仅从 tmux 祖先进程继承了 `$TMUX`/`$TMUX_PANE` 的终端会被视为不在 tmux 中,不添加任何内容。位置未变化时不添加任何内容;查询失败是空操作,绝不导致轮次失败。本插件需主动启用,且不属于随附 Web/无头组合。
13
+
14
+ ## 目录
15
+
16
+ - [使用本包](#use-this-package)
17
+ - [理解实现](#understand-the-implementation)
18
+ - [进一步探索](#further-exploration)
19
+ - [模型体验](#model-experience)
20
+ - [已知限制与延期工作](#known-limitations-and-deferred-work)
21
+ - [开发备注](#dev-note)
22
+
23
+ -----
24
+
25
+ <a id="use-this-package"></a>
26
+ ## 使用本包
27
+
28
+ 当 agent 进程运行在 tmux 内、且模型需要知道其 window 与 pane 位置时,挂载此插件。每条读数都是持久历史中额外的一条 user 角色消息;位置未变化时不添加任何内容,因此长时会话累积很少。
29
+
30
+ ### 模型能得到什么
6
31
 
7
- ## 配置
32
+ tmux 状态发生变化的每一轮,模型会收到一条带来源标记的上下文消息,包含 session 名称、window 索引与名称、pane 索引与 id、活动标志,以及紧凑的 pane 树布局。读数只发生在每轮的第一个步骤;轮次中途移动或缩放的 pane 会在下一轮反映。像素尺寸有意省略,相邻 pane 的可见内容从不采集。
33
+
34
+ ### 配置
35
+
36
+ 最小挂载无需任何配置。正的 `refreshIntervalMs` 会额外抑制距最近一次注入不足该毫秒数的注入;省略或设为 `0` 时,只要 tmux 状态自上次注入以来发生变化就注入。
8
37
 
9
38
  ```yaml
10
- - id: tmux-context
11
- name: '@deepseek-ai/dsh-tmux-context'
39
+ - name: '@deepseek-ai/dsh-tmux-context'
12
40
  config:
13
- refreshIntervalMs: 60000 # optional; omit or set to 0 to inject on every changed turn
41
+ refreshIntervalMs: 60000
14
42
  ```
15
43
 
16
- `refreshIntervalMs` 必须是非负安全整数。省略或 `0` 表示只要 tmux 状态自上次注入以来发生变化就注入。正值会额外抑制距最近一次注入不足该毫秒数的注入。
44
+ | 字段 | 默认值 | 含义 |
45
+ |---|---|---|
46
+ | `refreshIntervalMs` | `0`(每个变化轮次) | 同一会话中两次持久注入之间的最小毫秒数 |
17
47
 
18
- ## 如何读取 tmux
48
+ 生成的[配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-tmux-context)是每个受支持字段及其 JSDoc 的穷尽式真源。
19
49
 
20
- 插件前置注册一个 `agent/pre-step` 监听器,仅在每轮的第一个步骤运行。当需要注入时,它通过 `ctx.shell` 执行器服务运行一条只读命令:
50
+ ### 何时知道位置
21
51
 
22
- ```sh
23
- [ -n "$TMUX_PANE" ] || exit 1
24
- self_tty=$(ps -o tty= -p <pid> | tr -d ' ')
25
- pane_tty=$(tmux display-message -t "$TMUX_PANE" -p '#{pane_tty}') || exit 1
26
- [ "$pane_tty" = "/dev/$self_tty" ] || exit 1
27
- exec tmux display-message -t "$TMUX_PANE" -p '<format>'
28
- ```
52
+ 只有当进程的控制终端与 pane 的 `#{pane_tty}` 一致时,才视为位于 tmux 中;从 tmux shell 启动的终端(VS Code 集成终端、桌面启动器)会继承变量但不在 pane 内,因此被视为不在 tmux 中。`ctx.shell` 缺失、环境变量不存在或读数格式非法时是空操作;执行器拒绝会被兜住并记录为警告,而不会使该轮失败。
53
+
54
+ -----
55
+
56
+ <a id="understand-the-implementation"></a>
57
+ ## 理解实现
58
+
59
+ <details>
60
+ <summary>实现细节——点击展开</summary>
61
+
62
+ 本节解释插件的设计;可观察行为见[使用本包](#use-this-package)。
29
63
 
30
- 仅凭 `$TMUX_PANE` 并不足够:从 tmux shell 启动的终端(VS Code 集成终端、桌面启动器)会从该祖先进程**继承** `$TMUX` 与 `$TMUX_PANE`,因此即使进程并不位于那个 pane 中,这些变量依然存在。为此该命令还会把 pane 的 `#{pane_tty}` 与本进程自己的控制终端(对其 pid 执行 `ps -o tty=`)作比较:真正的 pane 拥有本进程的 tty,而继承而来的环境指向的是另一个 pane 的 tty。通过 `ctx.shell` 运行会应用部署方的沙箱与策略;插件不拥有任何子进程代码。当 `ctx.shell` 缺失、进程不在真实的 tmux pane 内(`$TMUX_PANE` 未设置,或 tty 不匹配 ⇒ 非零退出)或读取结果格式非法时,本次尝试为空操作,绝不报错。由于位置信息是可选的,执行器的拒绝——`resolve()` 的策略拒绝或 `run()` 的基础设施故障——会被兜住并记录为警告,而不会使该轮失败。
64
+ ### 设计理念
31
65
 
32
- 状态在每个符合条件的轮次拉取——pane 被移动、改名或重新布局都会被感知,无需任何 tmux hook 或后台进程。插件仅在渲染出的 tmux 状态与上次注入不同时才重新注入,因此位置不变时不会新增任何内容。
66
+ 插件前置注册一个 `agent/pre-step` 监听器,仅在每轮的第一个步骤运行。需要注入时,它通过 `ctx.shell` 执行器服务运行一条只读命令——部署方的沙箱与策略都会应用,插件不拥有任何子进程代码。命令在输出制表符分隔字段前,会比较 `$TMUX_PANE` 的 `#{pane_tty}` 与本进程自身的控制终端,因此继承的环境会被视为不在 tmux 中。插件只在渲染出的状态与上次注入不同时重新注入。
33
67
 
34
- ## 时序语义
68
+ ### 源码地图
35
69
 
36
- 该插件会前置一个 `agent/pre-step` 监听器。需要注入且下游决策进入拟议步骤时,它会向返回的批次前置添加一条带来源的 `UserMessage`。AgentLoop 会在 `step/start` 之后记录该上下文,其来源为 `{ kind: 'plugin', plugin: 'tmux-context' }`。变化抑制与间隔调度会扫描原始持久会话事件中该来源的最近一次注入,因此调度可跨压缩(compaction)与恢复的进程存续,无需进程内缓存状态;各会话独立调度。下游在步骤前运行的监听器拒绝或失败时,该读数不会被记录。
70
+ | 文件 | 职责 |
71
+ |---|---|
72
+ | [`src/index.ts`](src/index.ts) | 插件入口:第一步监听器、shell 查询、变化抑制、调度 |
73
+ | [`src/invariant.ts`](src/invariant.ts) | 快照约定的不变式伴生插件 |
37
74
 
75
+ ### 主要流程
76
+
77
+ 在每轮的第一个步骤,监听器检查注入是否到期,通过 `ctx.shell` 查询位置,并把渲染状态与该来源最近一次持久注入比较。变化抑制与间隔调度会扫描原始持久会话事件,因此调度可跨压缩(compaction)与恢复的进程存续,无需进程内缓存状态;各会话独立调度。下游在步骤前运行的监听器拒绝或失败时,该读数不会被记录。
78
+
79
+ </details>
80
+
81
+ -----
82
+
83
+ <a id="further-exploration"></a>
84
+ ## 进一步探索
85
+
86
+ 包级约定不够用时阅读以下页面。它们从设计决策进入查询所经由的执行器与穷尽式配置。
87
+
88
+ - [tmux 位置上下文决策记录](../../../.agents/notes/implemented/feature/2026-07-27-tmux-location-context.zh.md)——基于 tty 的检测与读数形状的设计理由。
89
+ - [shell 子系统](../../../docs/subsystems/shell.zh.md)——只读查询所经由的执行器服务。
90
+ - [context 组地图](../README.zh.md)——相邻的请求上下文包。
91
+ - [生成的配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-tmux-context)——每个受支持配置字段及其源声明。
92
+
93
+ -----
94
+
95
+ <a id="model-experience"></a>
38
96
  ## 模型体验
39
97
 
40
98
  ### 准备期 tmux 位置
@@ -53,16 +111,31 @@ window active=<0|1>, pane active=<0|1>, layout <window-layout>
53
111
 
54
112
  #### Token 影响
55
113
 
56
- 每条两行读数会累积,直到压缩将其遮蔽。位置未变化以及间隔抑制不会新增内容。
114
+ 每条三行读数会累积,直到压缩将其遮蔽。位置未变化以及间隔抑制不会新增内容。
57
115
 
58
116
  #### KV Cache 影响
59
117
 
60
118
  仅追加;新增可见内容位于可复用的请求前缀之后,不会使已有 KV Cache 条目失效。
61
119
 
62
- ## 已知限制与后续工作
120
+ ## 已知限制与延期工作
121
+
122
+ <a id="known-limitations-and-deferred-work"></a>
123
+
124
+
125
+ 这些限制说明 tmux 位置上下文何时不合适。它们是当前包约束。
63
126
 
64
127
  - **仅第一个步骤**——轮次中途移动或缩放的 pane 会在下一轮反映,而非在步骤之间。
65
128
  - **仅自身位置**——插件从不采集相邻 pane 的可见文本。
66
129
  - **只有布局,没有尺寸**——省略 pane/window 像素尺寸;仅报告布局树与活动标志。
67
130
  - **制表符分隔字段**——若 tmux window 名称包含字面两字符序列 `\t`,会使读数分割错误并作为非法读数跳过;常规名称不受影响。
68
131
  - **基于 tty 的 pane 判定**——只有当进程的控制终端与 `$TMUX_PANE` 的 `#{pane_tty}` 一致时,才视为「位于 tmux 中」。这会有意排除从 tmux 祖先进程继承 `$TMUX`/`$TMUX_PANE` 的终端(如 VS Code 集成终端)。`ps -o tty=` 属于 POSIX;在其或 `#{pane_tty}` 不可用的环境中,该检查即为空操作。
132
+
133
+ <a id="dev-note"></a>
134
+ ### 开发备注
135
+
136
+ <details>
137
+ <summary>维护者的工作上下文——点击展开</summary>
138
+
139
+ 无。
140
+
141
+ </details>