@symerian/symi 3.0.17 → 3.0.19

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 (259) hide show
  1. package/dist/{audio-preflight-CBDFctZN.js → audio-preflight-BfmZbg4Y.js} +4 -4
  2. package/dist/{audio-preflight-gsZSpG-6.js → audio-preflight-DcuC-liM.js} +4 -4
  3. package/dist/build-info.json +3 -3
  4. package/dist/bundled/boot-md/handler.js +8 -8
  5. package/dist/bundled/session-memory/handler.js +7 -7
  6. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  7. package/dist/{chrome-nPMY1XTJ.js → chrome-Bo7cbvFK.js} +5 -5
  8. package/dist/{chrome-BjVab8gM.js → chrome-DYp18Q0t.js} +5 -5
  9. package/dist/{deliver-D-QFqm31.js → deliver-ChSIbiMM.js} +1 -1
  10. package/dist/{deliver-B4-bcot9.js → deliver-DEgRQM4J.js} +1 -1
  11. package/dist/extensionAPI.js +7 -7
  12. package/dist/{image-CDwtQjmt.js → image-Bx-hvoNJ.js} +1 -1
  13. package/dist/{image-CcS-vzTA.js → image-CQl_mjWk.js} +1 -1
  14. package/dist/llm-slug-generator.js +7 -7
  15. package/dist/{manager-BnEdHzmO.js → manager-D_pn0urG.js} +1 -1
  16. package/dist/{manager-09r0qPze.js → manager-YQxK2t0C.js} +1 -1
  17. package/dist/{pi-embedded-CWsY69-4.js → pi-embedded-CLw_ZzEZ.js} +16 -16
  18. package/dist/{pi-embedded-helpers-BBMy-lqr.js → pi-embedded-helpers-B5I53aw6.js} +4 -4
  19. package/dist/{pi-embedded-helpers-ChEYbgVj.js → pi-embedded-helpers-sUAEIC9X.js} +4 -4
  20. package/dist/plugin-sdk/{accounts-BfyWsC_i.js → accounts-CWFytwbR.js} +3 -3
  21. package/dist/plugin-sdk/{active-listener-DcJW7xAT.js → active-listener-BkZ4jHrL.js} +2 -2
  22. package/dist/plugin-sdk/{agent-scope-ChbGV6of.js → agent-scope-C9gfY_Gk.js} +2 -2
  23. package/dist/plugin-sdk/{audio-preflight-D3GtNLqW.js → audio-preflight-HKbdzXLZ.js} +21 -21
  24. package/dist/plugin-sdk/{bindings-CN2Qmefj.js → bindings-BaKIqPPy.js} +2 -2
  25. package/dist/plugin-sdk/{channel-web-DTyqujjA.js → channel-web-D5nWiTH1.js} +18 -18
  26. package/dist/plugin-sdk/{chrome-BKzAKr3K.js → chrome-klTSnz-9.js} +3 -3
  27. package/dist/plugin-sdk/{chunk-DhDkBujV.js → chunk-BbrYSny_.js} +1 -1
  28. package/dist/plugin-sdk/{command-format-CVrYFyZS.js → command-format-BN6tyZt6.js} +1 -1
  29. package/dist/plugin-sdk/{commands-registry-17yfZkHZ.js → commands-registry-CTzKKtY6.js} +4 -4
  30. package/dist/plugin-sdk/{config-7wk65zKC.js → config-Crv2qEdJ.js} +9 -9
  31. package/dist/plugin-sdk/{consolidate-exbAW0ml.js → consolidate-DT1QH65Q.js} +2 -2
  32. package/dist/plugin-sdk/{deliver-TxAcw7J5.js → deliver-7rOvAlrc.js} +12 -12
  33. package/dist/plugin-sdk/{diagnostic-Debx4frd.js → diagnostic-0nsxhWp7.js} +1 -1
  34. package/dist/plugin-sdk/{fs-safe-wBYbAkJF.js → fs-safe-DfWYBeWF.js} +1 -1
  35. package/dist/plugin-sdk/{gemini-auth-7U2pm2Ky.js → gemini-auth-C0N0_u49.js} +1 -1
  36. package/dist/plugin-sdk/{image-BtDVmYA5.js → image-WOSl2apK.js} +4 -4
  37. package/dist/plugin-sdk/index.js +43 -43
  38. package/dist/plugin-sdk/{ir-CKMvRrGW.js → ir-9J84MTls.js} +4 -4
  39. package/dist/plugin-sdk/{local-roots-c_gaPs01.js → local-roots-OLRDbvyY.js} +3 -3
  40. package/dist/plugin-sdk/{login-DUym1Jy0.js → login-C7x4q0i2.js} +7 -7
  41. package/dist/plugin-sdk/{login-qr-B-WBdvrX.js → login-qr-Dv5_MoAW.js} +9 -9
  42. package/dist/plugin-sdk/{manager-B71SCzos.js → manager-C83tK17x.js} +8 -8
  43. package/dist/plugin-sdk/{manifest-registry-Dnic6Chh.js → manifest-registry-CJMV-PI7.js} +1 -1
  44. package/dist/plugin-sdk/{markdown-tables-Dur7OTlM.js → markdown-tables-DXNKz5y_.js} +1 -1
  45. package/dist/plugin-sdk/{message-channel-BrAhJJV_.js → message-channel-aGy1HbQQ.js} +1 -1
  46. package/dist/plugin-sdk/{model-selection-B9qaVQSJ.js → model-selection-C-3-tpe7.js} +4 -4
  47. package/dist/plugin-sdk/{outbound-DB1wDM8b.js → outbound-DquCeSy5.js} +6 -6
  48. package/dist/plugin-sdk/{pi-auth-json-ZO118hoy.js → pi-auth-json-D9PDCXGn.js} +1 -1
  49. package/dist/plugin-sdk/{pi-embedded-helpers-s_U0Un7j.js → pi-embedded-helpers-D3ygfH7l.js} +16 -16
  50. package/dist/plugin-sdk/{plugins-DF81oSaI.js → plugins-DOwnSg9D.js} +4 -4
  51. package/dist/plugin-sdk/{pw-ai-CTwP02uv.js → pw-ai-rlengLjb.js} +8 -8
  52. package/dist/plugin-sdk/{qmd-manager-CBaSGant.js → qmd-manager-BzxFjRFa.js} +4 -4
  53. package/dist/plugin-sdk/{registry-CZVURNhF.js → registry-5iFfixlB.js} +2 -2
  54. package/dist/plugin-sdk/{replies-hwRbkU3z.js → replies-BXOzO_H5.js} +7 -7
  55. package/dist/plugin-sdk/{reply-prefix-CaXmzZlx.js → reply-prefix-INAKTqCU.js} +1 -1
  56. package/dist/plugin-sdk/{resolve-outbound-target-fxVSOBmk.js → resolve-outbound-target-DvbxHtqp.js} +2 -2
  57. package/dist/plugin-sdk/{resolve-route-ClCyiOeu.js → resolve-route-URXlY3AK.js} +3 -3
  58. package/dist/plugin-sdk/{runner-Cq5jvwQ7.js → runner-Bv0_DWoH.js} +9 -9
  59. package/dist/plugin-sdk/{session-B_TkB65Y.js → session-C3r8l7ou.js} +4 -4
  60. package/dist/plugin-sdk/{skill-commands-0LF9HTGr.js → skill-commands-KjLUGIdZ.js} +5 -5
  61. package/dist/plugin-sdk/{skills-BIT_O7J0.js → skills-BrsD4L5c.js} +7 -7
  62. package/dist/plugin-sdk/{sqlite-Bx5Y5U5X.js → sqlite-CjW7ME1H.js} +1 -1
  63. package/dist/plugin-sdk/{subsystem-CXqYeDy-.js → subsystem-DcOg1xJr.js} +1 -1
  64. package/dist/plugin-sdk/{synthesis-DtsYAj1E.js → synthesis-CY7YAasV.js} +38 -38
  65. package/dist/plugin-sdk/{target-errors-B8mokOeH.js → target-errors-BVWJGWFq.js} +2 -2
  66. package/dist/plugin-sdk/{thinking-Ca0DhqzO.js → thinking-CtsTDPOi.js} +3 -3
  67. package/dist/plugin-sdk/{tokens-CvlONEqh.js → tokens-8lqOTZCB.js} +1 -1
  68. package/dist/plugin-sdk/{tool-images-DpBaWEHT.js → tool-images-Cl_rGIUZ.js} +2 -2
  69. package/dist/plugin-sdk/{tool-loop-detection-BOvUFa0f.js → tool-loop-detection-Da4WUT_P.js} +2 -2
  70. package/dist/plugin-sdk/{unified-runner-CnM7lyNd.js → unified-runner-nwMnsZyj.js} +60 -60
  71. package/dist/plugin-sdk/web-BlweOZDp.js +54 -0
  72. package/dist/plugin-sdk/{whatsapp-actions-CvnfsFJm.js → whatsapp-actions-DpfaGYs7.js} +21 -21
  73. package/dist/{pw-ai-BW8_KeDf.js → pw-ai-BqxJG-Wh.js} +1 -1
  74. package/dist/{pw-ai-j9IE1K0-.js → pw-ai-C-NSGye0.js} +1 -1
  75. package/dist/{runner-8ALr2UII.js → runner-COGFTeDw.js} +1 -1
  76. package/dist/{runner-C4-9kFdR.js → runner-DhCi2lT1.js} +1 -1
  77. package/dist/{synthesis-Cph3LhA1.js → synthesis-CXZu24Vx.js} +7 -7
  78. package/dist/{synthesis-Cus0A2dL.js → synthesis-DrPxcMlQ.js} +7 -7
  79. package/dist/{unified-runner-CX80YMTk.js → unified-runner-iByUazvW.js} +16 -16
  80. package/dist/{web-ChozvJ7I.js → web-EsMQBIYf.js} +7 -7
  81. package/dist/{web-DFlsbXmQ.js → web-PPg5y6xI.js} +7 -7
  82. package/package.json +1 -1
  83. package/dist/plugin-sdk/web-CIPJBHAU.js +0 -54
  84. package/extensions/copilot-proxy/README.md +0 -24
  85. package/extensions/copilot-proxy/index.ts +0 -154
  86. package/extensions/copilot-proxy/node_modules/.bin/symi +0 -21
  87. package/extensions/copilot-proxy/package.json +0 -15
  88. package/extensions/copilot-proxy/symi.plugin.json +0 -9
  89. package/extensions/device-pair/index.ts +0 -642
  90. package/extensions/device-pair/symi.plugin.json +0 -20
  91. package/extensions/diagnostics-otel/index.ts +0 -15
  92. package/extensions/diagnostics-otel/node_modules/.bin/acorn +0 -21
  93. package/extensions/diagnostics-otel/node_modules/.bin/symi +0 -21
  94. package/extensions/diagnostics-otel/package.json +0 -27
  95. package/extensions/diagnostics-otel/src/service.test.ts +0 -290
  96. package/extensions/diagnostics-otel/src/service.ts +0 -666
  97. package/extensions/diagnostics-otel/symi.plugin.json +0 -8
  98. package/extensions/google-antigravity-auth/README.md +0 -24
  99. package/extensions/google-antigravity-auth/index.ts +0 -424
  100. package/extensions/google-antigravity-auth/node_modules/.bin/symi +0 -21
  101. package/extensions/google-antigravity-auth/package.json +0 -15
  102. package/extensions/google-antigravity-auth/symi.plugin.json +0 -9
  103. package/extensions/google-gemini-cli-auth/README.md +0 -35
  104. package/extensions/google-gemini-cli-auth/index.ts +0 -75
  105. package/extensions/google-gemini-cli-auth/node_modules/.bin/symi +0 -21
  106. package/extensions/google-gemini-cli-auth/oauth.test.ts +0 -162
  107. package/extensions/google-gemini-cli-auth/oauth.ts +0 -636
  108. package/extensions/google-gemini-cli-auth/package.json +0 -15
  109. package/extensions/google-gemini-cli-auth/symi.plugin.json +0 -9
  110. package/extensions/learning-loop/index.ts +0 -159
  111. package/extensions/learning-loop/node_modules/.bin/symi +0 -21
  112. package/extensions/learning-loop/package.json +0 -18
  113. package/extensions/learning-loop/src/analytics/gateway-methods.ts +0 -230
  114. package/extensions/learning-loop/src/analytics/metrics-aggregator.ts +0 -153
  115. package/extensions/learning-loop/src/capture/run-tracker.ts +0 -181
  116. package/extensions/learning-loop/src/capture/serializer.ts +0 -74
  117. package/extensions/learning-loop/src/db.ts +0 -583
  118. package/extensions/learning-loop/src/feedback/explicit-feedback.ts +0 -58
  119. package/extensions/learning-loop/src/feedback/implicit-signals.ts +0 -89
  120. package/extensions/learning-loop/src/graph/edge-inference.ts +0 -189
  121. package/extensions/learning-loop/src/graph/graph-retrieval.ts +0 -144
  122. package/extensions/learning-loop/src/graph/graph-store.ts +0 -183
  123. package/extensions/learning-loop/src/hooks.ts +0 -244
  124. package/extensions/learning-loop/src/injection/cache.ts +0 -73
  125. package/extensions/learning-loop/src/injection/context-injector.ts +0 -104
  126. package/extensions/learning-loop/src/injection/prompt-builder.ts +0 -43
  127. package/extensions/learning-loop/src/learning/embedding-bridge.ts +0 -54
  128. package/extensions/learning-loop/src/learning/learning-extractor.ts +0 -217
  129. package/extensions/learning-loop/src/learning/learning-store.ts +0 -158
  130. package/extensions/learning-loop/src/learning/retrieval.ts +0 -87
  131. package/extensions/learning-loop/src/math/confidence-intervals.ts +0 -62
  132. package/extensions/learning-loop/src/math/ewma.ts +0 -51
  133. package/extensions/learning-loop/src/math/weighted-scorer.ts +0 -42
  134. package/extensions/learning-loop/src/schema.ts +0 -176
  135. package/extensions/learning-loop/src/scoring/normalization.ts +0 -32
  136. package/extensions/learning-loop/src/scoring/quality-engine.ts +0 -78
  137. package/extensions/learning-loop/src/scoring/signal-extractors.ts +0 -155
  138. package/extensions/learning-loop/src/test/context-injector.test.ts +0 -142
  139. package/extensions/learning-loop/src/test/fixes.test.ts +0 -1286
  140. package/extensions/learning-loop/src/test/graph.test.ts +0 -711
  141. package/extensions/learning-loop/src/test/integration.test.ts +0 -312
  142. package/extensions/learning-loop/src/test/learning-store.test.ts +0 -191
  143. package/extensions/learning-loop/src/test/math.test.ts +0 -148
  144. package/extensions/learning-loop/src/test/quality-engine.test.ts +0 -231
  145. package/extensions/learning-loop/src/test/run-tracker.test.ts +0 -143
  146. package/extensions/learning-loop/src/types.ts +0 -281
  147. package/extensions/learning-loop/symi.plugin.json +0 -46
  148. package/extensions/llm-task/README.md +0 -97
  149. package/extensions/llm-task/index.ts +0 -6
  150. package/extensions/llm-task/package.json +0 -12
  151. package/extensions/llm-task/src/llm-task-tool.test.ts +0 -138
  152. package/extensions/llm-task/src/llm-task-tool.ts +0 -249
  153. package/extensions/llm-task/symi.plugin.json +0 -21
  154. package/extensions/memory-lancedb/config.ts +0 -161
  155. package/extensions/memory-lancedb/index.test.ts +0 -330
  156. package/extensions/memory-lancedb/index.ts +0 -670
  157. package/extensions/memory-lancedb/node_modules/.bin/arrow2csv +0 -21
  158. package/extensions/memory-lancedb/node_modules/.bin/openai +0 -21
  159. package/extensions/memory-lancedb/node_modules/.bin/symi +0 -21
  160. package/extensions/memory-lancedb/package.json +0 -20
  161. package/extensions/memory-lancedb/symi.plugin.json +0 -71
  162. package/extensions/minimax-portal-auth/README.md +0 -33
  163. package/extensions/minimax-portal-auth/index.ts +0 -161
  164. package/extensions/minimax-portal-auth/node_modules/.bin/symi +0 -21
  165. package/extensions/minimax-portal-auth/oauth.ts +0 -247
  166. package/extensions/minimax-portal-auth/package.json +0 -15
  167. package/extensions/minimax-portal-auth/symi.plugin.json +0 -9
  168. package/extensions/model-equalizer/index.ts +0 -80
  169. package/extensions/model-equalizer/skills/model-equalizer/SKILL.md +0 -58
  170. package/extensions/model-equalizer/src/detection.ts +0 -62
  171. package/extensions/model-equalizer/src/enhancer.ts +0 -63
  172. package/extensions/model-equalizer/src/test/detection.test.ts +0 -218
  173. package/extensions/model-equalizer/src/test/enhancer.test.ts +0 -137
  174. package/extensions/model-equalizer/src/test/integration.test.ts +0 -185
  175. package/extensions/model-equalizer/src/types.ts +0 -24
  176. package/extensions/model-equalizer/symi.plugin.json +0 -12
  177. package/extensions/phone-control/index.ts +0 -421
  178. package/extensions/phone-control/symi.plugin.json +0 -10
  179. package/extensions/pipeline/README.md +0 -75
  180. package/extensions/pipeline/SKILL.md +0 -97
  181. package/extensions/pipeline/index.ts +0 -18
  182. package/extensions/pipeline/package.json +0 -11
  183. package/extensions/pipeline/src/pipeline-tool.test.ts +0 -345
  184. package/extensions/pipeline/src/pipeline-tool.ts +0 -266
  185. package/extensions/pipeline/src/windows-spawn.test.ts +0 -148
  186. package/extensions/pipeline/src/windows-spawn.ts +0 -193
  187. package/extensions/pipeline/symi.plugin.json +0 -10
  188. package/extensions/qwen-portal-auth/README.md +0 -24
  189. package/extensions/qwen-portal-auth/index.ts +0 -134
  190. package/extensions/qwen-portal-auth/oauth.ts +0 -190
  191. package/extensions/qwen-portal-auth/symi.plugin.json +0 -9
  192. package/extensions/talk-voice/index.ts +0 -150
  193. package/extensions/talk-voice/symi.plugin.json +0 -10
  194. package/extensions/thread-ownership/index.test.ts +0 -180
  195. package/extensions/thread-ownership/index.ts +0 -133
  196. package/extensions/thread-ownership/symi.plugin.json +0 -28
  197. package/skills/1password/SKILL.md +0 -71
  198. package/skills/1password/references/cli-examples.md +0 -29
  199. package/skills/1password/references/get-started.md +0 -17
  200. package/skills/apple-notes/SKILL.md +0 -78
  201. package/skills/apple-reminders/SKILL.md +0 -119
  202. package/skills/bear-notes/SKILL.md +0 -108
  203. package/skills/blogwatcher/SKILL.md +0 -70
  204. package/skills/blucli/SKILL.md +0 -48
  205. package/skills/bluebubbles/SKILL.md +0 -132
  206. package/skills/camsnap/SKILL.md +0 -46
  207. package/skills/canvas/SKILL.md +0 -204
  208. package/skills/connect-email/SKILL.md +0 -142
  209. package/skills/document-generation/SKILL.md +0 -83
  210. package/skills/eightctl/SKILL.md +0 -51
  211. package/skills/food-order/SKILL.md +0 -49
  212. package/skills/gemini/SKILL.md +0 -44
  213. package/skills/gh-issues/SKILL.md +0 -865
  214. package/skills/gifgrep/SKILL.md +0 -80
  215. package/skills/github/SKILL.md +0 -164
  216. package/skills/gog/SKILL.md +0 -117
  217. package/skills/goplaces/SKILL.md +0 -53
  218. package/skills/healthcheck/SKILL.md +0 -246
  219. package/skills/himalaya/SKILL.md +0 -258
  220. package/skills/himalaya/references/configuration.md +0 -184
  221. package/skills/himalaya/references/message-composition.md +0 -199
  222. package/skills/imsg/SKILL.md +0 -122
  223. package/skills/long-task/SKILL.md +0 -58
  224. package/skills/long-task/scripts/detach-task.sh +0 -187
  225. package/skills/nano-banana-pro/SKILL.md +0 -59
  226. package/skills/nano-banana-pro/scripts/generate_image.py +0 -184
  227. package/skills/nano-pdf/SKILL.md +0 -39
  228. package/skills/notion/SKILL.md +0 -173
  229. package/skills/obsidian/SKILL.md +0 -82
  230. package/skills/openai-image-gen/SKILL.md +0 -90
  231. package/skills/openai-image-gen/scripts/gen.py +0 -240
  232. package/skills/openai-whisper/SKILL.md +0 -39
  233. package/skills/openai-whisper-api/SKILL.md +0 -53
  234. package/skills/openai-whisper-api/scripts/transcribe.sh +0 -85
  235. package/skills/openhue/SKILL.md +0 -113
  236. package/skills/oracle/SKILL.md +0 -126
  237. package/skills/ordercli/SKILL.md +0 -79
  238. package/skills/peekaboo/SKILL.md +0 -191
  239. package/skills/reactions-extensive/SKILL.md +0 -30
  240. package/skills/reactions-minimal/SKILL.md +0 -31
  241. package/skills/safe-edit/SKILL.md +0 -51
  242. package/skills/sag/SKILL.md +0 -88
  243. package/skills/sherpa-onnx-tts/SKILL.md +0 -104
  244. package/skills/sherpa-onnx-tts/bin/sherpa-onnx-tts +0 -178
  245. package/skills/songsee/SKILL.md +0 -50
  246. package/skills/sonoscli/SKILL.md +0 -66
  247. package/skills/spotify-player/SKILL.md +0 -65
  248. package/skills/symihub/SKILL.md +0 -78
  249. package/skills/things-mac/SKILL.md +0 -87
  250. package/skills/tmux/SKILL.md +0 -153
  251. package/skills/tmux/scripts/find-sessions.sh +0 -112
  252. package/skills/tmux/scripts/wait-for-text.sh +0 -83
  253. package/skills/trello/SKILL.md +0 -96
  254. package/skills/video-frames/SKILL.md +0 -47
  255. package/skills/video-frames/scripts/frame.sh +0 -81
  256. package/skills/voice-call/SKILL.md +0 -46
  257. package/skills/wacli/SKILL.md +0 -73
  258. package/skills/weather/SKILL.md +0 -113
  259. package/skills/xurl/SKILL.md +0 -462
