pi-ssh-remote 0.1.4 → 0.1.5

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 CHANGED
@@ -31,7 +31,7 @@ The extension exposes `ssh_remote_control` for the agent and `/remote` for the u
31
31
 
32
32
  ### Stateful endpoints instead of disposable SSH commands
33
33
 
34
- Each `user@host:port` endpoint remembers its remote working directory, note, and port-forward configuration locally. Notes such as `H100 training`, `staging`, or `customer demo` appear in configuration, status messages, and Pi's footer, so the active execution environment stays visible.
34
+ Each `user@host:port` endpoint remembers its remote working directory, note, server-specific memory, and port-forward configuration locally. Notes such as `H100 training`, `staging`, or `customer demo` appear in configuration, status messages, and Pi's footer, so the active execution environment stays visible. Server memory is automatically injected into the model context whenever that endpoint is connected as the active remote workspace.
35
35
 
36
36
  ### Resilient and bounded by default
37
37
 
@@ -66,6 +66,7 @@ Requires Node.js 20+. The remote server must provide Bash, SFTP, and GNU `timeou
66
66
  /remote ssh root@gpu-box.example.com -p 2202
67
67
  /remote cd /srv/project
68
68
  /remote config note H100 training server
69
+ /remote config memory Use /opt/conda/bin/python and never stop shared jobs.
69
70
  /remote status
70
71
  ```
71
72
 
@@ -120,7 +121,7 @@ The default foreground timeout prevents an accidental long-running command from
120
121
  /remote
121
122
  ```
122
123
 
123
- Endpoint notes and working directories survive Pi restarts because they are stored in the local remote configuration.
124
+ Endpoint notes, working directories, and server-specific memories survive Pi restarts because they are stored in the local remote configuration. When Pi connects to an endpoint, its memory is added to the system context on every agent run while remote tool routing remains active. Disconnecting or switching to tunnel-only mode removes it from subsequent model requests.
124
125
 
125
126
  ### 4. Expose a remote service while editing locally
126
127
 
@@ -165,6 +166,8 @@ These requests are handled through the agent-facing `ssh_remote_control` tool; s
165
166
  | `/remote use USER@HOST:PORT` | Select a saved endpoint |
166
167
  | `/remote config note TEXT` | Persist a note for the selected endpoint |
167
168
  | `/remote config note --clear` | Clear its note |
169
+ | `/remote config memory TEXT` | Persist context that is injected while working on this endpoint |
170
+ | `/remote config memory --clear` | Clear its server-specific memory |
168
171
  | `/remote config cwd PATH` | Persist its default remote working directory |
169
172
  | `/remote cd PATH` | Change the connected remote cwd and persist it |
170
173
  | `/remote config forward MAPPING...` | Persist port forwards such as `7860:127.0.0.1:7860` |
@@ -187,7 +190,7 @@ Endpoint configuration is stored locally in:
187
190
  ~/.pi/agent/ssh-remote-config.json
188
191
  ```
189
192
 
190
- Saved values include endpoints, active endpoint, notes, remote working directories, forwards, and preview settings. Passwords are **never written to this file**: SSH agent authentication is preferred, and prompted passwords remain only in process memory.
193
+ Saved values include endpoints, active endpoint, notes, server-specific memories, remote working directories, forwards, and preview settings. Server memory is user-configured trusted context and is inserted into each model request only while that endpoint is the active remote workspace; it is not read from the remote server. Passwords are **never written to this file**: SSH agent authentication is preferred, and prompted passwords remain only in process memory.
191
194
 
192
195
  New or changed host keys require interactive confirmation and are stored separately from OpenSSH. Remote output sent to the model is limited to 2,000 lines or 50 KB; oversized complete output is written to a temporary local file. Preview-line settings affect only the collapsed UI.
193
196
 
@@ -195,4 +198,101 @@ New or changed host keys require interactive confirmation and are stored separat
195
198
 
196
199
  The extension currently supports direct SSH commands with `-p` and `-l`. It does not yet consume `~/.ssh/config`, `IdentityFile`, or ProxyJump settings.
