@north-light/crouter 0.3.247 → 0.3.249

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.
@@ -73,6 +73,12 @@ export declare class ContextAdminShell implements Component, Focusable {
73
73
  * modal over the rows it is selecting. */
74
74
  private handleSearch;
75
75
  private handleDetail;
76
+ /** Put the focused document's path on the clipboard, so a reader who spotted
77
+ * the document that is misbehaving can open, grep, or pass it along without
78
+ * retyping it off the screen. The clipboard carries the absolute path, which
79
+ * is what survives being pasted into another command; the notice collapses
80
+ * it against home, which is only read. */
81
+ private yankPath;
76
82
  /** The resting face: reading, and the two gestures that leave it. */
77
83
  private handleRead;
78
84
  /** The field list. Every write gesture is resolved before it is started, so a
@@ -4,6 +4,8 @@
4
4
  // dialled event, and the dossier is the only place a write starts.
5
5
  import { Input, matchesKey, truncateToWidth, visibleWidth, } from '@earendil-works/pi-tui';
6
6
  import { formatGesture, matchesPiTuiInput, } from '../../../../core/keybindings/index.js';
7
+ import { writeClipboardTextEverywhere } from '../../../../core/clipboard-text.js';
8
+ import { shortPath } from '../../../../core/inspector/model.js';
7
9
  import { runTuiPage } from '../../../../core/tui/page-host.js';
8
10
  import { PAGE_CHROME_ROWS, columns, framed, pageFrame, theme, } from '../../../../core/tui/panel.js';
9
11
  import { RUNGS, SURFACE_EVENTS, SURFACE_RUNGS, } from '../../../../core/substrate/schema.js';
@@ -250,6 +252,9 @@ export class ContextAdminShell {
250
252
  if (data === '/' || matchesKey(data, '/')) {
251
253
  this.openSearch();
252
254
  }
255
+ else if (matchesKey(data, 'y')) {
256
+ this.yankPath();
257
+ }
253
258
  else if (this.isDown(data)) {
254
259
  this.docs.move(1);
255
260
  this.syncDetail();
@@ -302,11 +307,29 @@ export class ContextAdminShell {
302
307
  this.tui.requestRender();
303
308
  }
304
309
  handleDetail(data) {
305
- if (this.detail.editing)
310
+ if (matchesKey(data, 'y'))
311
+ this.yankPath();
312
+ else if (this.detail.editing)
306
313
  this.handleEdit(data);
307
314
  else
308
315
  this.handleRead(data);
309
316
  }
317
+ /** Put the focused document's path on the clipboard, so a reader who spotted
318
+ * the document that is misbehaving can open, grep, or pass it along without
319
+ * retyping it off the screen. The clipboard carries the absolute path, which
320
+ * is what survives being pasted into another command; the notice collapses
321
+ * it against home, which is only read. */
322
+ yankPath() {
323
+ const row = this.docs.selected;
324
+ if (row === undefined)
325
+ return;
326
+ const { system, tmux } = writeClipboardTextEverywhere(row.key);
327
+ this.notice =
328
+ system || tmux
329
+ ? { text: `Copied ${shortPath(row.key)}${system ? '' : ' to the tmux buffer'}`, ok: true }
330
+ : { text: 'No clipboard tool available — nothing copied', ok: false };
331
+ this.tui.requestRender();
332
+ }
310
333
  /** The resting face: reading, and the two gestures that leave it. */
311
334
  handleRead(data) {
312
335
  if (this.isDown(data))
@@ -743,12 +766,12 @@ export class ContextAdminShell {
743
766
  const left = this.zone === 'rail'
744
767
  ? `${move} row · ${railGesture(railRow)}`
745
768
  : this.zone === 'docs'
746
- ? `${move} row · ${this.docsGesture()} · / search`
769
+ ? `${move} row · ${this.docsGesture()} · / search · y path`
747
770
  : this.detail.editing
748
- ? `${move} field · enter edit · e add · x remove · g gate · b body · u unlisted · s slash · m cap · r rename · esc read`
771
+ ? `${move} field · enter edit · e add · x remove · g gate · b body · u unlisted · s slash · m cap · r rename · y path · esc read`
749
772
  : this.detail.bodyOpen
750
- ? `${move} scroll · ctrl-d/u page · g/G ends · esc collapse`
751
- : `${move} scroll · enter body · e edit · esc list`;
773
+ ? `${move} scroll · ctrl-d/u page · g/G ends · y path · esc collapse`
774
+ : `${move} scroll · enter body · e edit · y path · esc list`;
752
775
  const right = `${this.label('crtr.setup.tab-next', 'tab')} event · ${this.label('crtr.setup.cancel', 'q')} close`;
753
776
  const gap = width - visibleWidth(left) - visibleWidth(right);
754
777
  return gap >= 2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.247",
3
+ "version": "0.3.249",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.247",
3
+ "version": "0.3.249",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/crouter",
9
- "version": "0.3.247",
9
+ "version": "0.3.249",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT",
12
12
  "dependencies": {
@@ -1,2 +0,0 @@
1
- /** Write text to the system clipboard without throwing. */
2
- export declare function writeClipboardText(text: string): boolean;
@@ -1,26 +0,0 @@
1
- import { spawnSync } from 'node:child_process';
2
- const SPAWN_TIMEOUT_MS = 3000;
3
- function writers() {
4
- if (process.platform === 'darwin')
5
- return [['pbcopy', []]];
6
- const wayland = Boolean(process.env.WAYLAND_DISPLAY)
7
- || process.env.XDG_SESSION_TYPE === 'wayland';
8
- const xclip = ['xclip', ['-selection', 'clipboard']];
9
- const wlcopy = ['wl-copy', []];
10
- return wayland ? [wlcopy, xclip] : [xclip, wlcopy];
11
- }
12
- /** Write text to the system clipboard without throwing. */
13
- export function writeClipboardText(text) {
14
- for (const [command, args] of writers()) {
15
- const result = spawnSync(command, args, {
16
- input: text,
17
- timeout: SPAWN_TIMEOUT_MS,
18
- encoding: 'utf-8',
19
- });
20
- if (result.error)
21
- continue;
22
- if (result.status === 0)
23
- return true;
24
- }
25
- return false;
26
- }