opencode-quick-links 0.1.1 → 1.0.1
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 +15 -12
- package/dist/tui.d.ts +2 -4
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +59 -62
- package/dist/tui.js.map +1 -1
- package/package.json +9 -10
- package/tui.js +1 -0
package/README.md
CHANGED
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
OpenCode TUI plugin for searching and opening links from the active conversation.
|
|
4
4
|
|
|
5
|
+
Requires OpenCode V2 (beta).
|
|
6
|
+
|
|
5
7
|
## Install
|
|
6
8
|
|
|
7
|
-
Add the package to your
|
|
9
|
+
Add the package to your global `~/.config/opencode/cli.json`:
|
|
8
10
|
|
|
9
11
|
```json
|
|
10
12
|
{
|
|
11
|
-
"$schema": "https://opencode.ai/
|
|
12
|
-
"
|
|
13
|
+
"$schema": "https://opencode.ai/v2/cli.json",
|
|
14
|
+
"plugins": ["opencode-quick-links"]
|
|
13
15
|
}
|
|
14
16
|
```
|
|
15
17
|
|
|
@@ -23,29 +25,30 @@ The plugin scans the active conversation when you open the dialog. It includes H
|
|
|
23
25
|
|
|
24
26
|
## Configure
|
|
25
27
|
|
|
26
|
-
The plugin does not register a default shortcut. Add one through
|
|
28
|
+
The plugin does not register a default shortcut. Add one through `cli.json` if wanted:
|
|
27
29
|
|
|
28
30
|
```json
|
|
29
31
|
{
|
|
30
|
-
"$schema": "https://opencode.ai/
|
|
31
|
-
"
|
|
32
|
+
"$schema": "https://opencode.ai/v2/cli.json",
|
|
33
|
+
"plugins": ["opencode-quick-links"],
|
|
32
34
|
"keybinds": {
|
|
33
|
-
"quick-links.open": "<leader>
|
|
35
|
+
"quick-links.open": "<leader>o"
|
|
34
36
|
}
|
|
35
37
|
}
|
|
36
38
|
```
|
|
37
39
|
|
|
38
40
|
## Local Development
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
OpenCode auto-loads the local source from `.opencode/plugins/quick-links/` when run from the package directory.
|
|
41
43
|
|
|
42
44
|
From the monorepo root:
|
|
43
45
|
|
|
44
46
|
```sh
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
bun install
|
|
48
|
+
bun run --filter opencode-quick-links build
|
|
49
|
+
bun run --filter opencode-quick-links typecheck
|
|
50
|
+
bun run --filter opencode-quick-links test
|
|
51
|
+
bun run --filter opencode-quick-links smoke
|
|
49
52
|
```
|
|
50
53
|
|
|
51
54
|
Restart OpenCode after changing plugin files or config.
|
package/dist/tui.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
tui: (api: import("@opencode-ai/plugin/tui").TuiPluginApi) => Promise<void>;
|
|
4
|
-
};
|
|
1
|
+
import { Plugin } from "@opencode/plugin/tui";
|
|
2
|
+
declare const _default: Plugin.Definition;
|
|
5
3
|
export default _default;
|
|
6
4
|
//# sourceMappingURL=tui.d.ts.map
|
package/dist/tui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../plugin/src/tui.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../plugin/src/tui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;;AAyD7C,wBAmDE"}
|
package/dist/tui.js
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
+
import { Plugin } from "@opencode/plugin/tui";
|
|
1
2
|
import open from "open";
|
|
2
3
|
const URL_PATTERN = /https?:\/\/[^\s<>"'`]+/gi;
|
|
3
|
-
const TRAILING_PUNCTUATION = /[\],.;:!?}]+$/;
|
|
4
|
-
function
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const closing = (result.match(/\)/g) ?? []).length;
|
|
15
|
-
if (closing <= opening)
|
|
16
|
-
break;
|
|
17
|
-
result = result.slice(0, -1);
|
|
4
|
+
const TRAILING_PUNCTUATION = /[\],.;:!?}*]+$/;
|
|
5
|
+
function trimLink(url) {
|
|
6
|
+
let depth = 0;
|
|
7
|
+
for (let index = 0; index < url.length; index++) {
|
|
8
|
+
if (url[index] === "(")
|
|
9
|
+
depth++;
|
|
10
|
+
if (url[index] !== ")")
|
|
11
|
+
continue;
|
|
12
|
+
if (depth === 0)
|
|
13
|
+
return url.slice(0, index).replace(TRAILING_PUNCTUATION, "");
|
|
14
|
+
depth--;
|
|
18
15
|
}
|
|
19
|
-
return
|
|
16
|
+
return url.replace(TRAILING_PUNCTUATION, "");
|
|
20
17
|
}
|
|
21
18
|
function extractLinks(messages) {
|
|
22
19
|
const seen = new Set();
|
|
23
20
|
const links = [];
|
|
24
21
|
for (const message of messages) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
const texts = message.type === "user"
|
|
23
|
+
? [message.text]
|
|
24
|
+
: message.type === "assistant"
|
|
25
|
+
? message.content.flatMap((part) => part.type === "text" ? [part.text] : [])
|
|
26
|
+
: [];
|
|
27
|
+
for (const text of texts) {
|
|
28
|
+
for (const match of text.matchAll(URL_PATTERN)) {
|
|
29
|
+
const candidate = trimLink(match[0]);
|
|
30
30
|
let url;
|
|
31
31
|
try {
|
|
32
32
|
const parsed = new URL(candidate);
|
|
@@ -46,57 +46,54 @@ function extractLinks(messages) {
|
|
|
46
46
|
}
|
|
47
47
|
return links;
|
|
48
48
|
}
|
|
49
|
-
export default {
|
|
49
|
+
export default Plugin.define({
|
|
50
50
|
id: "opencode-quick-links",
|
|
51
|
-
|
|
51
|
+
setup(ctx) {
|
|
52
52
|
async function showQuickLinks() {
|
|
53
|
-
const
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
const result = await api.client.session.messages({ sessionID });
|
|
59
|
-
if (result.error) {
|
|
60
|
-
api.ui.toast({ variant: "error", message: "Could not load session links." });
|
|
53
|
+
const route = ctx.ui.router.current();
|
|
54
|
+
if (route.type !== "session") {
|
|
55
|
+
ctx.ui.toast.show({ variant: "warning", message: "Start a session." });
|
|
61
56
|
return;
|
|
62
57
|
}
|
|
63
|
-
|
|
58
|
+
await ctx.data.session.message.sync(route.sessionID);
|
|
59
|
+
const links = extractLinks(ctx.data.session.message.list(route.sessionID));
|
|
64
60
|
if (links.length === 0) {
|
|
65
|
-
|
|
61
|
+
ctx.ui.toast.show({ variant: "info", message: "No links found in this session." });
|
|
66
62
|
return;
|
|
67
63
|
}
|
|
68
|
-
|
|
64
|
+
const url = await ctx.ui.dialog.select({
|
|
69
65
|
title: "Quick Links",
|
|
70
|
-
placeholder: "Search links",
|
|
71
|
-
options: links.map((link) => ({
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
void open(option.value).catch(() => {
|
|
78
|
-
api.ui.toast({ variant: "warning", title: "Could not open browser", message: option.value });
|
|
79
|
-
});
|
|
80
|
-
},
|
|
81
|
-
}));
|
|
82
|
-
}
|
|
83
|
-
function runQuickLinks() {
|
|
84
|
-
void showQuickLinks().catch(() => {
|
|
85
|
-
api.ui.toast({ variant: "error", message: "Could not load session links." });
|
|
66
|
+
placeholder: "Search links in the conversation",
|
|
67
|
+
options: links.map((link) => ({ title: link.url.replace(/^https?:\/\//, ""), value: link.url })),
|
|
68
|
+
});
|
|
69
|
+
if (!url)
|
|
70
|
+
return;
|
|
71
|
+
await open(url).catch(() => {
|
|
72
|
+
ctx.ui.toast.show({ variant: "warning", title: "Could not open browser", message: url });
|
|
86
73
|
});
|
|
87
74
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
75
|
+
return ctx.ui.slot({
|
|
76
|
+
append: "app",
|
|
77
|
+
render() {
|
|
78
|
+
ctx.keymap.layer(() => ({
|
|
79
|
+
mode: "global",
|
|
80
|
+
commands: [
|
|
81
|
+
{
|
|
82
|
+
id: "quick-links.open",
|
|
83
|
+
title: "Open session links",
|
|
84
|
+
group: "Plugin",
|
|
85
|
+
palette: true,
|
|
86
|
+
slash: { name: "links" },
|
|
87
|
+
run: () => showQuickLinks().catch(() => {
|
|
88
|
+
ctx.ui.toast.show({ variant: "error", message: "Could not load session links." });
|
|
89
|
+
}),
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
bindings: ["quick-links.open"],
|
|
93
|
+
}));
|
|
94
|
+
return null;
|
|
97
95
|
},
|
|
98
|
-
|
|
99
|
-
api.lifecycle.onDispose(dispose);
|
|
96
|
+
});
|
|
100
97
|
},
|
|
101
|
-
};
|
|
98
|
+
});
|
|
102
99
|
//# sourceMappingURL=tui.js.map
|
package/dist/tui.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.js","sourceRoot":"","sources":["../plugin/src/tui.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tui.js","sourceRoot":"","sources":["../plugin/src/tui.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "opencode-quick-links",
|
|
4
|
-
"version": "0.1
|
|
4
|
+
"version": "1.0.1",
|
|
5
5
|
"description": "OpenCode TUI plugin for searching and opening links from the active conversation.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
@@ -13,16 +13,18 @@
|
|
|
13
13
|
},
|
|
14
14
|
"files": [
|
|
15
15
|
"dist",
|
|
16
|
+
"tui.js",
|
|
16
17
|
"README.md",
|
|
17
18
|
"LICENSE"
|
|
18
19
|
],
|
|
19
20
|
"scripts": {
|
|
20
21
|
"build": "tsc -p tsconfig.build.json",
|
|
21
22
|
"typecheck": "tsc --noEmit",
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
23
|
+
"test": "bun test",
|
|
24
|
+
"smoke": "bun -e \"import('./dist/tui.js').then((m) => { if (!m.default?.id || typeof m.default.setup !== 'function') throw new Error('missing V2 CLI plugin export') })\"",
|
|
25
|
+
"pack:dry-run": "bun pm pack --dry-run",
|
|
26
|
+
"prepack": "bun run build && bun run smoke",
|
|
27
|
+
"prepublishOnly": "bun run prepack && bun run typecheck"
|
|
26
28
|
},
|
|
27
29
|
"keywords": [
|
|
28
30
|
"opencode",
|
|
@@ -48,17 +50,14 @@
|
|
|
48
50
|
"access": "public",
|
|
49
51
|
"provenance": true
|
|
50
52
|
},
|
|
51
|
-
"engines": {
|
|
52
|
-
"opencode": ">=1.15.0"
|
|
53
|
-
},
|
|
54
53
|
"dependencies": {
|
|
54
|
+
"@opencode/plugin": "0.0.0-beta-19296",
|
|
55
55
|
"open": "^10.1.2"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"
|
|
58
|
+
"solid-js": ">=1.9.0"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@opencode-ai/plugin": "^1.15.1",
|
|
62
61
|
"typescript": "^5.9.3"
|
|
63
62
|
}
|
|
64
63
|
}
|
package/tui.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./dist/tui.js"
|