197
200
 
201
+ ## Release history
202
+
203
+ Release dates below are npm publication dates. Every release records user-visible additions, changes, and bug fixes; `None` means that category had no changes in that release.
204
+
205
+ ### 0.1.5 — 2026-08-04
206
+
207
+ **Added**
208
+
209
+ - Added persistent, endpoint-specific server memory through `/remote config memory TEXT` and the `ssh_remote_control` `memory` action.
210
+ - Added automatic injection of that memory into every model request while the matching endpoint is the active remote workspace.
211
+
212
+ **Changed**
213
+
214
+ - Server memory is removed from subsequent model requests when remote tool routing is disabled, including disconnect and tunnel-only mode.
215
+ - `/remote config` now shows the memory stored for each endpoint.
216
+
217
+ **Fixed**
218
+
219
+ - None.
220
+
221
+ ### 0.1.4 — 2026-07-31
222
+
223
+ **Added**
224
+
225
+ - Added persistent endpoint notes through `/remote config note TEXT` and the `ssh_remote_control` `note` action.
226
+ - Added per-command timeout overrides through `/remote exec --timeout SECONDS` and the tool's `timeout` parameter.
227
+
228
+ **Changed**
229
+
230
+ - Remote commands now default to a 30-second timeout and endpoint notes appear in status, connection, reconnection, and footer labels.
231
+ - Expanded the documentation around agent-first workflows, multi-server operation, background jobs, and tunnel mode.
232
+
233
+ **Fixed**
234
+
235
+ - Fixed remote commands that could run without a deadline by enforcing GNU `timeout` remotely and a local fallback timer.
236
+ - Fixed timeout reporting for processes terminated with timeout-related exit codes 124 and 137.
237
+
238
+ ### 0.1.3 — 2026-07-24
239
+
240
+ **Added**
241
+
242
+ - Added configurable collapsed command previews with `/remote config display-lines N`, `/remote exec --lines N`, and the tool's `displayLines` parameter.
243
+ - Added expandable custom rendering for remote command results.
244
+
245
+ **Changed**
246
+
247
+ - Remote command previews default to the last five visual lines while model-facing output remains limited to 2,000 lines or 50 KB.
248
+ - Oversized complete output is saved to a permission-restricted local temporary file.
249
+
250
+ **Fixed**
251
+
252
+ - Fixed `/remote exec` truncating its notification to an arbitrary 4,000 characters without preserving or identifying the full output.
253
+
254
+ ### 0.1.2 — 2026-07-24
255
+
256
+ **Added**
257
+
258
+ - None.
259
+
260
+ **Changed**
261
+
262
+ - Republished the 0.1.1 runtime as 0.1.2 to align npm package version metadata; there were no runtime code changes.
263
+
264
+ **Fixed**
265
+
266
+ - None.
267
+
268
+ ### 0.1.1 — 2026-07-24
269
+
270
+ **Added**
271
+
272
+ - Added the shorter `/remote ssh USER@HOST [-p PORT]` connection command.
273
+
274
+ **Changed**
275
+
276
+ - `/remote ssh` now saves, selects, and immediately connects to the endpoint instead of only storing it.
277
+
278
+ **Fixed**
279
+
280
+ - Fixed help and error text that still instructed users to run the obsolete `/remote config ssh ssh ...` form.
281
+
282
+ ### 0.1.0 — 2026-07-24
283
+
284
+ **Added**
285
+
286
+ - Initial release with persistent multi-endpoint SSH workspaces and remote working directories.
287
+ - Added transparent routing for Pi's `read`, `write`, `edit`, `bash`, and user shell operations.
288
+ - Added SSH-agent/password authentication, interactive host-key verification, automatic reconnection, SFTP file access, bounded command output, and local TCP forwarding.
289
+
290
+ **Changed**
291
+
292
+ - None.
293
+
294
+ **Fixed**
295
+
296
+ - None.
297
+
198
298
  MIT licensed.
