pi-harness-runtime 0.10.26 → 0.10.42
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/.pi/plugins/herdr-clipboard/herdr-plugin.toml +22 -0
- package/.pi/plugins/herdr-clipboard/start-bridge.sh +29 -0
- package/.pi/plugins/herdr-clipboard/tmux-watch.sh +39 -0
- package/CHANGELOG.md +41 -0
- package/README.md +87 -1
- package/config.toml.example +35 -0
- package/package.json +6 -4
- package/packages/architecture-generator/dist/adr.d.ts +15 -0
- package/packages/architecture-generator/dist/adr.d.ts.map +1 -0
- package/packages/architecture-generator/dist/adr.js +42 -0
- package/packages/architecture-generator/dist/adr.js.map +1 -0
- package/packages/architecture-generator/dist/index.d.ts +9 -0
- package/packages/architecture-generator/dist/index.d.ts.map +1 -0
- package/packages/architecture-generator/dist/index.js +9 -0
- package/packages/architecture-generator/dist/index.js.map +1 -0
- package/packages/architecture-generator/dist/mermaid.d.ts +30 -0
- package/packages/architecture-generator/dist/mermaid.d.ts.map +1 -0
- package/packages/architecture-generator/dist/mermaid.js +58 -0
- package/packages/architecture-generator/dist/mermaid.js.map +1 -0
- package/packages/architecture-generator/dist/types.d.ts +30 -0
- package/packages/architecture-generator/dist/types.d.ts.map +1 -0
- package/packages/architecture-generator/dist/types.js +7 -0
- package/packages/architecture-generator/dist/types.js.map +1 -0
- package/packages/architecture-generator/src/adr.ts +51 -0
- package/packages/architecture-generator/src/index.ts +9 -0
- package/packages/architecture-generator/src/mermaid.ts +76 -0
- package/packages/architecture-generator/src/types.ts +30 -0
- package/packages/capability-registry/src/types.js +10 -0
- package/packages/clipboard/dist/src/copy-sync.d.ts.map +1 -1
- package/packages/clipboard/dist/src/copy-sync.js +45 -3
- package/packages/clipboard/dist/src/copy-sync.js.map +1 -1
- package/packages/clipboard/dist/src/index.d.ts +1 -0
- package/packages/clipboard/dist/src/index.d.ts.map +1 -1
- package/packages/clipboard/dist/src/index.js +1 -0
- package/packages/clipboard/dist/src/index.js.map +1 -1
- package/packages/clipboard/dist/src/paste-bridge.d.ts +19 -0
- package/packages/clipboard/dist/src/paste-bridge.d.ts.map +1 -0
- package/packages/clipboard/dist/src/paste-bridge.js +78 -0
- package/packages/clipboard/dist/src/paste-bridge.js.map +1 -0
- package/packages/clipboard/src/copy-sync.ts +52 -3
- package/packages/clipboard/src/index.ts +1 -0
- package/packages/clipboard/src/paste-bridge.ts +86 -0
- package/packages/clipboard-plugin/dist/index.d.ts +28 -0
- package/packages/clipboard-plugin/dist/index.d.ts.map +1 -0
- package/packages/clipboard-plugin/dist/index.js +64 -0
- package/packages/clipboard-plugin/dist/index.js.map +1 -0
- package/packages/clipboard-plugin/dist/types.d.ts +30 -0
- package/packages/clipboard-plugin/dist/types.d.ts.map +1 -0
- package/packages/clipboard-plugin/dist/types.js +5 -0
- package/packages/clipboard-plugin/dist/types.js.map +1 -0
- package/packages/clipboard-plugin/src/index.ts +74 -0
- package/packages/clipboard-plugin/src/types.ts +30 -0
- package/packages/file-copy-helper/dist/src/extension.js +84 -25
- package/packages/file-copy-helper/src/extension.debug.ts +226 -0
- package/packages/file-copy-helper/src/extension.ts +89 -59
- package/packages/knowledge-graph/dist/graph-extractor.d.ts +27 -0
- package/packages/knowledge-graph/dist/graph-extractor.d.ts.map +1 -0
- package/packages/knowledge-graph/dist/graph-extractor.js +276 -0
- package/packages/knowledge-graph/dist/graph-extractor.js.map +1 -0
- package/packages/knowledge-graph/dist/index.d.ts +27 -0
- package/packages/knowledge-graph/dist/index.d.ts.map +1 -0
- package/packages/knowledge-graph/dist/index.js +27 -0
- package/packages/knowledge-graph/dist/index.js.map +1 -0
- package/packages/knowledge-graph/dist/mcp-client.d.ts +38 -0
- package/packages/knowledge-graph/dist/mcp-client.d.ts.map +1 -0
- package/packages/knowledge-graph/dist/mcp-client.js +157 -0
- package/packages/knowledge-graph/dist/mcp-client.js.map +1 -0
- package/packages/knowledge-graph/dist/provenance-linker.d.ts +19 -0
- package/packages/knowledge-graph/dist/provenance-linker.d.ts.map +1 -0
- package/packages/knowledge-graph/dist/provenance-linker.js +91 -0
- package/packages/knowledge-graph/dist/provenance-linker.js.map +1 -0
- package/packages/knowledge-graph/dist/types.d.ts +53 -0
- package/packages/knowledge-graph/dist/types.d.ts.map +1 -0
- package/packages/knowledge-graph/dist/types.js +7 -0
- package/packages/knowledge-graph/dist/types.js.map +1 -0
- package/packages/knowledge-graph/src/graph-extractor.ts +338 -0
- package/packages/knowledge-graph/src/index.ts +27 -0
- package/packages/knowledge-graph/src/mcp-client.ts +237 -0
- package/packages/knowledge-graph/src/provenance-linker.ts +101 -0
- package/packages/knowledge-graph/src/types.ts +86 -0
- package/packages/milestone-manager/dist/engine.d.ts +27 -0
- package/packages/milestone-manager/dist/engine.d.ts.map +1 -0
- package/packages/milestone-manager/dist/engine.js +78 -0
- package/packages/milestone-manager/dist/engine.js.map +1 -0
- package/packages/milestone-manager/dist/index.d.ts +6 -0
- package/packages/milestone-manager/dist/index.d.ts.map +1 -0
- package/packages/milestone-manager/dist/index.js +6 -0
- package/packages/milestone-manager/dist/index.js.map +1 -0
- package/packages/milestone-manager/dist/types.d.ts +25 -0
- package/packages/milestone-manager/dist/types.d.ts.map +1 -0
- package/packages/milestone-manager/dist/types.js +7 -0
- package/packages/milestone-manager/dist/types.js.map +1 -0
- package/packages/milestone-manager/src/engine.ts +105 -0
- package/packages/milestone-manager/src/index.ts +6 -0
- package/packages/milestone-manager/src/types.ts +28 -0
- package/packages/notification/dist/adapters/line-adapter.d.ts +17 -0
- package/packages/notification/dist/adapters/line-adapter.d.ts.map +1 -0
- package/packages/notification/dist/adapters/line-adapter.js +99 -0
- package/packages/notification/dist/adapters/line-adapter.js.map +1 -0
- package/packages/notification/dist/index.d.ts +1 -0
- package/packages/notification/dist/index.d.ts.map +1 -1
- package/packages/notification/dist/index.js +1 -0
- package/packages/notification/dist/index.js.map +1 -1
- package/packages/notification/dist/notification-center.d.ts.map +1 -1
- package/packages/notification/dist/notification-center.js +4 -0
- package/packages/notification/dist/notification-center.js.map +1 -1
- package/packages/notification/dist/types.d.ts +6 -2
- package/packages/notification/dist/types.d.ts.map +1 -1
- package/packages/notification/src/adapters/line-adapter.ts +119 -0
- package/packages/notification/src/index.ts +1 -0
- package/packages/notification/src/notification-center.ts +6 -0
- package/packages/notification/src/types.ts +7 -2
- package/packages/project-bootstrap/dist/bootstrap.d.ts +23 -0
- package/packages/project-bootstrap/dist/bootstrap.d.ts.map +1 -0
- package/packages/project-bootstrap/dist/bootstrap.js +128 -0
- package/packages/project-bootstrap/dist/bootstrap.js.map +1 -0
- package/packages/project-bootstrap/dist/frappe.d.ts +8 -0
- package/packages/project-bootstrap/dist/frappe.d.ts.map +1 -0
- package/packages/project-bootstrap/dist/frappe.js +82 -0
- package/packages/project-bootstrap/dist/frappe.js.map +1 -0
- package/packages/project-bootstrap/dist/index.d.ts +27 -0
- package/packages/project-bootstrap/dist/index.d.ts.map +1 -0
- package/packages/project-bootstrap/dist/index.js +27 -0
- package/packages/project-bootstrap/dist/index.js.map +1 -0
- package/packages/project-bootstrap/dist/minimal.d.ts +8 -0
- package/packages/project-bootstrap/dist/minimal.d.ts.map +1 -0
- package/packages/project-bootstrap/dist/minimal.js +35 -0
- package/packages/project-bootstrap/dist/minimal.js.map +1 -0
- package/packages/project-bootstrap/dist/types.d.ts +61 -0
- package/packages/project-bootstrap/dist/types.d.ts.map +1 -0
- package/packages/project-bootstrap/dist/types.js +7 -0
- package/packages/project-bootstrap/dist/types.js.map +1 -0
- package/packages/project-bootstrap/dist/typescript.d.ts +8 -0
- package/packages/project-bootstrap/dist/typescript.d.ts.map +1 -0
- package/packages/project-bootstrap/dist/typescript.js +103 -0
- package/packages/project-bootstrap/dist/typescript.js.map +1 -0
- package/packages/project-bootstrap/src/bootstrap.ts +166 -0
- package/packages/project-bootstrap/src/frappe.ts +97 -0
- package/packages/project-bootstrap/src/index.ts +27 -0
- package/packages/project-bootstrap/src/minimal.ts +45 -0
- package/packages/project-bootstrap/src/types.ts +66 -0
- package/packages/project-bootstrap/src/typescript.ts +114 -0
- package/packages/provider-router/dist/src/types.js +1 -1
- package/packages/write-review/src/index.ts +47 -0
- package/packages/write-review/src/injection.ts +21 -1
- package/prompts/agents/reviewer.md +57 -0
- package/prompts/agents/writer.md +42 -0
- package/prompts/slash-commands.md +40 -0
- package/prompts/write-review.md +50 -0
- package/scripts/copy-plugins.js +56 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Architecture Generator - RFC-0073
|
|
3
|
+
*
|
|
4
|
+
* Generate Mermaid diagrams.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ArchitectureDiagram, DiagramType, ArchitectureAnalysis } from './types.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Generate component diagram
|
|
11
|
+
*/
|
|
12
|
+
export function generateComponentDiagram(analysis: ArchitectureAnalysis): ArchitectureDiagram {
|
|
13
|
+
const mermaid = [
|
|
14
|
+
'graph TB',
|
|
15
|
+
' subgraph Layers',
|
|
16
|
+
...analysis.layers.map((layer, i) => {
|
|
17
|
+
const nodes = analysis.components.filter((_, j) => j % analysis.layers.length === i);
|
|
18
|
+
return ` ${nodes.join(' --> ')}`;
|
|
19
|
+
}),
|
|
20
|
+
' end',
|
|
21
|
+
...analysis.dependencies.map(d => ` ${d.from} --> ${d.to}`),
|
|
22
|
+
].join('\n');
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
type: 'component',
|
|
26
|
+
title: 'Architecture Components',
|
|
27
|
+
mermaid,
|
|
28
|
+
description: 'Component diagram showing layers and dependencies',
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Generate sequence diagram
|
|
34
|
+
*/
|
|
35
|
+
export function generateSequenceDiagram(
|
|
36
|
+
title: string,
|
|
37
|
+
steps: { actor: string; action: string; target: string }[]
|
|
38
|
+
): ArchitectureDiagram {
|
|
39
|
+
const mermaid = [
|
|
40
|
+
'sequenceDiagram',
|
|
41
|
+
...steps.map(
|
|
42
|
+
s => ` ${s.actor}->>+${s.target}: ${s.action}`
|
|
43
|
+
),
|
|
44
|
+
].join('\n');
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
type: 'sequence',
|
|
48
|
+
title,
|
|
49
|
+
mermaid,
|
|
50
|
+
description: 'Sequence diagram showing interaction flow',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Generate flow diagram
|
|
56
|
+
*/
|
|
57
|
+
export function generateFlowDiagram(
|
|
58
|
+
title: string,
|
|
59
|
+
nodes: { id: string; label: string }[],
|
|
60
|
+
edges: { from: string; to: string; label?: string }[]
|
|
61
|
+
): ArchitectureDiagram {
|
|
62
|
+
const mermaid = [
|
|
63
|
+
'flowchart LR',
|
|
64
|
+
...nodes.map(n => ` ${n.id}[${n.label}]`),
|
|
65
|
+
...edges.map(
|
|
66
|
+
e => ` ${e.from}${e.label ? `-->|"${e.label}"|` : '->>'}${e.to}`
|
|
67
|
+
),
|
|
68
|
+
].join('\n');
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
type: 'flow',
|
|
72
|
+
title,
|
|
73
|
+
mermaid,
|
|
74
|
+
description: 'Flow diagram showing process flow',
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Architecture Generator - RFC-0073
|
|
3
|
+
*
|
|
4
|
+
* Generate ADR and Mermaid diagrams from project analysis.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export type DiagramType = 'component' | 'flow' | 'sequence' | 'er' | 'class';
|
|
8
|
+
|
|
9
|
+
export interface ArchitectureDiagram {
|
|
10
|
+
type: DiagramType;
|
|
11
|
+
title: string;
|
|
12
|
+
mermaid: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ADR {
|
|
17
|
+
id: string;
|
|
18
|
+
title: string;
|
|
19
|
+
status: 'proposed' | 'accepted' | 'deprecated';
|
|
20
|
+
context: string;
|
|
21
|
+
decision: string;
|
|
22
|
+
consequences: string;
|
|
23
|
+
createdAt: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ArchitectureAnalysis {
|
|
27
|
+
components: string[];
|
|
28
|
+
dependencies: { from: string; to: string }[];
|
|
29
|
+
layers: string[];
|
|
30
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copy-sync.d.ts","sourceRoot":"","sources":["../../src/copy-sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"copy-sync.d.ts","sourceRoot":"","sources":["../../src/copy-sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA8KH;;;GAGG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE;IACtC,EAAE,EAAE;QAAE,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CACrD,GAAG,OAAO,CAAC,IAAI,CAAC,CAoChB;AAKD,KAAK,KAAK,GAAG,GAAG,CAAC;AAEjB;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,GAAG,IAAI,CAapE"}
|
|
@@ -65,9 +65,51 @@ function repairMojibake(text) {
|
|
|
65
65
|
return text;
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
-
// ───
|
|
68
|
+
// ─── Detect clipboard tool ──────────────────────────────────────────────────
|
|
69
|
+
/**
|
|
70
|
+
* Detect the best available system clipboard tool.
|
|
71
|
+
* Returns "wl-copy" (Wayland), "xclip" (X11), or null (none).
|
|
72
|
+
*/
|
|
73
|
+
function detectClipboardTool() {
|
|
74
|
+
const { spawnSync } = require("node:child_process");
|
|
75
|
+
// Wayland first (wl-copy is more modern)
|
|
76
|
+
if (spawnSync("wl-copy", ["--help"], { stdio: "ignore" }).status === 0) {
|
|
77
|
+
return "wl-copy";
|
|
78
|
+
}
|
|
79
|
+
// X11 fallback (xclip)
|
|
80
|
+
if (spawnSync("xclip", ["-help"], { stdio: "ignore" }).status === 0) {
|
|
81
|
+
return "xclip";
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
// ─── Read from system clipboard ───────────────────────────────────────────────
|
|
86
|
+
function readFromSystemClipboard(tool) {
|
|
87
|
+
const { execSync } = require("node:child_process");
|
|
88
|
+
try {
|
|
89
|
+
let cmd;
|
|
90
|
+
if (tool === "wl-copy") {
|
|
91
|
+
cmd = "wl-copy --primary --type text/plain 2>/dev/null || wl-copy 2>/dev/null || true";
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
cmd = "xclip -selection clipboard -o 2>/dev/null || true";
|
|
95
|
+
}
|
|
96
|
+
const content = execSync(cmd, { encoding: "utf8", timeout: 2000 }).trim();
|
|
97
|
+
return content || null;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// ─── Read from Xvfb clipboard (fallback) ──────────────────────────────────────
|
|
69
104
|
function readFromClipboard() {
|
|
70
|
-
// Try
|
|
105
|
+
// 1. Try system clipboard first (xclip/wl-copy - what herdr uses)
|
|
106
|
+
const tool = detectClipboardTool();
|
|
107
|
+
if (tool) {
|
|
108
|
+
const content = readFromSystemClipboard(tool);
|
|
109
|
+
if (content)
|
|
110
|
+
return repairMojibake(content);
|
|
111
|
+
}
|
|
112
|
+
// 2. Try Xvfb xclip (legacy fallback for headless servers)
|
|
71
113
|
try {
|
|
72
114
|
const content = execSync(`"${XCLIP_WRAPPER}" -selection clipboard -o 2>/dev/null || DISPLAY=:99 xclip -selection clipboard -o 2>/dev/null || true`, { encoding: "utf8", timeout: 2000 })
|
|
73
115
|
.trim()
|
|
@@ -79,7 +121,7 @@ function readFromClipboard() {
|
|
|
79
121
|
catch {
|
|
80
122
|
// Fall through
|
|
81
123
|
}
|
|
82
|
-
// Fallback: read bridge file directly
|
|
124
|
+
// 3. Fallback: read bridge file directly
|
|
83
125
|
try {
|
|
84
126
|
if (existsSync(BRIDGE_FILE)) {
|
|
85
127
|
const content = readFileSync(BRIDGE_FILE, "utf8").trim();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copy-sync.js","sourceRoot":"","sources":["../../src/copy-sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,YAAY,IAAI,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAE/E,iFAAiF;AAEjF,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,kBAAkB,CAAC,CAAC;AACxD,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;AAEhE,iFAAiF;AAEjF;;;;;;;;;;;;;;GAcG;AACH,SAAS,UAAU,CAAC,IAAY;IAC/B,qEAAqE;IACrE,4EAA4E;IAC5E,MAAM,IAAI,GAAG,2CAA2C,CAAC;IACzD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAS,cAAc,CAAC,IAAY;IACnC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnC,IAAI,CAAC;QACJ,qEAAqE;QACrE,mEAAmE;QACnE,mEAAmE;QACnE,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACR,oDAAoD;QACpD,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC;AAED,iFAAiF;AAEjF,SAAS,iBAAiB;IACzB,
|
|
1
|
+
{"version":3,"file":"copy-sync.js","sourceRoot":"","sources":["../../src/copy-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export type { ClipboardContent, ClipboardOptions } from "./types.js";
|
|
2
2
|
export * from "./gist-relay.js";
|
|
3
3
|
export { registerGithubLoginCommand } from "./github-login.js";
|
|
4
|
+
export { pasteFromBridge, registerPasteShortcut } from "./paste-bridge.js";
|
|
4
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACrE,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACrE,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paste Bridge — prefix+p shortcut for clipboard paste
|
|
3
|
+
*
|
|
4
|
+
* Reads content from the bridge file (~/.herdr-clipboard) and sends it
|
|
5
|
+
* to the terminal's active pane.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Read content from the bridge file.
|
|
9
|
+
* Returns null if the file doesn't exist or is empty.
|
|
10
|
+
*/
|
|
11
|
+
export declare function pasteFromBridge(): string | null;
|
|
12
|
+
type AnyPi = any;
|
|
13
|
+
/**
|
|
14
|
+
* Register prefix+p as the paste shortcut.
|
|
15
|
+
* Reads from bridge file and sends content to terminal.
|
|
16
|
+
*/
|
|
17
|
+
export declare function registerPasteShortcut(pi: AnyPi, Key: AnyPi): void;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=paste-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paste-bridge.d.ts","sourceRoot":"","sources":["../../src/paste-bridge.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAkCH;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,GAAG,IAAI,CAW/C;AAKD,KAAK,KAAK,GAAG,GAAG,CAAC;AAEjB;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,GAAG,IAAI,CAoBjE"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paste Bridge — prefix+p shortcut for clipboard paste
|
|
3
|
+
*
|
|
4
|
+
* Reads content from the bridge file (~/.herdr-clipboard) and sends it
|
|
5
|
+
* to the terminal's active pane.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { homedir } from "node:os";
|
|
10
|
+
// ─── Bridge file path ─────────────────────────────────────────────────────────
|
|
11
|
+
const BRIDGE_FILE = join(homedir(), ".herdr-clipboard");
|
|
12
|
+
// ─── Mojibake repair ──────────────────────────────────────────────────────────
|
|
13
|
+
/**
|
|
14
|
+
* Detect UTF-8 mojibake (double-encoding: UTF-8 → Latin-1 → UTF-8).
|
|
15
|
+
*/
|
|
16
|
+
function isMojibake(text) {
|
|
17
|
+
const moji = /[\u00e2\u00c2\u00e3\u00c3][\u0080-\u00ff]/;
|
|
18
|
+
return moji.test(text);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Repair UTF-8 mojibake.
|
|
22
|
+
*/
|
|
23
|
+
function repairMojibake(text) {
|
|
24
|
+
if (!isMojibake(text))
|
|
25
|
+
return text;
|
|
26
|
+
try {
|
|
27
|
+
return Buffer.from(text, "latin1").toString("utf8");
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return text;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// ─── Read from bridge ─────────────────────────────────────────────────────────
|
|
34
|
+
/**
|
|
35
|
+
* Read content from the bridge file.
|
|
36
|
+
* Returns null if the file doesn't exist or is empty.
|
|
37
|
+
*/
|
|
38
|
+
export function pasteFromBridge() {
|
|
39
|
+
try {
|
|
40
|
+
if (!existsSync(BRIDGE_FILE)) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const content = readFileSync(BRIDGE_FILE, "utf8").trim();
|
|
44
|
+
if (!content)
|
|
45
|
+
return null;
|
|
46
|
+
return repairMojibake(content);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Register prefix+p as the paste shortcut.
|
|
54
|
+
* Reads from bridge file and sends content to terminal.
|
|
55
|
+
*/
|
|
56
|
+
export function registerPasteShortcut(pi, Key) {
|
|
57
|
+
try {
|
|
58
|
+
pi.registerShortcut(Key.prefix("p"), {
|
|
59
|
+
description: "Paste from clipboard bridge",
|
|
60
|
+
handler: async (rawCtx) => {
|
|
61
|
+
const content = pasteFromBridge();
|
|
62
|
+
if (!content) {
|
|
63
|
+
rawCtx.ui.notify("Clipboard bridge is empty", "warning");
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
// Send content to terminal input
|
|
67
|
+
// The ctx.sendKeys approach depends on the runtime API
|
|
68
|
+
// For now, notify success - actual paste to terminal handled by runtime
|
|
69
|
+
rawCtx.ui.notify(`Pasting ${content.length} chars from bridge`, "info");
|
|
70
|
+
// TODO: Send keys to terminal pane when runtime API is available
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
console.error("[paste-bridge] Failed to register shortcut:", err);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=paste-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paste-bridge.js","sourceRoot":"","sources":["../../src/paste-bridge.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,iFAAiF;AAEjF,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,kBAAkB,CAAC,CAAC;AAExD,iFAAiF;AAEjF;;GAEG;AACH,SAAS,UAAU,CAAC,IAAY;IAC/B,MAAM,IAAI,GAAG,2CAA2C,CAAC;IACzD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,IAAY;IACnC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,CAAC;QACJ,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC;AAED,iFAAiF;AAEjF;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC9B,IAAI,CAAC;QACJ,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC;QACb,CAAC;QACD,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QACzD,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC1B,OAAO,cAAc,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC;AAOD;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,EAAS,EAAE,GAAU;IAC1D,IAAI,CAAC;QACJ,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;YACpC,WAAW,EAAE,6BAA6B;YAC1C,OAAO,EAAE,KAAK,EAAE,MAAa,EAAE,EAAE;gBAChC,MAAM,OAAO,GAAG,eAAe,EAAE,CAAC;gBAClC,IAAI,CAAC,OAAO,EAAE,CAAC;oBACd,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,2BAA2B,EAAE,SAAS,CAAC,CAAC;oBACzD,OAAO;gBACR,CAAC;gBACD,iCAAiC;gBACjC,uDAAuD;gBACvD,wEAAwE;gBACxE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,OAAO,CAAC,MAAM,oBAAoB,EAAE,MAAM,CAAC,CAAC;gBACxE,iEAAiE;YAClE,CAAC;SACD,CAAC,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,KAAK,CAAC,6CAA6C,EAAE,GAAG,CAAC,CAAC;IACnE,CAAC;AACF,CAAC"}
|
|
@@ -71,10 +71,59 @@ function repairMojibake(text: string): string {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
// ───
|
|
74
|
+
// ─── Detect clipboard tool ──────────────────────────────────────────────────
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Detect the best available system clipboard tool.
|
|
78
|
+
* Returns "wl-copy" (Wayland), "xclip" (X11), or null (none).
|
|
79
|
+
*/
|
|
80
|
+
function detectClipboardTool(): string | null {
|
|
81
|
+
const { spawnSync } = require("node:child_process");
|
|
82
|
+
|
|
83
|
+
// Wayland first (wl-copy is more modern)
|
|
84
|
+
if (spawnSync("wl-copy", ["--help"], { stdio: "ignore" }).status === 0) {
|
|
85
|
+
return "wl-copy";
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// X11 fallback (xclip)
|
|
89
|
+
if (spawnSync("xclip", ["-help"], { stdio: "ignore" }).status === 0) {
|
|
90
|
+
return "xclip";
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ─── Read from system clipboard ───────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
function readFromSystemClipboard(tool: string): string | null {
|
|
99
|
+
const { execSync } = require("node:child_process");
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
let cmd: string;
|
|
103
|
+
if (tool === "wl-copy") {
|
|
104
|
+
cmd = "wl-copy --primary --type text/plain 2>/dev/null || wl-copy 2>/dev/null || true";
|
|
105
|
+
} else {
|
|
106
|
+
cmd = "xclip -selection clipboard -o 2>/dev/null || true";
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const content = execSync(cmd, { encoding: "utf8", timeout: 2000 }).trim();
|
|
110
|
+
return content || null;
|
|
111
|
+
} catch {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ─── Read from Xvfb clipboard (fallback) ──────────────────────────────────────
|
|
75
117
|
|
|
76
118
|
function readFromClipboard(): string | null {
|
|
77
|
-
// Try
|
|
119
|
+
// 1. Try system clipboard first (xclip/wl-copy - what herdr uses)
|
|
120
|
+
const tool = detectClipboardTool();
|
|
121
|
+
if (tool) {
|
|
122
|
+
const content = readFromSystemClipboard(tool);
|
|
123
|
+
if (content) return repairMojibake(content);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// 2. Try Xvfb xclip (legacy fallback for headless servers)
|
|
78
127
|
try {
|
|
79
128
|
const content = execSync(
|
|
80
129
|
`"${XCLIP_WRAPPER}" -selection clipboard -o 2>/dev/null || DISPLAY=:99 xclip -selection clipboard -o 2>/dev/null || true`,
|
|
@@ -89,7 +138,7 @@ function readFromClipboard(): string | null {
|
|
|
89
138
|
// Fall through
|
|
90
139
|
}
|
|
91
140
|
|
|
92
|
-
// Fallback: read bridge file directly
|
|
141
|
+
// 3. Fallback: read bridge file directly
|
|
93
142
|
try {
|
|
94
143
|
if (existsSync(BRIDGE_FILE)) {
|
|
95
144
|
const content = readFileSync(BRIDGE_FILE, "utf8").trim();
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paste Bridge — prefix+p shortcut for clipboard paste
|
|
3
|
+
*
|
|
4
|
+
* Reads content from the bridge file (~/.herdr-clipboard) and sends it
|
|
5
|
+
* to the terminal's active pane.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { homedir } from "node:os";
|
|
11
|
+
|
|
12
|
+
// ─── Bridge file path ─────────────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
const BRIDGE_FILE = join(homedir(), ".herdr-clipboard");
|
|
15
|
+
|
|
16
|
+
// ─── Mojibake repair ──────────────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Detect UTF-8 mojibake (double-encoding: UTF-8 → Latin-1 → UTF-8).
|
|
20
|
+
*/
|
|
21
|
+
function isMojibake(text: string): boolean {
|
|
22
|
+
const moji = /[\u00e2\u00c2\u00e3\u00c3][\u0080-\u00ff]/;
|
|
23
|
+
return moji.test(text);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Repair UTF-8 mojibake.
|
|
28
|
+
*/
|
|
29
|
+
function repairMojibake(text: string): string {
|
|
30
|
+
if (!isMojibake(text)) return text;
|
|
31
|
+
try {
|
|
32
|
+
return Buffer.from(text, "latin1").toString("utf8");
|
|
33
|
+
} catch {
|
|
34
|
+
return text;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ─── Read from bridge ─────────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Read content from the bridge file.
|
|
42
|
+
* Returns null if the file doesn't exist or is empty.
|
|
43
|
+
*/
|
|
44
|
+
export function pasteFromBridge(): string | null {
|
|
45
|
+
try {
|
|
46
|
+
if (!existsSync(BRIDGE_FILE)) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
const content = readFileSync(BRIDGE_FILE, "utf8").trim();
|
|
50
|
+
if (!content) return null;
|
|
51
|
+
return repairMojibake(content);
|
|
52
|
+
} catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ─── Register shortcut ────────────────────────────────────────────────────────
|
|
58
|
+
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
60
|
+
type AnyPi = any;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Register prefix+p as the paste shortcut.
|
|
64
|
+
* Reads from bridge file and sends content to terminal.
|
|
65
|
+
*/
|
|
66
|
+
export function registerPasteShortcut(pi: AnyPi, Key: AnyPi): void {
|
|
67
|
+
try {
|
|
68
|
+
pi.registerShortcut(Key.prefix("p"), {
|
|
69
|
+
description: "Paste from clipboard bridge",
|
|
70
|
+
handler: async (rawCtx: AnyPi) => {
|
|
71
|
+
const content = pasteFromBridge();
|
|
72
|
+
if (!content) {
|
|
73
|
+
rawCtx.ui.notify("Clipboard bridge is empty", "warning");
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
// Send content to terminal input
|
|
77
|
+
// The ctx.sendKeys approach depends on the runtime API
|
|
78
|
+
// For now, notify success - actual paste to terminal handled by runtime
|
|
79
|
+
rawCtx.ui.notify(`Pasting ${content.length} chars from bridge`, "info");
|
|
80
|
+
// TODO: Send keys to terminal pane when runtime API is available
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
} catch (err) {
|
|
84
|
+
console.error("[paste-bridge] Failed to register shortcut:", err);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clipboard Bridge Plugin — Main Entry
|
|
3
|
+
*
|
|
4
|
+
* Provides clipboard bridge functionality as a pi plugin.
|
|
5
|
+
* Integrates paste-from-bridge and paste shortcut registration.
|
|
6
|
+
*/
|
|
7
|
+
import type { FrameworkExtension, ToolExtension } from "@pi/framework-plugin-sdk";
|
|
8
|
+
export type { ClipboardBridgeConfig } from "./types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Create a clipboard bridge tool plugin.
|
|
11
|
+
* Provides paste-from-bridge functionality.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createClipboardBridgeTool(): ToolExtension;
|
|
14
|
+
/**
|
|
15
|
+
* Create a clipboard bridge framework extension.
|
|
16
|
+
* For framework detection compatibility.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createClipboardBridgePlugin(): FrameworkExtension;
|
|
19
|
+
/**
|
|
20
|
+
* Register the paste shortcut with pi runtime.
|
|
21
|
+
* Call this during plugin activation.
|
|
22
|
+
*/
|
|
23
|
+
export declare function registerPasteShortcutHandler(pi: unknown, Key: unknown): void;
|
|
24
|
+
/**
|
|
25
|
+
* Default plugin export.
|
|
26
|
+
*/
|
|
27
|
+
export default createClipboardBridgeTool;
|
|
28
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAGlF,YAAY,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAExD;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,aAAa,CAqBzD;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,IAAI,kBAAkB,CAahE;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAC3C,EAAE,EAAE,OAAO,EACX,GAAG,EAAE,OAAO,GACV,IAAI,CAGN;AAED;;GAEG;eACY,yBAAyB"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clipboard Bridge Plugin — Main Entry
|
|
3
|
+
*
|
|
4
|
+
* Provides clipboard bridge functionality as a pi plugin.
|
|
5
|
+
* Integrates paste-from-bridge and paste shortcut registration.
|
|
6
|
+
*/
|
|
7
|
+
import { pasteFromBridge, registerPasteShortcut } from "@pi/clipboard";
|
|
8
|
+
/**
|
|
9
|
+
* Create a clipboard bridge tool plugin.
|
|
10
|
+
* Provides paste-from-bridge functionality.
|
|
11
|
+
*/
|
|
12
|
+
export function createClipboardBridgeTool() {
|
|
13
|
+
return {
|
|
14
|
+
capability: "tool",
|
|
15
|
+
name: "Clipboard Bridge",
|
|
16
|
+
tools: [
|
|
17
|
+
{
|
|
18
|
+
name: "paste-from-bridge",
|
|
19
|
+
description: "Read content from the clipboard bridge file (~/.herdr-clipboard)",
|
|
20
|
+
parameters: {
|
|
21
|
+
type: "object",
|
|
22
|
+
properties: {},
|
|
23
|
+
required: [],
|
|
24
|
+
},
|
|
25
|
+
execute: async () => {
|
|
26
|
+
const content = pasteFromBridge();
|
|
27
|
+
return { content };
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
config: {},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Create a clipboard bridge framework extension.
|
|
36
|
+
* For framework detection compatibility.
|
|
37
|
+
*/
|
|
38
|
+
export function createClipboardBridgePlugin() {
|
|
39
|
+
return {
|
|
40
|
+
capability: "framework",
|
|
41
|
+
name: "Clipboard Bridge Plugin",
|
|
42
|
+
detector: {
|
|
43
|
+
detect: async () => {
|
|
44
|
+
// This plugin doesn't detect frameworks, it's a utility plugin
|
|
45
|
+
return false;
|
|
46
|
+
},
|
|
47
|
+
signals: [],
|
|
48
|
+
},
|
|
49
|
+
config: {},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Register the paste shortcut with pi runtime.
|
|
54
|
+
* Call this during plugin activation.
|
|
55
|
+
*/
|
|
56
|
+
export function registerPasteShortcutHandler(pi, Key) {
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
58
|
+
registerPasteShortcut(pi, Key);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Default plugin export.
|
|
62
|
+
*/
|
|
63
|
+
export default createClipboardBridgeTool;
|
|
64
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAIvE;;;GAGG;AACH,MAAM,UAAU,yBAAyB;IACxC,OAAO;QACN,UAAU,EAAE,MAAM;QAClB,IAAI,EAAE,kBAAkB;QACxB,KAAK,EAAE;YACN;gBACC,IAAI,EAAE,mBAAmB;gBACzB,WAAW,EAAE,kEAAkE;gBAC/E,UAAU,EAAE;oBACX,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE,EAAE;oBACd,QAAQ,EAAE,EAAE;iBACZ;gBACD,OAAO,EAAE,KAAK,IAAI,EAAE;oBACnB,MAAM,OAAO,GAAG,eAAe,EAAE,CAAC;oBAClC,OAAO,EAAE,OAAO,EAAE,CAAC;gBACpB,CAAC;aACD;SACD;QACD,MAAM,EAAE,EAAE;KACV,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,2BAA2B;IAC1C,OAAO;QACN,UAAU,EAAE,WAAW;QACvB,IAAI,EAAE,yBAAyB;QAC/B,QAAQ,EAAE;YACT,MAAM,EAAE,KAAK,IAAI,EAAE;gBAClB,+DAA+D;gBAC/D,OAAO,KAAK,CAAC;YACd,CAAC;YACD,OAAO,EAAE,EAAE;SACX;QACD,MAAM,EAAE,EAAE;KACV,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,4BAA4B,CAC3C,EAAW,EACX,GAAY;IAEZ,8DAA8D;IAC9D,qBAAqB,CAAC,EAAS,EAAE,GAAU,CAAC,CAAC;AAC9C,CAAC;AAED;;GAEG;AACH,eAAe,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clipboard Bridge Plugin — Types
|
|
3
|
+
*/
|
|
4
|
+
import type { ToolExtension } from "@pi/framework-plugin-sdk";
|
|
5
|
+
export interface ClipboardBridgeConfig {
|
|
6
|
+
/** Enable the paste shortcut (default: true) */
|
|
7
|
+
enablePasteShortcut?: boolean;
|
|
8
|
+
/** Bridge file path (default: ~/.herdr-clipboard) */
|
|
9
|
+
bridgePath?: string;
|
|
10
|
+
/** Auto-sync to clipboard (default: true) */
|
|
11
|
+
autoSync?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface ClipboardBridgeTool extends ToolExtension {
|
|
14
|
+
capability: "tool";
|
|
15
|
+
name: "Clipboard Bridge";
|
|
16
|
+
tools: {
|
|
17
|
+
name: "paste-from-bridge";
|
|
18
|
+
description: "Read content from the clipboard bridge file and return it";
|
|
19
|
+
parameters: {
|
|
20
|
+
type: "object";
|
|
21
|
+
properties: {};
|
|
22
|
+
required: [];
|
|
23
|
+
};
|
|
24
|
+
execute: () => Promise<{
|
|
25
|
+
content: string | null;
|
|
26
|
+
}>;
|
|
27
|
+
}[];
|
|
28
|
+
config: ClipboardBridgeConfig;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,MAAM,WAAW,qBAAqB;IACrC,gDAAgD;IAChD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACzD,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,kBAAkB,CAAC;IACzB,KAAK,EAAE;QACN,IAAI,EAAE,mBAAmB,CAAC;QAC1B,WAAW,EAAE,2DAA2D,CAAC;QACzE,UAAU,EAAE;YACX,IAAI,EAAE,QAAQ,CAAC;YACf,UAAU,EAAE,EAAE,CAAC;YACf,QAAQ,EAAE,EAAE,CAAC;SACb,CAAC;QACF,OAAO,EAAE,MAAM,OAAO,CAAC;YAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;SAAE,CAAC,CAAC;KACnD,EAAE,CAAC;IACJ,MAAM,EAAE,qBAAqB,CAAC;CAC9B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|