@@ -1,266 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import path from "node:path";
3
- import { Type } from "@sinclair/typebox";
4
- import type { SymiPluginApi } from "../../../src/plugins/types.js";
5
- import { resolveWindowsPipelineSpawn } from "./windows-spawn.js";
6
-
7
- type PipelineEnvelope =
8
- | {
9
- ok: true;
10
- status: "ok" | "needs_approval" | "cancelled";
11
- output: unknown[];
12
- requiresApproval: null | {
13
- type: "approval_request";
14
- prompt: string;
15
- items: unknown[];
16
- resumeToken?: string;
17
- };
18
- }
19
- | {
20
- ok: false;
21
- error: { type?: string; message: string };
22
- };
23
-
24
- function normalizeForCwdSandbox(p: string): string {
25
- const normalized = path.normalize(p);
26
- return process.platform === "win32" ? normalized.toLowerCase() : normalized;
27
- }
28
-
29
- function resolveCwd(cwdRaw: unknown): string {
30
- if (typeof cwdRaw !== "string" || !cwdRaw.trim()) {
31
- return process.cwd();
32
- }
33
- const cwd = cwdRaw.trim();
34
- if (path.isAbsolute(cwd)) {
35
- throw new Error("cwd must be a relative path");
36
- }
37
- const base = process.cwd();
38
- const resolved = path.resolve(base, cwd);
39
-
40
- const rel = path.relative(normalizeForCwdSandbox(base), normalizeForCwdSandbox(resolved));
41
- if (rel === "" || rel === ".") {
42
- return resolved;
43
- }
44
- if (rel.startsWith("..") || path.isAbsolute(rel)) {
45
- throw new Error("cwd must stay within the gateway working directory");
46
- }
47
- return resolved;
48
- }
49
-
50
- async function runPipelineSubprocessOnce(params: {
51
- execPath: string;
52
- argv: string[];
53
- cwd: string;
54
- timeoutMs: number;
55
- maxStdoutBytes: number;
56
- }) {
57
- const { execPath, argv, cwd } = params;
58
- const timeoutMs = Math.max(200, params.timeoutMs);
59
- const maxStdoutBytes = Math.max(1024, params.maxStdoutBytes);
60
-
61
- const env = { ...process.env, LOBSTER_MODE: "tool" } as Record<string, string | undefined>;
62
- const nodeOptions = env.NODE_OPTIONS ?? "";
63
- if (nodeOptions.includes("--inspect")) {
64
- delete env.NODE_OPTIONS;
65
- }
66
- const spawnTarget =
67
- process.platform === "win32"
68
- ? resolveWindowsPipelineSpawn(execPath, argv, env)
69
- : { command: execPath, argv };
70
-
71
- return await new Promise<{ stdout: string }>((resolve, reject) => {
72
- const child = spawn(spawnTarget.command, spawnTarget.argv, {
73
- cwd,
74
- stdio: ["ignore", "pipe", "pipe"],
75
- env,
76
- windowsHide: spawnTarget.windowsHide,
77
- });
78
-
79
- let stdout = "";
80
- let stdoutBytes = 0;
81
- let stderr = "";
82
- let settled = false;
83
-
84
- const settle = (
85
- result: { ok: true; value: { stdout: string } } | { ok: false; error: Error },
86
- ) => {
87
- if (settled) {
88
- return;
89
- }
90
- settled = true;
91
- clearTimeout(timer);
92
- if (result.ok) {
93
- resolve(result.value);
94
- } else {
95
- reject(result.error);
96
- }
97
- };
98
-
99
- const failAndTerminate = (message: string) => {
100
- try {
101
- child.kill("SIGKILL");
102
- } finally {
103
- settle({ ok: false, error: new Error(message) });
104
- }
105
- };
106
-
107
- child.stdout?.setEncoding("utf8");
108
- child.stderr?.setEncoding("utf8");
109
-
110
- child.stdout?.on("data", (chunk) => {
111
- const str = String(chunk);
112
- stdoutBytes += Buffer.byteLength(str, "utf8");
113
- if (stdoutBytes > maxStdoutBytes) {
114
- failAndTerminate("pipeline output exceeded maxStdoutBytes");
115
- return;
116
- }
117
- stdout += str;
118
- });
119
-
120
- child.stderr?.on("data", (chunk) => {
121
- stderr += String(chunk);
122
- });
123
-
124
- const timer = setTimeout(() => {
125
- failAndTerminate("pipeline subprocess timed out");
126
- }, timeoutMs);
127
-
128
- child.once("error", (err) => {
129
- settle({ ok: false, error: err });
130
- });
131
-
132
- child.once("exit", (code) => {
133
- if (code !== 0) {
134
- settle({
135
- ok: false,
136
- error: new Error(`pipeline failed (${code ?? "?"}): ${stderr.trim() || stdout.trim()}`),
137
- });
138
- return;
139
- }
140
- settle({ ok: true, value: { stdout } });
141
- });
142
- });
143
- }
144
-
145
- function parseEnvelope(stdout: string): PipelineEnvelope {
146
- const trimmed = stdout.trim();
147
-
148
- const tryParse = (input: string) => {
149
- try {
150
- return JSON.parse(input) as unknown;
151
- } catch {
152
- return undefined;
153
- }
154
- };
155
-
156
- let parsed: unknown = tryParse(trimmed);
157
-
158
- // Some environments can leak extra stdout (e.g. warnings/logs) before the
159
- // final JSON envelope. Be tolerant and parse the last JSON-looking suffix.
160
- if (parsed === undefined) {
161
- const suffixMatch = trimmed.match(/({[\s\S]*}|\[[\s\S]*])\s*$/);
162
- if (suffixMatch?.[1]) {
163
- parsed = tryParse(suffixMatch[1]);
164
- }
165
- }
166
-
167
- if (parsed === undefined) {
168
- throw new Error("pipeline returned invalid JSON");
169
- }
170
-
171
- if (!parsed || typeof parsed !== "object") {
172
- throw new Error("pipeline returned invalid JSON envelope");
173
- }
174
-
175
- const ok = (parsed as { ok?: unknown }).ok;
176
- if (ok === true || ok === false) {
177
- return parsed as PipelineEnvelope;
178
- }
179
-
180
- throw new Error("pipeline returned invalid JSON envelope");
181
- }
182
-
183
- function buildPipelineArgv(action: string, params: Record<string, unknown>): string[] {
184
- if (action === "run") {
185
- const pipeline = typeof params.pipeline === "string" ? params.pipeline : "";
186
- if (!pipeline.trim()) {
187
- throw new Error("pipeline required");
188
- }
189
- const argv = ["run", "--mode", "tool", pipeline];
190
- const argsJson = typeof params.argsJson === "string" ? params.argsJson : "";
191
- if (argsJson.trim()) {
192
- argv.push("--args-json", argsJson);
193
- }
194
- return argv;
195
- }
196
- if (action === "resume") {
197
- const token = typeof params.token === "string" ? params.token : "";
198
- if (!token.trim()) {
199
- throw new Error("token required");
200
- }
201
- const approve = params.approve;
202
- if (typeof approve !== "boolean") {
203
- throw new Error("approve required");
204
- }
205
- return ["resume", "--token", token, "--approve", approve ? "yes" : "no"];
206
- }
207
- throw new Error(`Unknown action: ${action}`);
208
- }
209
-
210
- export function createPipelineTool(api: SymiPluginApi) {
211
- return {
212
- name: "pipeline",
213
- label: "Pipeline Workflow",
214
- description:
215
- "Run pipelines as a local-first workflow runtime (typed JSON envelope + resumable approvals).",
216
- parameters: Type.Object({
217
- // NOTE: Prefer string enums in tool schemas; some providers reject unions/anyOf.
218
- action: Type.Unsafe<"run" | "resume">({ type: "string", enum: ["run", "resume"] }),
219
- pipeline: Type.Optional(Type.String()),
220
- argsJson: Type.Optional(Type.String()),
221
- token: Type.Optional(Type.String()),
222
- approve: Type.Optional(Type.Boolean()),
223
- cwd: Type.Optional(
224
- Type.String({
225
- description:
226
- "Relative working directory (optional). Must stay within the gateway working directory.",
227
- }),
228
- ),
229
- timeoutMs: Type.Optional(Type.Number()),
230
- maxStdoutBytes: Type.Optional(Type.Number()),
231
- }),
232
- async execute(_id: string, params: Record<string, unknown>) {
233
- const action = typeof params.action === "string" ? params.action.trim() : "";
234
- if (!action) {
235
- throw new Error("action required");
236
- }
237
-
238
- const execPath = "lobster";
239
- const cwd = resolveCwd(params.cwd);
240
- const timeoutMs = typeof params.timeoutMs === "number" ? params.timeoutMs : 20_000;
241
- const maxStdoutBytes =
242
- typeof params.maxStdoutBytes === "number" ? params.maxStdoutBytes : 512_000;
243
-
244
- const argv = buildPipelineArgv(action, params);
245
-
246
- if (api.runtime?.version && api.logger?.debug) {
247
- api.logger.debug(`pipeline plugin runtime=${api.runtime.version}`);
248
- }
249
-
250
- const { stdout } = await runPipelineSubprocessOnce({
251
- execPath,
252
- argv,
253
- cwd,
254
- timeoutMs,
255
- maxStdoutBytes,
256
- });
257
-
258
- const envelope = parseEnvelope(stdout);
259
-
260
- return {
261
- content: [{ type: "text", text: JSON.stringify(envelope, null, 2) }],
262
- details: envelope,
263
- };
264
- },
265
- };
266
- }
@@ -1,148 +0,0 @@
1
- import fs from "node:fs/promises";
2
- import os from "node:os";
3
- import path from "node:path";
4
- import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
- import { resolveWindowsPipelineSpawn } from "./windows-spawn.js";
6
-
7
- function setProcessPlatform(platform: NodeJS.Platform) {
8
- Object.defineProperty(process, "platform", {
9
- value: platform,
10
- configurable: true,
11
- });
12
- }
13
-
14
- describe("resolveWindowsPipelineSpawn", () => {
15
- let tempDir = "";
16
- const originalPlatform = Object.getOwnPropertyDescriptor(process, "platform");
17
- const originalPath = process.env.PATH;
18
- const originalPathAlt = process.env.Path;
19
- const originalPathExt = process.env.PATHEXT;
20
- const originalPathExtAlt = process.env.Pathext;
21
-
22
- beforeEach(async () => {
23
- tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "symi-pipeline-win-spawn-"));
24
- setProcessPlatform("win32");
25
- });
26
-
27
- afterEach(async () => {
28
- if (originalPlatform) {
29
- Object.defineProperty(process, "platform", originalPlatform);
30
- }
31
- if (originalPath === undefined) {
32
- delete process.env.PATH;
33
- } else {
34
- process.env.PATH = originalPath;
35
- }
36
- if (originalPathAlt === undefined) {
37
- delete process.env.Path;
38
- } else {
39
- process.env.Path = originalPathAlt;
40
- }
41
- if (originalPathExt === undefined) {
42
- delete process.env.PATHEXT;
43
- } else {
44
- process.env.PATHEXT = originalPathExt;
45
- }
46
- if (originalPathExtAlt === undefined) {
47
- delete process.env.Pathext;
48
- } else {
49
- process.env.Pathext = originalPathExtAlt;
50
- }
51
- if (tempDir) {
52
- await fs.rm(tempDir, { recursive: true, force: true });
53
- tempDir = "";
54
- }
55
- });
56
-
57
- it("unwraps cmd shim with %dp0% token", async () => {
58
- const scriptPath = path.join(tempDir, "shim-dist", "lobster-cli.cjs");
59
- const shimPath = path.join(tempDir, "shim", "lobster.cmd");
60
- await fs.mkdir(path.dirname(scriptPath), { recursive: true });
61
- await fs.mkdir(path.dirname(shimPath), { recursive: true });
62
- await fs.writeFile(scriptPath, "module.exports = {};\n", "utf8");
63
- await fs.writeFile(
64
- shimPath,
65
- `@echo off\r\n"%dp0%\\..\\shim-dist\\lobster-cli.cjs" %*\r\n`,
66
- "utf8",
67
- );
68
-
69
- const target = resolveWindowsPipelineSpawn(shimPath, ["run", "noop"], process.env);
70
- expect(target.command).toBe(process.execPath);
71
- expect(target.argv).toEqual([scriptPath, "run", "noop"]);
72
- expect(target.windowsHide).toBe(true);
73
- });
74
-
75
- it("unwraps cmd shim with %~dp0% token", async () => {
76
- const scriptPath = path.join(tempDir, "shim-dist", "lobster-cli.cjs");
77
- const shimPath = path.join(tempDir, "shim", "lobster.cmd");
78
- await fs.mkdir(path.dirname(scriptPath), { recursive: true });
79
- await fs.mkdir(path.dirname(shimPath), { recursive: true });
80
- await fs.writeFile(scriptPath, "module.exports = {};\n", "utf8");
81
- await fs.writeFile(
82
- shimPath,
83
- `@echo off\r\n"%~dp0%\\..\\shim-dist\\lobster-cli.cjs" %*\r\n`,
84
- "utf8",
85
- );
86
-
87
- const target = resolveWindowsPipelineSpawn(shimPath, ["run", "noop"], process.env);
88
- expect(target.command).toBe(process.execPath);
89
- expect(target.argv).toEqual([scriptPath, "run", "noop"]);
90
- expect(target.windowsHide).toBe(true);
91
- });
92
-
93
- it("ignores node.exe shim entries and picks pipeline script", async () => {
94
- const shimDir = path.join(tempDir, "shim-with-node");
95
- const scriptPath = path.join(tempDir, "shim-dist-node", "lobster-cli.cjs");
96
- const shimPath = path.join(shimDir, "lobster.cmd");
97
- await fs.mkdir(path.dirname(scriptPath), { recursive: true });
98
- await fs.mkdir(shimDir, { recursive: true });
99
- await fs.writeFile(path.join(shimDir, "node.exe"), "", "utf8");
100
- await fs.writeFile(scriptPath, "module.exports = {};\n", "utf8");
101
- await fs.writeFile(
102
- shimPath,
103
- `@echo off\r\n"%~dp0%\\node.exe" "%~dp0%\\..\\shim-dist-node\\lobster-cli.cjs" %*\r\n`,
104
- "utf8",
105
- );
106
-
107
- const target = resolveWindowsPipelineSpawn(shimPath, ["run", "noop"], process.env);
108
- expect(target.command).toBe(process.execPath);
109
- expect(target.argv).toEqual([scriptPath, "run", "noop"]);
110
- expect(target.windowsHide).toBe(true);
111
- });
112
-
113
- it("resolves pipeline .cmd from PATH and unwraps npm layout shim", async () => {
114
- const binDir = path.join(tempDir, "node_modules", ".bin");
115
- const packageDir = path.join(tempDir, "node_modules", "lobster");
116
- const scriptPath = path.join(packageDir, "dist", "cli.js");
117
- const shimPath = path.join(binDir, "lobster.cmd");
118
- await fs.mkdir(path.dirname(scriptPath), { recursive: true });
119
- await fs.mkdir(binDir, { recursive: true });
120
- await fs.writeFile(shimPath, "@echo off\r\n", "utf8");
121
- await fs.writeFile(
122
- path.join(packageDir, "package.json"),
123
- JSON.stringify({ name: "lobster", version: "0.0.0", bin: { lobster: "dist/cli.js" } }),
124
- "utf8",
125
- );
126
- await fs.writeFile(scriptPath, "module.exports = {};\n", "utf8");
127
-
128
- const env = {
129
- ...process.env,
130
- PATH: `${binDir};${process.env.PATH ?? ""}`,
131
- PATHEXT: ".CMD;.EXE",
132
- };
133
- const target = resolveWindowsPipelineSpawn("lobster", ["run", "noop"], env);
134
- expect(target.command).toBe(process.execPath);
135
- expect(target.argv).toEqual([scriptPath, "run", "noop"]);
136
- expect(target.windowsHide).toBe(true);
137
- });
138
-
139
- it("fails fast when wrapper cannot be resolved without shell execution", async () => {
140
- const badShimPath = path.join(tempDir, "bad-shim", "lobster.cmd");
141
- await fs.mkdir(path.dirname(badShimPath), { recursive: true });
142
- await fs.writeFile(badShimPath, "@echo off\r\nREM no entrypoint\r\n", "utf8");
143
-
144
- expect(() => resolveWindowsPipelineSpawn(badShimPath, ["run", "noop"], process.env)).toThrow(
145
- /without shell execution/,
146
- );
147
- });
148
- });
@@ -1,193 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
-
4
- type SpawnTarget = {
5
- command: string;
6
- argv: string[];
7
- windowsHide?: boolean;
8
- };
9
-
10
- function isFilePath(value: string): boolean {
11
- try {
12
- const stat = fs.statSync(value);
13
- return stat.isFile();
14
- } catch {
15
- return false;
16
- }
17
- }
18
-
19
- function resolveWindowsExecutablePath(execPath: string, env: NodeJS.ProcessEnv): string {
20
- if (execPath.includes("/") || execPath.includes("\\") || path.isAbsolute(execPath)) {
21
- return execPath;
22
- }
23
-
24
- const pathValue = env.PATH ?? env.Path ?? process.env.PATH ?? process.env.Path ?? "";
25
- const pathEntries = pathValue
26
- .split(";")
27
- .map((entry) => entry.trim())
28
- .filter(Boolean);
29
-
30
- const hasExtension = path.extname(execPath).length > 0;
31
- const pathExtRaw =
32
- env.PATHEXT ??
33
- env.Pathext ??
34
- process.env.PATHEXT ??
35
- process.env.Pathext ??
36
- ".EXE;.CMD;.BAT;.COM";
37
- const pathExt = hasExtension
38
- ? [""]
39
- : pathExtRaw
40
- .split(";")
41
- .map((ext) => ext.trim())
42
- .filter(Boolean)
43
- .map((ext) => (ext.startsWith(".") ? ext : `.${ext}`));
44
-
45
- for (const dir of pathEntries) {
46
- for (const ext of pathExt) {
47
- for (const candidateExt of [ext, ext.toLowerCase(), ext.toUpperCase()]) {
48
- const candidate = path.join(dir, `${execPath}${candidateExt}`);
49
- if (isFilePath(candidate)) {
50
- return candidate;
51
- }
52
- }
53
- }
54
- }
55
-
56
- return execPath;
57
- }
58
-
59
- function resolveBinEntry(binField: string | Record<string, string> | undefined): string | null {
60
- if (typeof binField === "string") {
61
- const trimmed = binField.trim();
62
- return trimmed || null;
63
- }
64
- if (!binField || typeof binField !== "object") {
65
- return null;
66
- }
67
-
68
- const preferred = binField.lobster;
69
- if (typeof preferred === "string" && preferred.trim()) {
70
- return preferred.trim();
71
- }
72
-
73
- for (const value of Object.values(binField)) {
74
- if (typeof value === "string" && value.trim()) {
75
- return value.trim();
76
- }
77
- }
78
- return null;
79
- }
80
-
81
- function resolvePipelineScriptFromPackageJson(wrapperPath: string): string | null {
82
- const wrapperDir = path.dirname(wrapperPath);
83
- const packageDirs = [
84
- // Local install: <repo>/node_modules/.bin/lobster.cmd -> ../lobster
85
- path.resolve(wrapperDir, "..", "lobster"),
86
- // Global npm install: <npm-prefix>/lobster.cmd -> ./node_modules/lobster
87
- path.resolve(wrapperDir, "node_modules", "lobster"),
88
- ];
89
-
90
- for (const packageDir of packageDirs) {
91
- const packageJsonPath = path.join(packageDir, "package.json");
92
- if (!isFilePath(packageJsonPath)) {
93
- continue;
94
- }
95
-
96
- try {
97
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")) as {
98
- bin?: string | Record<string, string>;
99
- };
100
- const scriptRel = resolveBinEntry(packageJson.bin);
101
- if (!scriptRel) {
102
- continue;
103
- }
104
- const scriptPath = path.resolve(packageDir, scriptRel);
105
- if (isFilePath(scriptPath)) {
106
- return scriptPath;
107
- }
108
- } catch {
109
- // Ignore malformed package metadata; caller will throw a guided error.
110
- }
111
- }
112
-
113
- return null;
114
- }
115
-
116
- function resolvePipelineScriptFromCmdShim(wrapperPath: string): string | null {
117
- if (!isFilePath(wrapperPath)) {
118
- return null;
119
- }
120
-
121
- try {
122
- const content = fs.readFileSync(wrapperPath, "utf8");
123
- const candidates: string[] = [];
124
- const extractRelativeFromToken = (token: string): string | null => {
125
- const match = token.match(/%~?dp0%\s*[\\/]*(.*)$/i);
126
- if (!match) {
127
- return null;
128
- }
129
- const relative = match[1];
130
- if (!relative) {
131
- return null;
132
- }
133
- return relative;
134
- };
135
-
136
- const matches = content.matchAll(/"([^"\r\n]*)"/g);
137
- for (const match of matches) {
138
- const token = match[1] ?? "";
139
- const relative = extractRelativeFromToken(token);
140
- if (!relative) {
141
- continue;
142
- }
143
-
144
- const normalizedRelative = relative
145
- .trim()
146
- .replace(/[\\/]+/g, path.sep)
147
- .replace(/^[\\/]+/, "");
148
- const candidate = path.resolve(path.dirname(wrapperPath), normalizedRelative);
149
- if (isFilePath(candidate)) {
150
- candidates.push(candidate);
151
- }
152
- }
153
-
154
- const nonNode = candidates.find((candidate) => {
155
- const base = path.basename(candidate).toLowerCase();
156
- return base !== "node.exe" && base !== "node";
157
- });
158
- if (nonNode) {
159
- return nonNode;
160
- }
161
- } catch {
162
- // Ignore unreadable shims; caller will throw a guided error.
163
- }
164
-
165
- return null;
166
- }
167
-
168
- export function resolveWindowsPipelineSpawn(
169
- execPath: string,
170
- argv: string[],
171
- env: NodeJS.ProcessEnv,
172
- ): SpawnTarget {
173
- const resolvedExecPath = resolveWindowsExecutablePath(execPath, env);
174
- const ext = path.extname(resolvedExecPath).toLowerCase();
175
- if (ext !== ".cmd" && ext !== ".bat") {
176
- return { command: resolvedExecPath, argv };
177
- }
178
-
179
- const scriptPath =
180
- resolvePipelineScriptFromCmdShim(resolvedExecPath) ??
181
- resolvePipelineScriptFromPackageJson(resolvedExecPath);
182
- if (!scriptPath) {
183
- throw new Error(
184
- `${path.basename(resolvedExecPath)} wrapper resolved, but no Node entrypoint could be resolved without shell execution. Ensure the pipeline runtime is installed and runnable on PATH (prefer lobster.exe).`,
185
- );
186
- }
187
-
188
- const entryExt = path.extname(scriptPath).toLowerCase();
189
- if (entryExt === ".exe") {
190
- return { command: scriptPath, argv, windowsHide: true };
191
- }
192
- return { command: process.execPath, argv: [scriptPath, ...argv], windowsHide: true };
193
- }
@@ -1,10 +0,0 @@
1
- {
2
- "id": "pipeline",
3
- "name": "Pipeline",
4
- "description": "Typed workflow tool with resumable approvals.",
5
- "configSchema": {
6
- "type": "object",
7
- "additionalProperties": false,
8
- "properties": {}
9
- }
10
- }
@@ -1,24 +0,0 @@
1
- # Qwen OAuth (Symi plugin)
2
-
3
- OAuth provider plugin for **Qwen** (free-tier OAuth).
4
-
5
- ## Enable
6
-
7
- Bundled plugins are disabled by default. Enable this one:
8
-
9
- ```bash
10
- symi plugins enable qwen-portal-auth
11
- ```
12
-
13
- Restart the Gateway after enabling.
14
-
15
- ## Authenticate
16
-
17
- ```bash
18
- symi models auth login --provider qwen-portal --set-default
19
- ```
20
-
21
- ## Notes
22
-
23
- - Qwen OAuth uses a device-code login flow.
24
- - Tokens auto-refresh; re-run login if refresh fails or access is revoked.