package/README.zh-CN.md CHANGED
@@ -51,9 +51,10 @@ SSH remote H100 训练机 (root@gpu-box.example.com:2202):/srv/project
51
51
  - SSH 地址;
52
52
  - 默认工作目录;
53
53
  - 服务器备注;
54
+ - 服务器特定记忆;
54
55
  - 端口转发配置。
55
56
 
56
- 例如可以把几台机器分别备注为 `8xH100 训练机`、`预发布环境`、`线上只读机`。这些配置保存在本地,重启 Pi 后仍然存在。
57
+ 例如可以把几台机器分别备注为 `8xH100 训练机`、`预发布环境`、`线上只读机`。还可以为每个 `user@host:port` 保存独立记忆,例如指定 Python 环境、共享任务保护规则或部署约定。连接该 endpoint 并启用远端工具路由后,这段记忆会自动注入模型上下文;断开连接或切换到纯隧道模式后,后续请求不再注入。所有配置保存在本地,重启 Pi 后仍然存在。
57
58
 
58
59
  ### 断线后可以自动恢复
59
60
 
@@ -106,6 +107,7 @@ pi install npm:pi-ssh-remote
106
107
  ```text
107
108
  /remote cd /srv/project
108
109
  /remote config note H100 训练机
110
+ /remote config memory 使用 /opt/conda/bin/python,不要停止其他用户的共享任务。
109
111
  ```
110
112
 
111
113
  查看当前状态:
@@ -218,6 +220,8 @@ Pi 会通过插件提供的 `ssh_remote_control` 工具完成这些操作。
218
220
  | `/remote use USER@HOST:PORT` | 切换到指定服务器 |
219
221
  | `/remote config note TEXT` | 给当前服务器添加或修改备注 |
220
222
  | `/remote config note --clear` | 清除当前服务器备注 |
223
+ | `/remote config memory TEXT` | 保存连接该服务器时自动注入上下文的记忆 |
224
+ | `/remote config memory --clear` | 清除当前服务器的特定记忆 |
221
225
  | `/remote config cwd PATH` | 设置默认远程工作目录 |
222
226
  | `/remote cd PATH` | 切换当前远程目录并保存 |
223
227
  | `/remote config forward MAPPING...` | 保存端口转发配置,例如 `7860:127.0.0.1:7860` |
@@ -245,10 +249,13 @@ Pi 会通过插件提供的 `ssh_remote_control` 工具完成这些操作。
245
249
  - 已保存的服务器;
246
250
  - 当前选中的服务器;
247
251
  - 服务器备注;
252
+ - 服务器特定记忆;
248
253
  - 默认远程目录;
249
254
  - 端口转发配置;
250
255
  - 命令预览设置。
251
256
 
257
+ 服务器记忆是由用户在本地配置的可信上下文,不会从远程服务器自动读取;仅当对应 endpoint 作为远端工作区启用时才会加入每次模型请求。
258
+
252
259
  密码不会写入配置文件。插件会优先使用 SSH agent;如果需要手动输入密码,密码只会缓存在当前 Pi 进程的内存中。
253
260
 
254
261
  ## 安全与输出限制
@@ -264,4 +271,101 @@ Pi 会通过插件提供的 `ssh_remote_control` 工具完成这些操作。
264
271
 
265
272
  目前只支持 SSH 直连,以及 `-p`、`-l` 参数。暂不读取 `~/.ssh/config`,也不支持 `IdentityFile` 和 ProxyJump。
266
273
 
