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.
Files changed (117) hide show
  1. package/LICENSE +21 -0
  2. package/README.he.md +98 -0
  3. package/README.md +97 -0
  4. package/dist/drive-coding.js +126981 -0
  5. package/frontend-dist/_app/env.js +1 -0
  6. package/frontend-dist/_app/immutable/assets/0.CU-P_407.css +1 -0
  7. package/frontend-dist/_app/immutable/assets/2.D9ALpOww.css +1 -0
  8. package/frontend-dist/_app/immutable/assets/3.E6ED7Syh.css +1 -0
  9. package/frontend-dist/_app/immutable/assets/5.YWA13FkN.css +1 -0
  10. package/frontend-dist/_app/immutable/assets/KaTeX_AMS-Regular.BQhdFMY1.woff2 +0 -0
  11. package/frontend-dist/_app/immutable/assets/KaTeX_AMS-Regular.DMm9YOAa.woff +0 -0
  12. package/frontend-dist/_app/immutable/assets/KaTeX_AMS-Regular.DRggAlZN.ttf +0 -0
  13. package/frontend-dist/_app/immutable/assets/KaTeX_Caligraphic-Bold.ATXxdsX0.ttf +0 -0
  14. package/frontend-dist/_app/immutable/assets/KaTeX_Caligraphic-Bold.BEiXGLvX.woff +0 -0
  15. package/frontend-dist/_app/immutable/assets/KaTeX_Caligraphic-Bold.Dq_IR9rO.woff2 +0 -0
  16. package/frontend-dist/_app/immutable/assets/KaTeX_Caligraphic-Regular.CTRA-rTL.woff +0 -0
  17. package/frontend-dist/_app/immutable/assets/KaTeX_Caligraphic-Regular.Di6jR-x-.woff2 +0 -0
  18. package/frontend-dist/_app/immutable/assets/KaTeX_Caligraphic-Regular.wX97UBjC.ttf +0 -0
  19. package/frontend-dist/_app/immutable/assets/KaTeX_Fraktur-Bold.BdnERNNW.ttf +0 -0
  20. package/frontend-dist/_app/immutable/assets/KaTeX_Fraktur-Bold.BsDP51OF.woff +0 -0
  21. package/frontend-dist/_app/immutable/assets/KaTeX_Fraktur-Bold.CL6g_b3V.woff2 +0 -0
  22. package/frontend-dist/_app/immutable/assets/KaTeX_Fraktur-Regular.CB_wures.ttf +0 -0
  23. package/frontend-dist/_app/immutable/assets/KaTeX_Fraktur-Regular.CTYiF6lA.woff2 +0 -0
  24. package/frontend-dist/_app/immutable/assets/KaTeX_Fraktur-Regular.Dxdc4cR9.woff +0 -0
  25. package/frontend-dist/_app/immutable/assets/KaTeX_Main-Bold.Cx986IdX.woff2 +0 -0
  26. package/frontend-dist/_app/immutable/assets/KaTeX_Main-Bold.Jm3AIy58.woff +0 -0
  27. package/frontend-dist/_app/immutable/assets/KaTeX_Main-Bold.waoOVXN0.ttf +0 -0
  28. package/frontend-dist/_app/immutable/assets/KaTeX_Main-BoldItalic.DxDJ3AOS.woff2 +0 -0
  29. package/frontend-dist/_app/immutable/assets/KaTeX_Main-BoldItalic.DzxPMmG6.ttf +0 -0
  30. package/frontend-dist/_app/immutable/assets/KaTeX_Main-BoldItalic.SpSLRI95.woff +0 -0
  31. package/frontend-dist/_app/immutable/assets/KaTeX_Main-Italic.3WenGoN9.ttf +0 -0
  32. package/frontend-dist/_app/immutable/assets/KaTeX_Main-Italic.BMLOBm91.woff +0 -0
  33. package/frontend-dist/_app/immutable/assets/KaTeX_Main-Italic.NWA7e6Wa.woff2 +0 -0
  34. package/frontend-dist/_app/immutable/assets/KaTeX_Main-Regular.B22Nviop.woff2 +0 -0
  35. package/frontend-dist/_app/immutable/assets/KaTeX_Main-Regular.Dr94JaBh.woff +0 -0
  36. package/frontend-dist/_app/immutable/assets/KaTeX_Main-Regular.ypZvNtVU.ttf +0 -0
  37. package/frontend-dist/_app/immutable/assets/KaTeX_Math-BoldItalic.B3XSjfu4.ttf +0 -0
  38. package/frontend-dist/_app/immutable/assets/KaTeX_Math-BoldItalic.CZnvNsCZ.woff2 +0 -0
  39. package/frontend-dist/_app/immutable/assets/KaTeX_Math-BoldItalic.iY-2wyZ7.woff +0 -0
  40. package/frontend-dist/_app/immutable/assets/KaTeX_Math-Italic.DA0__PXp.woff +0 -0
  41. package/frontend-dist/_app/immutable/assets/KaTeX_Math-Italic.flOr_0UB.ttf +0 -0
  42. package/frontend-dist/_app/immutable/assets/KaTeX_Math-Italic.t53AETM-.woff2 +0 -0
  43. package/frontend-dist/_app/immutable/assets/KaTeX_SansSerif-Bold.CFMepnvq.ttf +0 -0
  44. package/frontend-dist/_app/immutable/assets/KaTeX_SansSerif-Bold.D1sUS0GD.woff2 +0 -0
  45. package/frontend-dist/_app/immutable/assets/KaTeX_SansSerif-Bold.DbIhKOiC.woff +0 -0
  46. package/frontend-dist/_app/immutable/assets/KaTeX_SansSerif-Italic.C3H0VqGB.woff2 +0 -0
  47. package/frontend-dist/_app/immutable/assets/KaTeX_SansSerif-Italic.DN2j7dab.woff +0 -0
  48. package/frontend-dist/_app/immutable/assets/KaTeX_SansSerif-Italic.YYjJ1zSn.ttf +0 -0
  49. package/frontend-dist/_app/immutable/assets/KaTeX_SansSerif-Regular.BNo7hRIc.ttf +0 -0
  50. package/frontend-dist/_app/immutable/assets/KaTeX_SansSerif-Regular.CS6fqUqJ.woff +0 -0
  51. package/frontend-dist/_app/immutable/assets/KaTeX_SansSerif-Regular.DDBCnlJ7.woff2 +0 -0
  52. package/frontend-dist/_app/immutable/assets/KaTeX_Script-Regular.C5JkGWo-.ttf +0 -0
  53. package/frontend-dist/_app/immutable/assets/KaTeX_Script-Regular.D3wIWfF6.woff2 +0 -0
  54. package/frontend-dist/_app/immutable/assets/KaTeX_Script-Regular.D5yQViql.woff +0 -0
  55. package/frontend-dist/_app/immutable/assets/KaTeX_Size1-Regular.C195tn64.woff +0 -0
  56. package/frontend-dist/_app/immutable/assets/KaTeX_Size1-Regular.Dbsnue_I.ttf +0 -0
  57. package/frontend-dist/_app/immutable/assets/KaTeX_Size1-Regular.mCD8mA8B.woff2 +0 -0
  58. package/frontend-dist/_app/immutable/assets/KaTeX_Size2-Regular.B7gKUWhC.ttf +0 -0
  59. package/frontend-dist/_app/immutable/assets/KaTeX_Size2-Regular.Dy4dx90m.woff2 +0 -0
  60. package/frontend-dist/_app/immutable/assets/KaTeX_Size2-Regular.oD1tc_U0.woff +0 -0
  61. package/frontend-dist/_app/immutable/assets/KaTeX_Size3-Regular.CTq5MqoE.woff +0 -0
  62. package/frontend-dist/_app/immutable/assets/KaTeX_Size3-Regular.DgpXs0kz.ttf +0 -0
  63. package/frontend-dist/_app/immutable/assets/KaTeX_Size4-Regular.BF-4gkZK.woff +0 -0
  64. package/frontend-dist/_app/immutable/assets/KaTeX_Size4-Regular.DWFBv043.ttf +0 -0
  65. package/frontend-dist/_app/immutable/assets/KaTeX_Size4-Regular.Dl5lxZxV.woff2 +0 -0
  66. package/frontend-dist/_app/immutable/assets/KaTeX_Typewriter-Regular.C0xS9mPB.woff +0 -0
  67. package/frontend-dist/_app/immutable/assets/KaTeX_Typewriter-Regular.CO6r4hn1.woff2 +0 -0
  68. package/frontend-dist/_app/immutable/assets/KaTeX_Typewriter-Regular.D3Ib7_Hf.ttf +0 -0
  69. package/frontend-dist/_app/immutable/assets/LoadingModal.DNP0Snt_.css +1 -0
  70. package/frontend-dist/_app/immutable/assets/ort-wasm-simd-threaded.jsep.CyqnNavA.wasm +0 -0
  71. package/frontend-dist/_app/immutable/chunks/6wE5kWJZ.js +1 -0
  72. package/frontend-dist/_app/immutable/chunks/BQWUQCb9.js +1 -0
  73. package/frontend-dist/_app/immutable/chunks/Ba9FG7d8.js +1 -0
  74. package/frontend-dist/_app/immutable/chunks/BeCtfktE.js +292 -0
  75. package/frontend-dist/_app/immutable/chunks/Bg0A44SF.js +1 -0
  76. package/frontend-dist/_app/immutable/chunks/CKhUHIER.js +1 -0
  77. package/frontend-dist/_app/immutable/chunks/CeZBaqrV.js +1 -0
  78. package/frontend-dist/_app/immutable/chunks/CisdKsFD.js +1 -0
  79. package/frontend-dist/_app/immutable/chunks/CqwDxRdj.js +1 -0
  80. package/frontend-dist/_app/immutable/chunks/CuPEg3Gz.js +2 -0
  81. package/frontend-dist/_app/immutable/chunks/CuT6ZSeQ.js +1 -0
  82. package/frontend-dist/_app/immutable/chunks/DgOhoED9.js +1 -0
  83. package/frontend-dist/_app/immutable/chunks/DvwKyUJ9.js +1 -0
  84. package/frontend-dist/_app/immutable/chunks/JqqgS7yq.js +1 -0
  85. package/frontend-dist/_app/immutable/chunks/LL0hSDod.js +1 -0
  86. package/frontend-dist/_app/immutable/chunks/LNR4j0nK.js +7 -0
  87. package/frontend-dist/_app/immutable/chunks/Oe6tjNLB.js +1 -0
  88. package/frontend-dist/_app/immutable/chunks/SrseV9LB.js +109 -0
  89. package/frontend-dist/_app/immutable/chunks/cseHWQnP.js +2 -0
  90. package/frontend-dist/_app/immutable/chunks/iM4ae5dg.js +1 -0
  91. package/frontend-dist/_app/immutable/entry/app.Dtr_WULu.js +2 -0
  92. package/frontend-dist/_app/immutable/entry/start.DNvi4k83.js +1 -0
  93. package/frontend-dist/_app/immutable/nodes/0.D_beALrd.js +423 -0
  94. package/frontend-dist/_app/immutable/nodes/1.BDPrJE0T.js +1 -0
  95. package/frontend-dist/_app/immutable/nodes/2.CFtWC6Ki.js +1 -0
  96. package/frontend-dist/_app/immutable/nodes/3.D_3DlZlE.js +9 -0
  97. package/frontend-dist/_app/immutable/nodes/4.xmsDSvqR.js +4 -0
  98. package/frontend-dist/_app/immutable/nodes/5.CihE_QrF.js +2881 -0
  99. package/frontend-dist/_app/version.json +1 -0
  100. package/frontend-dist/icons/apple-touch-icon.png +0 -0
  101. package/frontend-dist/icons/favicon-64.png +0 -0
  102. package/frontend-dist/icons/icon-180.png +0 -0
  103. package/frontend-dist/icons/icon-192.png +0 -0
  104. package/frontend-dist/icons/icon-512-maskable.png +0 -0
  105. package/frontend-dist/icons/icon-512.png +0 -0
  106. package/frontend-dist/index.html +67 -0
  107. package/frontend-dist/manifest.webmanifest +17 -0
  108. package/frontend-dist/wake-word/models/alexa_v0.1.onnx +0 -0
  109. package/frontend-dist/wake-word/models/embedding_model.onnx +0 -0
  110. package/frontend-dist/wake-word/models/hey_jarvis_v0.1.onnx +0 -0
  111. package/frontend-dist/wake-word/models/hey_mycroft_v0.1.onnx +0 -0
  112. package/frontend-dist/wake-word/models/hey_rhasspy_v0.1.onnx +0 -0
  113. package/frontend-dist/wake-word/models/melspectrogram.onnx +0 -0
  114. package/frontend-dist/wake-word/models/silero_vad.onnx +0 -0
  115. package/package.json +42 -0
  116. package/plugins/README.md +47 -0
  117. package/plugins/prompt-injector.ts +83 -0
@@ -0,0 +1 @@
1
+ {"version":"v0.17.0 (cdcc9f2)"}
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
+ }
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