drive-coding 0.17.0
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/LICENSE +21 -0
- package/README.he.md +98 -0
- package/README.md +97 -0
- package/dist/drive-coding.js +126981 -0
- package/frontend-dist/_app/env.js +1 -0
- package/frontend-dist/_app/immutable/assets/0.CU-P_407.css +1 -0
- package/frontend-dist/_app/immutable/assets/2.D9ALpOww.css +1 -0
- package/frontend-dist/_app/immutable/assets/3.E6ED7Syh.css +1 -0
- package/frontend-dist/_app/immutable/assets/5.YWA13FkN.css +1 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_AMS-Regular.BQhdFMY1.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_AMS-Regular.DMm9YOAa.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_AMS-Regular.DRggAlZN.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Caligraphic-Bold.ATXxdsX0.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Caligraphic-Bold.BEiXGLvX.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Caligraphic-Bold.Dq_IR9rO.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Caligraphic-Regular.CTRA-rTL.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Caligraphic-Regular.Di6jR-x-.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Caligraphic-Regular.wX97UBjC.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Fraktur-Bold.BdnERNNW.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Fraktur-Bold.BsDP51OF.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Fraktur-Bold.CL6g_b3V.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Fraktur-Regular.CB_wures.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Fraktur-Regular.CTYiF6lA.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Fraktur-Regular.Dxdc4cR9.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Main-Bold.Cx986IdX.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Main-Bold.Jm3AIy58.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Main-Bold.waoOVXN0.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Main-BoldItalic.DxDJ3AOS.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Main-BoldItalic.DzxPMmG6.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Main-BoldItalic.SpSLRI95.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Main-Italic.3WenGoN9.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Main-Italic.BMLOBm91.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Main-Italic.NWA7e6Wa.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Main-Regular.B22Nviop.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Main-Regular.Dr94JaBh.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Main-Regular.ypZvNtVU.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Math-BoldItalic.B3XSjfu4.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Math-BoldItalic.CZnvNsCZ.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Math-BoldItalic.iY-2wyZ7.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Math-Italic.DA0__PXp.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Math-Italic.flOr_0UB.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Math-Italic.t53AETM-.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_SansSerif-Bold.CFMepnvq.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_SansSerif-Bold.D1sUS0GD.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_SansSerif-Bold.DbIhKOiC.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_SansSerif-Italic.C3H0VqGB.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_SansSerif-Italic.DN2j7dab.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_SansSerif-Italic.YYjJ1zSn.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_SansSerif-Regular.BNo7hRIc.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_SansSerif-Regular.CS6fqUqJ.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_SansSerif-Regular.DDBCnlJ7.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Script-Regular.C5JkGWo-.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Script-Regular.D3wIWfF6.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Script-Regular.D5yQViql.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Size1-Regular.C195tn64.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Size1-Regular.Dbsnue_I.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Size1-Regular.mCD8mA8B.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Size2-Regular.B7gKUWhC.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Size2-Regular.Dy4dx90m.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Size2-Regular.oD1tc_U0.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Size3-Regular.CTq5MqoE.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Size3-Regular.DgpXs0kz.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Size4-Regular.BF-4gkZK.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Size4-Regular.DWFBv043.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Size4-Regular.Dl5lxZxV.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Typewriter-Regular.C0xS9mPB.woff +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Typewriter-Regular.CO6r4hn1.woff2 +0 -0
- package/frontend-dist/_app/immutable/assets/KaTeX_Typewriter-Regular.D3Ib7_Hf.ttf +0 -0
- package/frontend-dist/_app/immutable/assets/LoadingModal.DNP0Snt_.css +1 -0
- package/frontend-dist/_app/immutable/assets/ort-wasm-simd-threaded.jsep.CyqnNavA.wasm +0 -0
- package/frontend-dist/_app/immutable/chunks/6wE5kWJZ.js +1 -0
- package/frontend-dist/_app/immutable/chunks/BQWUQCb9.js +1 -0
- package/frontend-dist/_app/immutable/chunks/Ba9FG7d8.js +1 -0
- package/frontend-dist/_app/immutable/chunks/BeCtfktE.js +292 -0
- package/frontend-dist/_app/immutable/chunks/Bg0A44SF.js +1 -0
- package/frontend-dist/_app/immutable/chunks/CKhUHIER.js +1 -0
- package/frontend-dist/_app/immutable/chunks/CeZBaqrV.js +1 -0
- package/frontend-dist/_app/immutable/chunks/CisdKsFD.js +1 -0
- package/frontend-dist/_app/immutable/chunks/CqwDxRdj.js +1 -0
- package/frontend-dist/_app/immutable/chunks/CuPEg3Gz.js +2 -0
- package/frontend-dist/_app/immutable/chunks/CuT6ZSeQ.js +1 -0
- package/frontend-dist/_app/immutable/chunks/DgOhoED9.js +1 -0
- package/frontend-dist/_app/immutable/chunks/DvwKyUJ9.js +1 -0
- package/frontend-dist/_app/immutable/chunks/JqqgS7yq.js +1 -0
- package/frontend-dist/_app/immutable/chunks/LL0hSDod.js +1 -0
- package/frontend-dist/_app/immutable/chunks/LNR4j0nK.js +7 -0
- package/frontend-dist/_app/immutable/chunks/Oe6tjNLB.js +1 -0
- package/frontend-dist/_app/immutable/chunks/SrseV9LB.js +109 -0
- package/frontend-dist/_app/immutable/chunks/cseHWQnP.js +2 -0
- package/frontend-dist/_app/immutable/chunks/iM4ae5dg.js +1 -0
- package/frontend-dist/_app/immutable/entry/app.Dtr_WULu.js +2 -0
- package/frontend-dist/_app/immutable/entry/start.DNvi4k83.js +1 -0
- package/frontend-dist/_app/immutable/nodes/0.D_beALrd.js +423 -0
- package/frontend-dist/_app/immutable/nodes/1.BDPrJE0T.js +1 -0
- package/frontend-dist/_app/immutable/nodes/2.CFtWC6Ki.js +1 -0
- package/frontend-dist/_app/immutable/nodes/3.D_3DlZlE.js +9 -0
- package/frontend-dist/_app/immutable/nodes/4.xmsDSvqR.js +4 -0
- package/frontend-dist/_app/immutable/nodes/5.CihE_QrF.js +2881 -0
- package/frontend-dist/_app/version.json +1 -0
- package/frontend-dist/icons/apple-touch-icon.png +0 -0
- package/frontend-dist/icons/favicon-64.png +0 -0
- package/frontend-dist/icons/icon-180.png +0 -0
- package/frontend-dist/icons/icon-192.png +0 -0
- package/frontend-dist/icons/icon-512-maskable.png +0 -0
- package/frontend-dist/icons/icon-512.png +0 -0
- package/frontend-dist/index.html +67 -0
- package/frontend-dist/manifest.webmanifest +17 -0
- package/frontend-dist/wake-word/models/alexa_v0.1.onnx +0 -0
- package/frontend-dist/wake-word/models/embedding_model.onnx +0 -0
- package/frontend-dist/wake-word/models/hey_jarvis_v0.1.onnx +0 -0
- package/frontend-dist/wake-word/models/hey_mycroft_v0.1.onnx +0 -0
- package/frontend-dist/wake-word/models/hey_rhasspy_v0.1.onnx +0 -0
- package/frontend-dist/wake-word/models/melspectrogram.onnx +0 -0
- package/frontend-dist/wake-word/models/silero_vad.onnx +0 -0
- package/package.json +42 -0
- package/plugins/README.md +47 -0
- package/plugins/prompt-injector.ts +83 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":"v0.17.0 (cdcc9f2)"}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="he" dir="rtl" data-palette="ember">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
6
|
+
<title>Drive Coding</title>
|
|
7
|
+
|
|
8
|
+
<!-- PWA -->
|
|
9
|
+
<!-- crossorigin=use-credentials: שולח את ה-Access cookie בעת משיכת ה-manifest;
|
|
10
|
+
בלעדיו Cloudflare Access מחזיר redirect ל-login (manifest נמשך אנונימית כברירת מחדל). -->
|
|
11
|
+
<link rel="manifest" href="/manifest.webmanifest" crossorigin="use-credentials" />
|
|
12
|
+
<meta name="theme-color" content="#16130f" />
|
|
13
|
+
<link rel="icon" href="/icons/favicon-64.png" sizes="64x64" type="image/png" />
|
|
14
|
+
<link rel="apple-touch-icon" href="/icons/apple-touch-icon.png" />
|
|
15
|
+
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
16
|
+
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
17
|
+
<meta name="apple-mobile-web-app-title" content="drive-coding" />
|
|
18
|
+
<meta name="mobile-web-app-capable" content="yes" />
|
|
19
|
+
|
|
20
|
+
<link href="/_app/immutable/entry/start.DNvi4k83.js" rel="modulepreload">
|
|
21
|
+
<link href="/_app/immutable/chunks/iM4ae5dg.js" rel="modulepreload">
|
|
22
|
+
<link href="/_app/immutable/chunks/LL0hSDod.js" rel="modulepreload">
|
|
23
|
+
<link href="/_app/immutable/entry/app.Dtr_WULu.js" rel="modulepreload">
|
|
24
|
+
<link href="/_app/immutable/chunks/CuPEg3Gz.js" rel="modulepreload">
|
|
25
|
+
<link href="/_app/immutable/chunks/DgOhoED9.js" rel="modulepreload">
|
|
26
|
+
<link href="/_app/immutable/chunks/6wE5kWJZ.js" rel="modulepreload">
|
|
27
|
+
<link href="/_app/immutable/chunks/CKhUHIER.js" rel="modulepreload">
|
|
28
|
+
<link href="/_app/immutable/chunks/CisdKsFD.js" rel="modulepreload">
|
|
29
|
+
<link href="/_app/immutable/chunks/Ba9FG7d8.js" rel="modulepreload">
|
|
30
|
+
<link href="/_app/immutable/nodes/0.D_beALrd.js" rel="modulepreload">
|
|
31
|
+
<link href="/_app/immutable/chunks/BQWUQCb9.js" rel="modulepreload">
|
|
32
|
+
<link href="/_app/immutable/chunks/DvwKyUJ9.js" rel="modulepreload">
|
|
33
|
+
<link href="/_app/immutable/chunks/CeZBaqrV.js" rel="modulepreload">
|
|
34
|
+
<link href="/_app/immutable/chunks/SrseV9LB.js" rel="modulepreload">
|
|
35
|
+
<link href="/_app/immutable/chunks/CuT6ZSeQ.js" rel="modulepreload">
|
|
36
|
+
<link href="/_app/immutable/chunks/Oe6tjNLB.js" rel="modulepreload">
|
|
37
|
+
<link href="/_app/immutable/chunks/CqwDxRdj.js" rel="modulepreload">
|
|
38
|
+
<link href="/_app/env.js" rel="modulepreload">
|
|
39
|
+
|
|
40
|
+
<link href="/_app/immutable/assets/0.CU-P_407.css" rel="stylesheet">
|
|
41
|
+
</head>
|
|
42
|
+
<body>
|
|
43
|
+
<div style="display: contents">
|
|
44
|
+
<script>
|
|
45
|
+
{
|
|
46
|
+
__sveltekit_mrx7ku = {
|
|
47
|
+
base: "",
|
|
48
|
+
env: null
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const element = document.currentScript.parentElement;
|
|
52
|
+
|
|
53
|
+
import("/_app/env.js").then(({ env }) => {
|
|
54
|
+
__sveltekit_mrx7ku.env = env;
|
|
55
|
+
|
|
56
|
+
Promise.all([
|
|
57
|
+
import("/_app/immutable/entry/start.DNvi4k83.js"),
|
|
58
|
+
import("/_app/immutable/entry/app.Dtr_WULu.js")
|
|
59
|
+
]).then(([kit, app]) => {
|
|
60
|
+
kit.start(app, element);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
</script>
|
|
65
|
+
</div>
|
|
66
|
+
</body>
|
|
67
|
+
</html>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "drive-coding",
|
|
3
|
+
"short_name": "drive-coding",
|
|
4
|
+
"description": "Voice-first hands-free interface for ACP CLI agents",
|
|
5
|
+
"lang": "he",
|
|
6
|
+
"dir": "rtl",
|
|
7
|
+
"start_url": "/",
|
|
8
|
+
"scope": "/",
|
|
9
|
+
"display": "standalone",
|
|
10
|
+
"background_color": "#16130f",
|
|
11
|
+
"theme_color": "#16130f",
|
|
12
|
+
"icons": [
|
|
13
|
+
{ "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" },
|
|
14
|
+
{ "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" },
|
|
15
|
+
{ "src": "/icons/icon-512-maskable.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
|
|
16
|
+
]
|
|
17
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "drive-coding",
|
|
3
|
+
"version": "0.17.0",
|
|
4
|
+
"description": "AI-powered coding assistant — single-command server + web UI for ACP coding agents",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"drive-coding": "dist/drive-coding.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist/drive-coding.js",
|
|
12
|
+
"plugins",
|
|
13
|
+
"frontend-dist"
|
|
14
|
+
],
|
|
15
|
+
"keywords": [
|
|
16
|
+
"acp",
|
|
17
|
+
"ai",
|
|
18
|
+
"coding-agent",
|
|
19
|
+
"voice-first",
|
|
20
|
+
"cli",
|
|
21
|
+
"opencode",
|
|
22
|
+
"claude-code",
|
|
23
|
+
"self-hosted"
|
|
24
|
+
],
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/MusiCode1/drive-coding.git"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://github.com/MusiCode1/drive-coding#readme",
|
|
30
|
+
"bugs": "https://github.com/MusiCode1/drive-coding/issues",
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"bundle": "node scripts/build.mjs",
|
|
36
|
+
"prepack": "node scripts/build.mjs"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"pino": "^10.3.1",
|
|
40
|
+
"pino-pretty": "^13.1.3"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Backend Plugins
|
|
2
|
+
|
|
3
|
+
Plugins injected into CLI sub-processes via `OPENCODE_CONFIG_CONTENT`.
|
|
4
|
+
|
|
5
|
+
These files **must stay accessible as separate TS files at runtime** — OpenCode loads
|
|
6
|
+
them directly via `file://` URL using Bun. They are NOT bundled with the backend code.
|
|
7
|
+
|
|
8
|
+
## How it works
|
|
9
|
+
|
|
10
|
+
When spawning an `opencode` sub-process, `packages/backend/src/plugin-config.ts`
|
|
11
|
+
builds a JSON config containing a `file://` URL pointing to the plugin file here
|
|
12
|
+
(plus per-plugin options as a tuple `[url, options]`). That config is passed via
|
|
13
|
+
the `OPENCODE_CONFIG_CONTENT` environment variable.
|
|
14
|
+
|
|
15
|
+
OpenCode merges this config with any existing user config, loads the plugin,
|
|
16
|
+
and fires the `experimental.chat.system.transform` hook before every LLM call.
|
|
17
|
+
|
|
18
|
+
## The `prompt-injector` plugin
|
|
19
|
+
|
|
20
|
+
Generic plugin that appends a system-prompt string (passed via `options.text`)
|
|
21
|
+
to every chat's system prompts. The actual prompt content lives in the backend
|
|
22
|
+
under `src/prompts/` — the plugin is purely the mechanism.
|
|
23
|
+
|
|
24
|
+
This indirection lets us:
|
|
25
|
+
- Update prompt text without restarting the spawned `opencode` process pool
|
|
26
|
+
(it's read at spawn time, but no plugin rebuild needed).
|
|
27
|
+
- Use the same plugin with different prompt profiles in the future (e.g.
|
|
28
|
+
audio-friendly, coding-focused, tutoring) — just pass different `options.text`.
|
|
29
|
+
- Keep the plugin tiny + reusable, separate from the BE's prompt catalog.
|
|
30
|
+
|
|
31
|
+
See slice 11 for the original audio-friendly behavior and slice 14 for the
|
|
32
|
+
generic refactor.
|
|
33
|
+
|
|
34
|
+
## Adding a new plugin
|
|
35
|
+
|
|
36
|
+
1. Create `<name>.ts` in this directory.
|
|
37
|
+
2. Export a `PluginModule` (with `id` + `server`) or a bare `Plugin` function
|
|
38
|
+
(see `@opencode-ai/plugin` types).
|
|
39
|
+
3. Register the file URL in `plugin-config.ts` (as a string for option-less
|
|
40
|
+
plugins, or a `[url, options]` tuple for parameterized ones).
|
|
41
|
+
|
|
42
|
+
## Production notes
|
|
43
|
+
|
|
44
|
+
If voice-acp is ever packaged as a binary, the `plugins/` directory must be
|
|
45
|
+
copied to the output alongside the binary so the `file://` URLs remain valid.
|
|
46
|
+
|
|
47
|
+
See `docs/audio-friendly-prompt-plan.md` §5 for full rationale.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { Hooks, PluginInput, PluginModule } from "@opencode-ai/plugin"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generic prompt-injector plugin.
|
|
5
|
+
*
|
|
6
|
+
* Receives the system-prompt text via plugin options (`options.text`) and
|
|
7
|
+
* appends it to every chat's system prompts (via the
|
|
8
|
+
* `experimental.chat.system.transform` hook).
|
|
9
|
+
*
|
|
10
|
+
* The actual prompt text lives in the backend (`src/prompts/`) and is
|
|
11
|
+
* passed in by `plugin-config.ts` at spawn time. This file is purely the
|
|
12
|
+
* "mechanism" — no hardcoded prompt content.
|
|
13
|
+
*
|
|
14
|
+
* Usage in opencode config:
|
|
15
|
+
* plugin: [["file:///abs/path/prompt-injector.ts", { text: "..." }]]
|
|
16
|
+
*
|
|
17
|
+
* If `options.text` is missing/empty/non-string, the hook is a no-op
|
|
18
|
+
* (defensive — the BE always passes a non-empty string today, but a
|
|
19
|
+
* future caller that forgets the options shouldn't break the agent).
|
|
20
|
+
*
|
|
21
|
+
* Debug option — `options.debugWritePath` (string):
|
|
22
|
+
* If set, the plugin atomically writes the final `output.system` array
|
|
23
|
+
* (as JSON) to this path on every invocation. Useful for verifying that
|
|
24
|
+
* the prompt actually reaches the LLM and seeing what other system
|
|
25
|
+
* prompts opencode is layering on. No-op if unset.
|
|
26
|
+
*/
|
|
27
|
+
const plugin: PluginModule = {
|
|
28
|
+
id: "prompt-injector",
|
|
29
|
+
async server(
|
|
30
|
+
_input: PluginInput,
|
|
31
|
+
options?: Record<string, unknown>,
|
|
32
|
+
): Promise<Hooks> {
|
|
33
|
+
// Commit 3 (windows-adaptation): fallback לenv כשopencode טוען את הפלאגין כ-string-URL
|
|
34
|
+
// ללא options (opencode 1.2.27 — plugin: string[], לא tuple).
|
|
35
|
+
// options.text גובר על env (backwards compat למי שעדיין משתמש ב-tuple בקונפיג ישן).
|
|
36
|
+
const text =
|
|
37
|
+
typeof options?.text === "string"
|
|
38
|
+
? options.text
|
|
39
|
+
: (process.env.PROMPT_INJECTOR_TEXT ?? "")
|
|
40
|
+
const debugWritePath =
|
|
41
|
+
typeof options?.debugWritePath === "string"
|
|
42
|
+
? options.debugWritePath
|
|
43
|
+
: (process.env.PROMPT_INJECTOR_DEBUG_PATH ?? null)
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
"experimental.chat.system.transform": async (_hookInput, output) => {
|
|
47
|
+
if (text.length > 0) {
|
|
48
|
+
output.system.push(text)
|
|
49
|
+
}
|
|
50
|
+
if (debugWritePath) {
|
|
51
|
+
// Dynamic import — keeps node:fs out of the module-load path for
|
|
52
|
+
// environments that don't need debug (smaller blast radius if the
|
|
53
|
+
// plugin ever runs in a context without fs).
|
|
54
|
+
try {
|
|
55
|
+
const { writeFile, rename } = await import("node:fs/promises")
|
|
56
|
+
const payload = JSON.stringify(
|
|
57
|
+
{
|
|
58
|
+
timestamp: new Date().toISOString(),
|
|
59
|
+
systemPromptCount: output.system.length,
|
|
60
|
+
systemPrompts: output.system,
|
|
61
|
+
},
|
|
62
|
+
null,
|
|
63
|
+
2,
|
|
64
|
+
)
|
|
65
|
+
// Atomic: write to .tmp, then rename. Avoids partial reads.
|
|
66
|
+
const tmpPath = `${debugWritePath}.tmp`
|
|
67
|
+
await writeFile(tmpPath, payload, "utf8")
|
|
68
|
+
await rename(tmpPath, debugWritePath)
|
|
69
|
+
} catch (err) {
|
|
70
|
+
// Defensive — debug write failures must not break the chat.
|
|
71
|
+
// eslint-disable-next-line no-console
|
|
72
|
+
console.warn(
|
|
73
|
+
"[prompt-injector] debug write failed:",
|
|
74
|
+
(err as Error).message,
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export default plugin
|