274
+ ## 版本更新记录
275
+
276
+ 以下日期均为 npm 发布时间。每次发布都记录用户可见的新增内容、行为变更和 Bug 修复;“无”表示该版本在对应类别没有变化。
277
+
278
+ ### 0.1.5 — 2026-08-04
279
+
280
+ **新增**
281
+
282
+ - 新增 endpoint 级持久化服务器记忆,支持 `/remote config memory TEXT` 和 `ssh_remote_control` 的 `memory` action。
283
+ - 对应 endpoint 作为当前远程工作区时,在每次模型请求中自动注入服务器记忆。
284
+
285
+ **变更**
286
+
287
+ - 断开连接、关闭远端工具路由或进入纯隧道模式后,后续模型请求不再包含服务器记忆。
288
+ - `/remote config` 现在会显示每个 endpoint 保存的记忆。
289
+
290
+ **修复**
291
+
292
+ - 无。
293
+
294
+ ### 0.1.4 — 2026-07-31
295
+
296
+ **新增**
297
+
298
+ - 新增 endpoint 备注,支持 `/remote config note TEXT` 和 `ssh_remote_control` 的 `note` action。
299
+ - 新增单次命令超时覆盖,支持 `/remote exec --timeout SECONDS` 和工具的 `timeout` 参数。
300
+
301
+ **变更**
302
+
303
+ - 远程命令默认超时改为 30 秒;备注会显示在状态、连接、重连提示和底部状态栏中。
304
+ - 扩充了 Agent 工作流、多服务器、后台任务和纯隧道模式文档。
305
+
306
+ **修复**
307
+
308
+ - 修复部分远程命令没有截止时间、可能一直占用 Agent 的问题:远端使用 GNU `timeout`,本地增加兜底定时器。
309
+ - 修复退出码 124 和 137 未被统一识别为超时的问题。
310
+
311
+ ### 0.1.3 — 2026-07-24
312
+
313
+ **新增**
314
+
315
+ - 新增可配置的命令折叠预览,支持 `/remote config display-lines N`、`/remote exec --lines N` 和工具的 `displayLines` 参数。
316
+ - 新增远程命令结果的展开显示。
317
+
318
+ **变更**
319
+
320
+ - 命令折叠预览默认显示最后 5 个视觉行;发送给模型的输出仍限制为 2,000 行或 50 KB。
321
+ - 超限的完整输出会保存到权限受限的本地临时文件。
322
+
323
+ **修复**
324
+
325
+ - 修复 `/remote exec` 直接按 4,000 字符截断通知、且不保留或提示完整输出位置的问题。
326
+
327
+ ### 0.1.2 — 2026-07-24
328
+
329
+ **新增**
330
+
331
+ - 无。
332
+
333
+ **变更**
334
+
335
+ - 将 0.1.1 的运行时代码以 0.1.2 重新发布,用于对齐 npm 包版本元数据;没有运行时代码变化。
336
+
337
+ **修复**
338
+
339
+ - 无。
340
+
341
+ ### 0.1.1 — 2026-07-24
342
+
343
+ **新增**
344
+
345
+ - 新增简化命令 `/remote ssh USER@HOST [-p PORT]`。
346
+
347
+ **变更**
348
+
349
+ - `/remote ssh` 现在会保存、选中并立即连接 endpoint,而不只是保存配置。
350
+
351
+ **修复**
352
+
353
+ - 修复帮助和错误信息仍提示使用旧命令 `/remote config ssh ssh ...` 的问题。
354
+
355
+ ### 0.1.0 — 2026-07-24
356
+
357
+ **新增**
358
+
359
+ - 首次发布,支持持久化多 endpoint SSH 工作区和远程工作目录。
360
+ - 新增 Pi `read`、`write`、`edit`、`bash` 和用户 Shell 操作的透明远端路由。
361
+ - 新增 SSH agent/密码认证、交互式主机密钥校验、自动重连、SFTP 文件访问、命令输出限制和本地 TCP 端口转发。
362
+
363
+ **变更**
364
+
365
+ - 无。
366
+
367
+ **修复**
368
+
369
+ - 无。
370
+
267
371
  MIT License。
package/index.ts CHANGED
@@ -55,6 +55,7 @@ interface RemoteEndpointConfig {
55
55
  remoteCwd?: string;
56
56
  forwards?: string[];
57
57
  note?: string;
58
+ memory?: string;
58
59
  }
59
60
 
60
61
  interface RemoteConfig {
@@ -252,6 +253,23 @@ function endpointDisplayLabel(endpoint: ParsedSsh, config = loadRemoteConfig()):
252
253
  return note ? `${note} (${endpoint.label})` : endpoint.label;
253
254
  }
254
255
 
256
+ function endpointMemory(endpoint: ParsedSsh, config = loadRemoteConfig()): string | undefined {
257
+ return endpointConfig(config, endpoint.command).memory?.trim() || undefined;
258
+ }
259
+
260
+ function remoteSystemPrompt(systemPrompt: string, localCwd: string, remote: RemoteState): string {
261
+ return systemPrompt.replace(
262
+ `Current working directory: ${localCwd}`,
263
+ `Current working directory: ${remote.cwd} (via SSH ${endpointDisplayLabel(remote)}). All read, write, edit, bash, and user shell operations run on this remote server. Use ssh_remote_control with action disconnect to return to the local environment when requested.`,
264
+ );
265
+ }
266
+
267
+ function serverMemoryContext(remote: RemoteState): string | undefined {
268
+ const memory = endpointMemory(remote);
269
+ if (!memory) return undefined;
270
+ return `<ssh_remote_server_memory endpoint="${remote.label}">\nThe following is user-configured, persistent memory specific to this SSH server. Apply it while working on this server:\n${memory}\n</ssh_remote_server_memory>`;
271
+ }
272
+
255
273
  function saveEndpointConfig(command: string, updates: RemoteEndpointConfig, makeActive = false): void {
256
274
  const config = loadRemoteConfig();
257
275
  const key = cacheId(parseSshCommand(command));
@@ -759,8 +777,8 @@ export default function sshRemoteExtension(pi: ExtensionAPI) {
759
777
  pi.registerTool({
760
778
  name: "ssh_remote_control",
761
779
  label: "SSH Remote Control",
762
- description: "Connect, reconnect, annotate endpoints, change the persistent remote working directory, inspect, forward ports, run remote SSH commands, or disconnect the configured SSH environment. Exec output uses a configurable collapsed preview (5 visual lines by default), while model output is limited to 50KB or 2000 lines and saved to a local temporary file when truncated. Passwords are never accepted as arguments and are cached only in process memory.",
763
- promptSnippet: "Control the configured remote SSH connection, endpoint note, working directory, and local port forwarding",
780
+ description: "Connect, reconnect, annotate endpoints, manage server-specific memory, change the persistent remote working directory, inspect, forward ports, run remote SSH commands, or disconnect the configured SSH environment. Exec output uses a configurable collapsed preview (5 visual lines by default), while model output is limited to 50KB or 2000 lines and saved to a local temporary file when truncated. Passwords are never accepted as arguments and are cached only in process memory.",
781
+ promptSnippet: "Control the configured remote SSH connection, endpoint note and memory, working directory, and local port forwarding",
764
782
  promptGuidelines: [
765
783
  "Use ssh_remote_control when the user asks the agent to enter, reconnect, inspect, or leave a remote SSH environment.",
766
784
  "Use ssh_remote_control with action chdir when the user asks to change the remote working directory; do not emulate a persistent directory change with action exec and a one-command cwd.",
@@ -768,9 +786,10 @@ export default function sshRemoteExtension(pi: ExtensionAPI) {
768
786
  "Use ssh_remote_control with action disconnect after remote work when the user asks to return to the local environment.",
769
787
  ],
770
788
  parameters: Type.Object({
771
- action: StringEnum(["connect", "reconnect", "status", "disconnect", "forget", "forward", "unforward", "exec", "chdir", "note"] as const),
772
- command: Type.Optional(Type.String({ description: "SSH command for connect, such as ssh root@host -p 22; optionally selects the endpoint for note" })),
789
+ action: StringEnum(["connect", "reconnect", "status", "disconnect", "forget", "forward", "unforward", "exec", "chdir", "note", "memory"] as const),
790
+ command: Type.Optional(Type.String({ description: "SSH command for connect, such as ssh root@host -p 22; optionally selects the endpoint for note or memory" })),
773
791
  note: Type.Optional(Type.String({ description: "Endpoint note for the note action; omit or use an empty string to clear it" })),
792
+ memory: Type.Optional(Type.String({ description: "Persistent server-specific context for the memory action; omit or use an empty string to clear it" })),
774
793
  cwd: Type.Optional(Type.String({ description: "Remote working directory; required for chdir, and a one-command override for exec" })),
775
794
  forwards: Type.Optional(Type.String({ description: "Space-separated LOCAL_PORT:REMOTE_HOST:REMOTE_PORT mappings; defaults to ssh-remote-config.json" })),
776
795
  remoteCommand: Type.Optional(Type.String({ description: "Remote shell command for the exec action" })),
@@ -813,16 +832,24 @@ export default function sshRemoteExtension(pi: ExtensionAPI) {
813
832
  const resolved = await changeRemoteCwd(params.cwd, ctx);
814
833
  return { content: [{ type: "text", text: `Remote working directory: ${resolved}` }], details: { connected: true, cwd: resolved } };
815
834
  }
816
- if (params.action === "note") {
835
+ if (params.action === "note" || params.action === "memory") {
817
836
  const command = params.command || lastCommand || activeSshCommand();
818
837
  if (!command) throw new Error("No SSH endpoint configured; connect or select an endpoint first");
819
- const note = params.note?.trim() || undefined;
820
- saveEndpointConfig(command, { note });
821
- if (remote && cacheId(remote) === cacheId(parseSshCommand(command)) && currentCtx) status(currentCtx);
822
838
  const label = parseSshCommand(command).label;
839
+ if (params.action === "note") {
840
+ const note = params.note?.trim() || undefined;
841
+ saveEndpointConfig(command, { note });
842
+ if (remote && cacheId(remote) === cacheId(parseSshCommand(command)) && currentCtx) status(currentCtx);
843
+ return {
844
+ content: [{ type: "text", text: note ? `SSH remote note updated (${label}): ${note}` : `SSH remote note cleared (${label})` }],
845
+ details: { endpoint: label, note },
846
+ };
847
+ }
848
+ const memory = params.memory?.trim() || undefined;
849
+ saveEndpointConfig(command, { memory });
823
850
  return {
824
- content: [{ type: "text", text: note ? `SSH remote note updated (${label}): ${note}` : `SSH remote note cleared (${label})` }],
825
- details: { endpoint: label, note },
851
+ content: [{ type: "text", text: memory ? `SSH remote server memory updated (${label}). It will be injected while this endpoint is the active remote workspace.` : `SSH remote server memory cleared (${label}).` }],
852
+ details: { endpoint: label, memory },
826
853
  };
827
854
  }
828
855
  if (params.action === "exec") {
@@ -867,7 +894,7 @@ export default function sshRemoteExtension(pi: ExtensionAPI) {
867
894
  });
868
895
 
869
896
  pi.registerCommand("remote", {
870
- description: "Connect over SSH and manage endpoints: /remote | ssh USER@HOST [-p PORT] | config | use USER@HOST:PORT | config note TEXT|--clear | config cwd PATH | config display-lines N | forward [MAPPINGS] | unforward | exec [--timeout SECONDS] [--lines N] COMMAND | cd PATH | status | reload | off | forget",
897
+ description: "Connect over SSH and manage endpoints: /remote | ssh USER@HOST [-p PORT] | config | use USER@HOST:PORT | config note TEXT|--clear | config memory TEXT|--clear | config cwd PATH | config display-lines N | forward [MAPPINGS] | unforward | exec [--timeout SECONDS] [--lines N] COMMAND | cd PATH | status | reload | off | forget",
871
898
  handler: async (args, ctx) => {
872
899
  const input = args.trim().replace(/^\/?remote(?:\s+|$)/i, "").trim();
873
900
  const action = input.toLowerCase();
@@ -875,7 +902,7 @@ export default function sshRemoteExtension(pi: ExtensionAPI) {
875
902
  const config = loadRemoteConfig();
876
903
  const rows = Object.entries(config.endpoints ?? {}).map(([key, endpoint]) => {
877
904
  const active = key === config.activeEndpoint ? "*" : " ";
878
- return `${active} ${key}\n note: ${endpoint.note || "none"}\n SSH: ${endpoint.sshCommand}\n cwd: ${endpoint.remoteCwd || FALLBACK_REMOTE_CWD}\n forward: ${endpoint.forwards?.join(", ") || "none"}`;
905
+ return `${active} ${key}\n note: ${endpoint.note || "none"}\n memory: ${endpoint.memory || "none"}\n SSH: ${endpoint.sshCommand}\n cwd: ${endpoint.remoteCwd || FALLBACK_REMOTE_CWD}\n forward: ${endpoint.forwards?.join(", ") || "none"}`;
879
906
  });
880
907
  ctx.ui.notify(`SSH remote configuration: ${REMOTE_CONFIG_FILE}\nDisplay lines: ${configuredDisplayLines(config)}\n${rows.join("\n") || "No saved endpoints"}`, "info");
881
908
  return;
@@ -927,6 +954,16 @@ export default function sshRemoteExtension(pi: ExtensionAPI) {
927
954
  ctx.ui.notify(note ? `SSH remote note updated (${parseSshCommand(command).label}): ${note}` : `SSH remote note cleared (${parseSshCommand(command).label})`, "info");
928
955
  return;
929
956
  }
957
+ if (/^config\s+memory(?:\s+|$)/i.test(input)) {
958
+ const value = input.replace(/^config\s+memory\s*/i, "").trim();
959
+ if (!value) { ctx.ui.notify("Use /remote config memory TEXT or /remote config memory --clear", "error"); return; }
960
+ const command = lastCommand || activeSshCommand();
961
+ if (!command) { ctx.ui.notify("Configure an SSH endpoint first", "error"); return; }
962
+ const memory = value.toLowerCase() === "--clear" ? undefined : value;
963
+ saveEndpointConfig(command, { memory });
964
+ ctx.ui.notify(memory ? `SSH remote server memory updated (${parseSshCommand(command).label}); it will be injected while connected` : `SSH remote server memory cleared (${parseSshCommand(command).label})`, "info");
965
+ return;
966
+ }
930
967
  if (/^config\s+display-lines\s+/i.test(input)) {
931
968
  try {
932
969
  const displayLines = parseDisplayLines(input.replace(/^config\s+display-lines\s+/i, "").trim());
@@ -1055,9 +1092,20 @@ export default function sshRemoteExtension(pi: ExtensionAPI) {
1055
1092
  }
1056
1093
  });
1057
1094
  pi.on("before_agent_start", (event) => remote && routeRemoteTools ? {
1058
- systemPrompt: event.systemPrompt.replace(
1059
- `Current working directory: ${localCwd}`,
1060
- `Current working directory: ${remote.cwd} (via SSH ${endpointDisplayLabel(remote)}). All read, write, edit, bash, and user shell operations run on this remote server. Use ssh_remote_control with action disconnect to return to the local environment when requested.`,
1061
- ),
1095
+ systemPrompt: remoteSystemPrompt(event.systemPrompt, localCwd, remote),
1062
1096
  } : undefined);
1097
+ pi.on("context", (event) => {
1098
+ if (!remote || !routeRemoteTools) return undefined;
1099
+ const content = serverMemoryContext(remote);
1100
+ if (!content) return undefined;
1101
+ return {
1102
+ messages: [...event.messages, {
1103
+ role: "custom",
1104
+ customType: "ssh-remote-server-memory",
1105
+ content,
1106
+ display: false,
1107
+ timestamp: Date.now(),
1108
+ }],
1109
+ };
1110
+ });
1063
1111
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-ssh-remote",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Persistent remote SSH workspaces for Pi.",
5
5
  "type": "module",
6
6
  "author": "Yutong Bian",