vskill 1.0.15 → 1.0.18

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 (220) hide show
  1. package/README.md +84 -9
  2. package/agents.json +3 -1
  3. package/dist/agents/agents-registry.d.ts +69 -3
  4. package/dist/agents/agents-registry.js +203 -0
  5. package/dist/agents/agents-registry.js.map +1 -1
  6. package/dist/api/client.d.ts +85 -0
  7. package/dist/api/client.js +193 -24
  8. package/dist/api/client.js.map +1 -1
  9. package/dist/commands/add-lockfile.d.ts +6 -0
  10. package/dist/commands/add-lockfile.js +10 -0
  11. package/dist/commands/add-lockfile.js.map +1 -1
  12. package/dist/commands/add.d.ts +7 -0
  13. package/dist/commands/add.js +110 -2
  14. package/dist/commands/add.js.map +1 -1
  15. package/dist/commands/auth.d.ts +23 -0
  16. package/dist/commands/auth.js +105 -11
  17. package/dist/commands/auth.js.map +1 -1
  18. package/dist/commands/eval/serve.d.ts +2 -0
  19. package/dist/commands/eval/serve.js +126 -4
  20. package/dist/commands/eval/serve.js.map +1 -1
  21. package/dist/commands/orgs.d.ts +21 -0
  22. package/dist/commands/orgs.js +164 -0
  23. package/dist/commands/orgs.js.map +1 -0
  24. package/dist/commands/skill.js +14 -1
  25. package/dist/commands/skill.js.map +1 -1
  26. package/dist/commands/whoami.d.ts +29 -0
  27. package/dist/commands/whoami.js +119 -0
  28. package/dist/commands/whoami.js.map +1 -0
  29. package/dist/discovery/github-tree.d.ts +23 -3
  30. package/dist/discovery/github-tree.js +172 -24
  31. package/dist/discovery/github-tree.js.map +1 -1
  32. package/dist/eval/anthropic-catalog.js +32 -2
  33. package/dist/eval/anthropic-catalog.js.map +1 -1
  34. package/dist/eval/batch-judge.js +1 -0
  35. package/dist/eval/batch-judge.js.map +1 -1
  36. package/dist/eval/llm.d.ts +1 -1
  37. package/dist/eval/llm.js +104 -2
  38. package/dist/eval/llm.js.map +1 -1
  39. package/dist/eval-server/__tests__/helpers/studio-token-test-helpers.d.ts +2 -0
  40. package/dist/eval-server/__tests__/helpers/studio-token-test-helpers.js +20 -0
  41. package/dist/eval-server/__tests__/helpers/studio-token-test-helpers.js.map +1 -0
  42. package/dist/eval-server/active-tenant-routes.d.ts +15 -0
  43. package/dist/eval-server/active-tenant-routes.js +101 -0
  44. package/dist/eval-server/active-tenant-routes.js.map +1 -0
  45. package/dist/eval-server/api-routes.js +206 -6
  46. package/dist/eval-server/api-routes.js.map +1 -1
  47. package/dist/eval-server/desktop-open-routes.d.ts +8 -0
  48. package/dist/eval-server/desktop-open-routes.js +64 -0
  49. package/dist/eval-server/desktop-open-routes.js.map +1 -0
  50. package/dist/eval-server/eval-server.js +90 -6
  51. package/dist/eval-server/eval-server.js.map +1 -1
  52. package/dist/eval-server/export-skill-routes.d.ts +9 -0
  53. package/dist/eval-server/export-skill-routes.js +81 -0
  54. package/dist/eval-server/export-skill-routes.js.map +1 -0
  55. package/dist/eval-server/git-routes.d.ts +1 -0
  56. package/dist/eval-server/git-routes.js +101 -4
  57. package/dist/eval-server/git-routes.js.map +1 -1
  58. package/dist/eval-server/install-engine-routes.d.ts +3 -16
  59. package/dist/eval-server/install-engine-routes.js +9 -124
  60. package/dist/eval-server/install-engine-routes.js.map +1 -1
  61. package/dist/eval-server/install-jobs.d.ts +41 -0
  62. package/dist/eval-server/install-jobs.js +161 -0
  63. package/dist/eval-server/install-jobs.js.map +1 -0
  64. package/dist/eval-server/install-skill-routes.d.ts +74 -11
  65. package/dist/eval-server/install-skill-routes.js +506 -79
  66. package/dist/eval-server/install-skill-routes.js.map +1 -1
  67. package/dist/eval-server/install-state-routes.d.ts +25 -0
  68. package/dist/eval-server/install-state-routes.js +125 -0
  69. package/dist/eval-server/install-state-routes.js.map +1 -0
  70. package/dist/eval-server/oauth-github-routes.d.ts +2 -0
  71. package/dist/eval-server/oauth-github-routes.js +505 -0
  72. package/dist/eval-server/oauth-github-routes.js.map +1 -0
  73. package/dist/eval-server/platform-proxy.d.ts +17 -1
  74. package/dist/eval-server/platform-proxy.js +125 -13
  75. package/dist/eval-server/platform-proxy.js.map +1 -1
  76. package/dist/eval-server/plugin-cli-routes.js +9 -9
  77. package/dist/eval-server/plugin-cli-routes.js.map +1 -1
  78. package/dist/eval-server/remove-skill-routes.d.ts +18 -0
  79. package/dist/eval-server/remove-skill-routes.js +145 -0
  80. package/dist/eval-server/remove-skill-routes.js.map +1 -0
  81. package/dist/eval-server/router.d.ts +17 -3
  82. package/dist/eval-server/router.js +166 -9
  83. package/dist/eval-server/router.js.map +1 -1
  84. package/dist/eval-server/settings-store.js +1 -1
  85. package/dist/eval-server/settings-store.js.map +1 -1
  86. package/dist/eval-server/supported-agents-routes.d.ts +6 -0
  87. package/dist/eval-server/supported-agents-routes.js +41 -0
  88. package/dist/eval-server/supported-agents-routes.js.map +1 -0
  89. package/dist/eval-server/utils/spawn-env.d.ts +1 -0
  90. package/dist/eval-server/utils/spawn-env.js +47 -0
  91. package/dist/eval-server/utils/spawn-env.js.map +1 -0
  92. package/dist/eval-ui/assets/AdvancedTab-D8zbE5fH.js +1 -0
  93. package/dist/eval-ui/assets/{CreateSkillPage-BmbvQEzE.js → CreateSkillPage-DOBhKdgr.js} +5 -5
  94. package/dist/eval-ui/assets/FindSkillsPalette-CyMmNPr-.js +2 -0
  95. package/dist/eval-ui/assets/GeneralTab-DYR9NWC4.js +1 -0
  96. package/dist/eval-ui/assets/PrivacyTab-CXIqQokl.js +1 -0
  97. package/dist/eval-ui/assets/SearchPaletteCore-Dn5gQJS_.js +14 -0
  98. package/dist/eval-ui/assets/SkillDetailPanel-DTrRnyyJ.js +1 -0
  99. package/dist/eval-ui/assets/UpdateDropdown-Cvr2fe0z.js +1 -0
  100. package/dist/eval-ui/assets/UpdatesTab-DwJIUDPX.js +1 -0
  101. package/dist/eval-ui/assets/core-DZAvsxlC.js +1 -0
  102. package/dist/eval-ui/assets/event-CDYWU2X3.js +1 -0
  103. package/dist/eval-ui/assets/globals-BRZwPAPF.js +49 -0
  104. package/dist/eval-ui/assets/globals-C3oEdsJh.css +1 -0
  105. package/dist/eval-ui/assets/index-D7M0Jdss.js +1 -0
  106. package/dist/eval-ui/assets/lifecycle-DSleOV-l.js +1 -0
  107. package/dist/eval-ui/assets/lifecycle-d1Sm9Hts.css +1 -0
  108. package/dist/eval-ui/assets/main-D2shn1dH.js +87 -0
  109. package/dist/eval-ui/assets/preferences-BHZXB5dL.css +1 -0
  110. package/dist/eval-ui/assets/preferences-BKv6X7fK.js +2 -0
  111. package/dist/eval-ui/assets/useDesktopBridge-DxVWbYqK.js +2 -0
  112. package/dist/eval-ui/index.html +4 -2
  113. package/dist/eval-ui/lifecycle.html +33 -0
  114. package/dist/eval-ui/preferences.html +34 -0
  115. package/dist/index.js +47 -1
  116. package/dist/index.js.map +1 -1
  117. package/dist/installer/bundle-files.d.ts +4 -0
  118. package/dist/installer/bundle-files.js +97 -0
  119. package/dist/installer/bundle-files.js.map +1 -0
  120. package/dist/installer/canonical.d.ts +31 -6
  121. package/dist/installer/canonical.js +50 -23
  122. package/dist/installer/canonical.js.map +1 -1
  123. package/dist/installer/clipboard-export.d.ts +19 -0
  124. package/dist/installer/clipboard-export.js +88 -0
  125. package/dist/installer/clipboard-export.js.map +1 -0
  126. package/dist/installer/frontmatter.js +1 -1
  127. package/dist/installer/frontmatter.js.map +1 -1
  128. package/dist/installer/multi-install.d.ts +43 -0
  129. package/dist/installer/multi-install.js +237 -0
  130. package/dist/installer/multi-install.js.map +1 -0
  131. package/dist/installer/transformers/aider.d.ts +2 -0
  132. package/dist/installer/transformers/aider.js +32 -0
  133. package/dist/installer/transformers/aider.js.map +1 -0
  134. package/dist/installer/transformers/continue-dev.d.ts +2 -0
  135. package/dist/installer/transformers/continue-dev.js +6 -0
  136. package/dist/installer/transformers/continue-dev.js.map +1 -0
  137. package/dist/installer/transformers/cursor.d.ts +2 -0
  138. package/dist/installer/transformers/cursor.js +24 -0
  139. package/dist/installer/transformers/cursor.js.map +1 -0
  140. package/dist/installer/transformers/github-copilot.d.ts +2 -0
  141. package/dist/installer/transformers/github-copilot.js +17 -0
  142. package/dist/installer/transformers/github-copilot.js.map +1 -0
  143. package/dist/installer/transformers/index.d.ts +78 -0
  144. package/dist/installer/transformers/index.js +13 -0
  145. package/dist/installer/transformers/index.js.map +1 -0
  146. package/dist/installer/transformers/junie.d.ts +2 -0
  147. package/dist/installer/transformers/junie.js +6 -0
  148. package/dist/installer/transformers/junie.js.map +1 -0
  149. package/dist/installer/transformers/kiro.d.ts +2 -0
  150. package/dist/installer/transformers/kiro.js +6 -0
  151. package/dist/installer/transformers/kiro.js.map +1 -0
  152. package/dist/installer/transformers/trae.d.ts +2 -0
  153. package/dist/installer/transformers/trae.js +6 -0
  154. package/dist/installer/transformers/trae.js.map +1 -0
  155. package/dist/installer/transformers/windsurf.d.ts +2 -0
  156. package/dist/installer/transformers/windsurf.js +12 -0
  157. package/dist/installer/transformers/windsurf.js.map +1 -0
  158. package/dist/installer/yaml-safe-mutate.d.ts +19 -0
  159. package/dist/installer/yaml-safe-mutate.js +184 -0
  160. package/dist/installer/yaml-safe-mutate.js.map +1 -0
  161. package/dist/lib/active-tenant.d.ts +36 -0
  162. package/dist/lib/active-tenant.js +120 -0
  163. package/dist/lib/active-tenant.js.map +1 -0
  164. package/dist/lib/github-fetch.d.ts +1 -0
  165. package/dist/lib/github-fetch.js +11 -1
  166. package/dist/lib/github-fetch.js.map +1 -1
  167. package/dist/lib/keychain.d.ts +15 -2
  168. package/dist/lib/keychain.js +156 -8
  169. package/dist/lib/keychain.js.map +1 -1
  170. package/dist/lib/migration/keychain-migration.d.ts +35 -0
  171. package/dist/lib/migration/keychain-migration.js +189 -0
  172. package/dist/lib/migration/keychain-migration.js.map +1 -0
  173. package/dist/lib/tenant-resolver.d.ts +38 -0
  174. package/dist/lib/tenant-resolver.js +79 -0
  175. package/dist/lib/tenant-resolver.js.map +1 -0
  176. package/dist/lockfile/types.d.ts +8 -0
  177. package/dist/sidecar/eval-ui-manifest.json +1 -0
  178. package/dist/sidecar/sea-config.json +57 -0
  179. package/dist/sidecar/sea-prep.blob +0 -0
  180. package/dist/sidecar/server.cjs +141627 -0
  181. package/dist/sidecar/vskill-version.txt +1 -0
  182. package/dist/studio/lib/ops-log.js +140 -57
  183. package/dist/studio/lib/ops-log.js.map +1 -1
  184. package/dist/studio/lib/provenance.js +3 -2
  185. package/dist/studio/lib/provenance.js.map +1 -1
  186. package/dist/studio/lib/query.d.ts +1 -0
  187. package/dist/studio/lib/query.js +7 -0
  188. package/dist/studio/lib/query.js.map +1 -0
  189. package/dist/studio/lib/scope-transfer.d.ts +16 -0
  190. package/dist/studio/lib/scope-transfer.js +52 -25
  191. package/dist/studio/lib/scope-transfer.js.map +1 -1
  192. package/dist/studio/routes/index.js +13 -1
  193. package/dist/studio/routes/index.js.map +1 -1
  194. package/dist/studio/routes/ops.js +31 -9
  195. package/dist/studio/routes/ops.js.map +1 -1
  196. package/dist/studio/routes/promote.js +16 -11
  197. package/dist/studio/routes/promote.js.map +1 -1
  198. package/dist/studio/routes/revert.js +14 -18
  199. package/dist/studio/routes/revert.js.map +1 -1
  200. package/dist/studio/routes/test-install.js +14 -11
  201. package/dist/studio/routes/test-install.js.map +1 -1
  202. package/dist/studio-runtime/lockfile.d.ts +51 -0
  203. package/dist/studio-runtime/lockfile.js +216 -0
  204. package/dist/studio-runtime/lockfile.js.map +1 -0
  205. package/dist/updater/source-fetcher.js +2 -2
  206. package/dist/updater/source-fetcher.js.map +1 -1
  207. package/dist/utils/skill-builder-detection.d.ts +14 -1
  208. package/dist/utils/skill-builder-detection.js +20 -8
  209. package/dist/utils/skill-builder-detection.js.map +1 -1
  210. package/dist/utils/skill-creator-detection.d.ts +10 -2
  211. package/dist/utils/skill-creator-detection.js +12 -43
  212. package/dist/utils/skill-creator-detection.js.map +1 -1
  213. package/package.json +17 -1
  214. package/dist/eval-ui/assets/FindSkillsPalette-D0Zjhm31.js +0 -2
  215. package/dist/eval-ui/assets/SearchPaletteCore-EhcN1xEa.js +0 -14
  216. package/dist/eval-ui/assets/SkillDetailPanel-B5J60ffv.js +0 -1
  217. package/dist/eval-ui/assets/UpdateDropdown-Celf0_Cr.js +0 -1
  218. package/dist/eval-ui/assets/index-BV7k6fdk.js +0 -124
  219. package/dist/eval-ui/assets/index-CKLqBL52.css +0 -1
  220. package/dist/eval-ui/assets/skill-studio-logo-CRyKgIrg.png +0 -0
@@ -21,11 +21,9 @@
21
21
  // Ref: .specweave/increments/0734-studio-create-skill-engine-selector
22
22
  // ACs: AC-US5-01..AC-US5-09
23
23
  // ---------------------------------------------------------------------------
24
- import { spawn } from "node:child_process";
25
- import { randomUUID } from "node:crypto";
26
24
  import { sendJson, readBody } from "./router.js";
27
- import { initSSE, sendSSE, sendSSEDone } from "./sse-helpers.js";
28
25
  import { isCliAvailable } from "./install-engine-routes-helpers.js";
26
+ import { isLocalhost, mountSpawnStreamRoute, startSpawnJob, } from "./install-jobs.js";
29
27
  /**
30
28
  * Hard-coded engine→command allow-list. The HTTP request body NEVER reaches a
31
29
  * shell — only the engine *name* is read from the request, then mapped here.
@@ -43,86 +41,7 @@ const INSTALL_COMMANDS = {
43
41
  },
44
42
  };
45
43
  const INSTALL_TIMEOUT_MS = 120_000;
46
- const STDOUT_BUFFER_CAP = 1024 * 1024; // 1 MB
47
44
  const JOBS = new Map();
48
- function isLocalhost(req) {
49
- const addr = req.socket.remoteAddress ?? "";
50
- return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
51
- }
52
- function trimRing(buf, cap) {
53
- return buf.length <= cap ? buf : buf.slice(buf.length - cap);
54
- }
55
- function emitToJob(job, event, data) {
56
- job.pastEvents.push({ event, data });
57
- for (const sub of job.subscribers) {
58
- try {
59
- sub(event, data);
60
- }
61
- catch { /* subscriber failed — ignore */ }
62
- }
63
- }
64
- function startInstall(engine) {
65
- const cmd = INSTALL_COMMANDS[engine];
66
- const proc = spawn(cmd.command, cmd.args, { stdio: ["ignore", "pipe", "pipe"] });
67
- const job = {
68
- id: randomUUID(),
69
- engine,
70
- proc,
71
- stdoutBuffer: "",
72
- stderrBuffer: "",
73
- exitCode: null,
74
- done: false,
75
- subscribers: new Set(),
76
- pastEvents: [],
77
- };
78
- proc.stdout?.on("data", (chunk) => {
79
- const text = chunk.toString();
80
- job.stdoutBuffer = trimRing(job.stdoutBuffer + text, STDOUT_BUFFER_CAP);
81
- for (const line of text.split(/\r?\n/)) {
82
- if (line.length > 0)
83
- emitToJob(job, "progress", { stream: "stdout", line });
84
- }
85
- });
86
- proc.stderr?.on("data", (chunk) => {
87
- const text = chunk.toString();
88
- job.stderrBuffer = trimRing(job.stderrBuffer + text, STDOUT_BUFFER_CAP);
89
- for (const line of text.split(/\r?\n/)) {
90
- if (line.length > 0)
91
- emitToJob(job, "progress", { stream: "stderr", line });
92
- }
93
- });
94
- let timedOut = false;
95
- const timer = setTimeout(() => {
96
- timedOut = true;
97
- try {
98
- proc.kill("SIGTERM");
99
- }
100
- catch { /* process already gone */ }
101
- }, INSTALL_TIMEOUT_MS);
102
- proc.on("exit", (code) => {
103
- clearTimeout(timer);
104
- job.exitCode = timedOut ? -1 : code;
105
- job.done = true;
106
- const stderr = timedOut ? "timeout" : job.stderrBuffer.trim();
107
- emitToJob(job, "done", {
108
- success: !timedOut && code === 0,
109
- exitCode: timedOut ? -1 : code,
110
- stderr,
111
- });
112
- });
113
- proc.on("error", (err) => {
114
- clearTimeout(timer);
115
- job.exitCode = -1;
116
- job.done = true;
117
- emitToJob(job, "done", {
118
- success: false,
119
- exitCode: -1,
120
- stderr: err.message || "spawn failed",
121
- });
122
- });
123
- JOBS.set(job.id, job);
124
- return job;
125
- }
126
45
  export function registerInstallEngineRoutes(router, _root) {
127
46
  // POST /api/studio/install-engine
128
47
  router.post("/api/studio/install-engine", async (req, res) => {
@@ -153,51 +72,17 @@ export function registerInstallEngineRoutes(router, _root) {
153
72
  }, 412, req);
154
73
  return;
155
74
  }
156
- const job = startInstall(engine);
75
+ const job = startSpawnJob({
76
+ command: cmd.command,
77
+ args: cmd.args,
78
+ meta: { engine },
79
+ timeoutMs: INSTALL_TIMEOUT_MS,
80
+ jobs: JOBS,
81
+ });
157
82
  sendJson(res, { jobId: job.id }, 202, req);
158
83
  });
159
84
  // GET /api/studio/install-engine/:jobId/stream
160
- router.get("/api/studio/install-engine/:jobId/stream", async (req, res, params) => {
161
- if (!isLocalhost(req)) {
162
- sendJson(res, { error: "localhost-only endpoint" }, 403, req);
163
- return;
164
- }
165
- const job = JOBS.get(params.jobId);
166
- if (!job) {
167
- sendJson(res, { error: "unknown jobId" }, 404, req);
168
- return;
169
- }
170
- initSSE(res, req);
171
- // Replay any events that fired before this stream connected.
172
- for (const ev of job.pastEvents) {
173
- try {
174
- sendSSE(res, ev.event, ev.data);
175
- }
176
- catch { /* stream closed */ }
177
- }
178
- if (job.done) {
179
- try {
180
- res.end();
181
- }
182
- catch { /* already closed */ }
183
- return;
184
- }
185
- const subscriber = (event, data) => {
186
- try {
187
- if (event === "done")
188
- sendSSEDone(res, data);
189
- else
190
- sendSSE(res, event, data);
191
- }
192
- catch { /* stream closed */ }
193
- };
194
- job.subscribers.add(subscriber);
195
- const cleanup = () => {
196
- job.subscribers.delete(subscriber);
197
- };
198
- req.on("close", cleanup);
199
- req.on("aborted", cleanup);
200
- });
85
+ mountSpawnStreamRoute(router, "/api/studio/install-engine", JOBS);
201
86
  }
202
87
  // ---------------------------------------------------------------------------
203
88
  // Internals exposed for tests.
@@ -1 +1 @@
1
- {"version":3,"file":"install-engine-routes.js","sourceRoot":"","sources":["../../src/eval-server/install-engine-routes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"install-engine-routes.js","sourceRoot":"","sources":["../../src/eval-server/install-engine-routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import * as http from "node:http";
2
+ import { type ChildProcess } from "node:child_process";
3
+ import type { Router } from "./router.js";
4
+ export declare const STDOUT_BUFFER_CAP: number;
5
+ export type JobEvent = "progress" | "done";
6
+ export interface SpawnJob<TMeta extends object> {
7
+ id: string;
8
+ meta: TMeta;
9
+ proc: ChildProcess;
10
+ stdoutBuffer: string;
11
+ stderrBuffer: string;
12
+ exitCode: number | null;
13
+ done: boolean;
14
+ subscribers: Set<(event: JobEvent, data: unknown) => void>;
15
+ pastEvents: Array<{
16
+ event: JobEvent;
17
+ data: unknown;
18
+ }>;
19
+ }
20
+ export interface StartSpawnJobOptions<TMeta extends object> {
21
+ command: string;
22
+ args: string[];
23
+ meta: TMeta;
24
+ timeoutMs: number;
25
+ jobs: Map<string, SpawnJob<TMeta>>;
26
+ }
27
+ export declare function isLocalhost(req: http.IncomingMessage): boolean;
28
+ export declare function trimRing(buf: string, cap: number): string;
29
+ /**
30
+ * Spawn `command` with `args`, wire stdout/stderr to per-line "progress"
31
+ * events, register the job in `jobs`, and emit "done" on exit / error /
32
+ * timeout. Returns the registered job synchronously so the HTTP handler
33
+ * can reply with `{ jobId }` immediately.
34
+ */
35
+ export declare function startSpawnJob<TMeta extends object>(opts: StartSpawnJobOptions<TMeta>): SpawnJob<TMeta>;
36
+ /**
37
+ * Mount `GET <prefix>/:jobId/stream` on `router`. The handler enforces the
38
+ * localhost gate, replays buffered events, then subscribes the SSE response
39
+ * to live "progress"/"done" events until disconnect.
40
+ */
41
+ export declare function mountSpawnStreamRoute<TMeta extends object>(router: Router, prefix: string, jobs: Map<string, SpawnJob<TMeta>>): void;
@@ -0,0 +1,161 @@
1
+ // ---------------------------------------------------------------------------
2
+ // install-jobs — shared spawn-job runtime for install-skill / install-engine
3
+ // ---------------------------------------------------------------------------
4
+ // Both install-skill-routes and install-engine-routes were ~90% duplicate code:
5
+ // - InstallJob interface (proc, buffers, subscribers, pastEvents)
6
+ // - JOBS Map per route (UUID → job)
7
+ // - localhost-only guard
8
+ // - stdout/stderr ring-buffered into per-line "progress" events
9
+ // - SIGTERM on timeout, "done" event on exit/error
10
+ // - SSE replay-then-subscribe `/:jobId/stream` route
11
+ //
12
+ // Extracting that here means an SSE / timeout / replay bug fix lands once,
13
+ // not twice. Each route file now declares only:
14
+ // - its argv builder + body validation
15
+ // - its prefix and metadata shape (TMeta)
16
+ // ---------------------------------------------------------------------------
17
+ import { spawn } from "node:child_process";
18
+ import { randomUUID } from "node:crypto";
19
+ import { sendJson } from "./router.js";
20
+ import { initSSE, sendSSE, sendSSEDone } from "./sse-helpers.js";
21
+ import { buildSpawnEnv } from "./utils/spawn-env.js";
22
+ export const STDOUT_BUFFER_CAP = 1024 * 1024; // 1 MiB ring per stream.
23
+ export function isLocalhost(req) {
24
+ const addr = req.socket.remoteAddress ?? "";
25
+ return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
26
+ }
27
+ export function trimRing(buf, cap) {
28
+ return buf.length <= cap ? buf : buf.slice(buf.length - cap);
29
+ }
30
+ function emitToJob(job, event, data) {
31
+ job.pastEvents.push({ event, data });
32
+ for (const sub of job.subscribers) {
33
+ try {
34
+ sub(event, data);
35
+ }
36
+ catch { /* subscriber failed — ignore */ }
37
+ }
38
+ }
39
+ /**
40
+ * Spawn `command` with `args`, wire stdout/stderr to per-line "progress"
41
+ * events, register the job in `jobs`, and emit "done" on exit / error /
42
+ * timeout. Returns the registered job synchronously so the HTTP handler
43
+ * can reply with `{ jobId }` immediately.
44
+ */
45
+ export function startSpawnJob(opts) {
46
+ const proc = spawn(opts.command, opts.args, {
47
+ stdio: ["ignore", "pipe", "pipe"],
48
+ // Scrub env — provider keys / studio overrides are not needed by the
49
+ // installer command and shouldn't leak to subprocess descendants.
50
+ env: buildSpawnEnv(),
51
+ });
52
+ const job = {
53
+ id: randomUUID(),
54
+ meta: opts.meta,
55
+ proc,
56
+ stdoutBuffer: "",
57
+ stderrBuffer: "",
58
+ exitCode: null,
59
+ done: false,
60
+ subscribers: new Set(),
61
+ pastEvents: [],
62
+ };
63
+ proc.stdout?.on("data", (chunk) => {
64
+ const text = chunk.toString();
65
+ job.stdoutBuffer = trimRing(job.stdoutBuffer + text, STDOUT_BUFFER_CAP);
66
+ for (const line of text.split(/\r?\n/)) {
67
+ if (line.length > 0)
68
+ emitToJob(job, "progress", { stream: "stdout", line });
69
+ }
70
+ });
71
+ proc.stderr?.on("data", (chunk) => {
72
+ const text = chunk.toString();
73
+ job.stderrBuffer = trimRing(job.stderrBuffer + text, STDOUT_BUFFER_CAP);
74
+ for (const line of text.split(/\r?\n/)) {
75
+ if (line.length > 0)
76
+ emitToJob(job, "progress", { stream: "stderr", line });
77
+ }
78
+ });
79
+ let timedOut = false;
80
+ const timer = setTimeout(() => {
81
+ timedOut = true;
82
+ try {
83
+ proc.kill("SIGTERM");
84
+ }
85
+ catch { /* process already gone */ }
86
+ }, opts.timeoutMs);
87
+ proc.on("exit", (code) => {
88
+ clearTimeout(timer);
89
+ job.exitCode = timedOut ? -1 : code;
90
+ job.done = true;
91
+ const stderr = timedOut ? "timeout" : job.stderrBuffer.trim();
92
+ emitToJob(job, "done", {
93
+ success: !timedOut && code === 0,
94
+ exitCode: timedOut ? -1 : code,
95
+ stderr,
96
+ });
97
+ });
98
+ proc.on("error", (err) => {
99
+ clearTimeout(timer);
100
+ job.exitCode = -1;
101
+ job.done = true;
102
+ emitToJob(job, "done", {
103
+ success: false,
104
+ exitCode: -1,
105
+ stderr: err.message || "spawn failed",
106
+ });
107
+ });
108
+ opts.jobs.set(job.id, job);
109
+ return job;
110
+ }
111
+ /**
112
+ * Mount `GET <prefix>/:jobId/stream` on `router`. The handler enforces the
113
+ * localhost gate, replays buffered events, then subscribes the SSE response
114
+ * to live "progress"/"done" events until disconnect.
115
+ */
116
+ export function mountSpawnStreamRoute(router, prefix, jobs) {
117
+ router.get(`${prefix}/:jobId/stream`, async (req, res, params) => {
118
+ if (!isLocalhost(req)) {
119
+ sendJson(res, { error: "localhost-only endpoint" }, 403, req);
120
+ return;
121
+ }
122
+ const job = jobs.get(params.jobId);
123
+ if (!job) {
124
+ sendJson(res, { error: "unknown jobId" }, 404, req);
125
+ return;
126
+ }
127
+ initSSE(res, req);
128
+ // Replay any events that fired before this stream connected.
129
+ for (const ev of job.pastEvents) {
130
+ try {
131
+ sendSSE(res, ev.event, ev.data);
132
+ }
133
+ catch { /* stream closed */ }
134
+ }
135
+ if (job.done) {
136
+ try {
137
+ res.end();
138
+ }
139
+ catch { /* already closed */ }
140
+ return;
141
+ }
142
+ const subscriber = (event, data) => {
143
+ try {
144
+ if (event === "done")
145
+ sendSSEDone(res, data);
146
+ else
147
+ sendSSE(res, event, data);
148
+ }
149
+ catch {
150
+ // Stream write failed — eagerly drop this subscriber so we don't
151
+ // accumulate dead listeners on half-open sockets.
152
+ job.subscribers.delete(subscriber);
153
+ }
154
+ };
155
+ job.subscribers.add(subscriber);
156
+ const cleanup = () => { job.subscribers.delete(subscriber); };
157
+ req.on("close", cleanup);
158
+ req.on("aborted", cleanup);
159
+ });
160
+ }
161
+ //# sourceMappingURL=install-jobs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-jobs.js","sourceRoot":"","sources":["../../src/eval-server/install-jobs.ts"],"names":[],"mappings":"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"}
@@ -1,28 +1,91 @@
1
- import { type ChildProcess } from "node:child_process";
2
1
  import type { Router } from "./router.js";
2
+ import { type SpawnJob, type JobEvent } from "./install-jobs.js";
3
+ import { type AgentInstallResult } from "../installer/multi-install.js";
4
+ import type { ParsedSkill } from "../installer/transformers/index.js";
3
5
  type InstallScope = "project" | "user" | "global";
4
- interface InstallJob {
5
- id: string;
6
+ type MultiInstallScope = "project" | "user";
7
+ interface SkillJobMeta {
6
8
  skill: string;
7
9
  scope: InstallScope;
8
- proc: ChildProcess;
9
- stdoutBuffer: string;
10
- stderrBuffer: string;
11
- exitCode: number | null;
10
+ }
11
+ interface MultiInstallJob {
12
+ id: string;
12
13
  done: boolean;
13
- subscribers: Set<(event: "progress" | "done", data: unknown) => void>;
14
+ subscribers: Set<(event: MultiInstallJobEvent, data: unknown) => void>;
14
15
  pastEvents: Array<{
15
- event: "progress" | "done";
16
+ event: MultiInstallJobEvent;
16
17
  data: unknown;
17
18
  }>;
18
19
  }
20
+ type MultiInstallJobEvent = JobEvent | "result";
19
21
  declare function buildArgs(skill: string, scope: InstallScope): string[];
20
- export declare function registerInstallSkillRoutes(router: Router): void;
22
+ declare function normalizeInstallScope(scope: InstallScope): MultiInstallScope;
23
+ declare function isValidParsedSkill(s: unknown): s is ParsedSkill;
24
+ type FetchLike = typeof fetch;
25
+ interface ResolveSkillOptions {
26
+ cwd?: string;
27
+ home?: string;
28
+ fetchImpl?: FetchLike;
29
+ platformBaseUrl?: string;
30
+ githubTokenProvider?: () => string | null;
31
+ }
32
+ declare function fetchSkillMdFromGitHub(opts: {
33
+ repoUrl: string;
34
+ skillPath: string;
35
+ refs: string[];
36
+ fetchImpl: FetchLike;
37
+ token: string | null;
38
+ }): Promise<string | null>;
39
+ declare function resolveParsedSkillFromPlatform(identifier: string, opts?: ResolveSkillOptions): Promise<ParsedSkill | null>;
40
+ /**
41
+ * Server-side fallback: when the frontend posts a multi-agent install
42
+ * without `parsedSkill`, locate the skill on disk (project / personal /
43
+ * plugin cache via {@link locateSkill}), read its SKILL.md, and build a
44
+ * minimal {@link ParsedSkill}. Keeps the POST payload trivial — the
45
+ * frontend doesn't need to fetch, parse, and re-marshal SKILL.md itself.
46
+ *
47
+ * Returns `null` when no on-disk skill matches the identifier (the route
48
+ * surfaces this as a 404 so the caller can retry with an explicit
49
+ * `parsedSkill`).
50
+ */
51
+ export declare function resolveParsedSkillFromIdentifier(identifier: string, opts?: ResolveSkillOptions): Promise<ParsedSkill | null>;
52
+ declare function validateAgentIds(ids: unknown): {
53
+ ok: true;
54
+ ids: string[];
55
+ } | {
56
+ ok: false;
57
+ error: string;
58
+ };
59
+ declare function writeMultiInstallLockfile(opts: {
60
+ identifier: string;
61
+ skill: ParsedSkill;
62
+ scope: "project" | "user";
63
+ projectRoot: string;
64
+ results: AgentInstallResult[];
65
+ }): void;
66
+ declare function runMultiInstallJob(opts: {
67
+ identifier: string;
68
+ skill: ParsedSkill;
69
+ agentIds: string[];
70
+ scope: "project" | "user";
71
+ projectRoot: string;
72
+ }): Promise<MultiInstallJob>;
73
+ export declare function registerInstallSkillRoutes(router: Router, root?: string): void;
21
74
  export declare const __test__: {
22
- JOBS: Map<string, InstallJob>;
75
+ JOBS: Map<string, SpawnJob<SkillJobMeta>>;
76
+ MULTI_JOBS: Map<string, MultiInstallJob>;
23
77
  SAFE_NAME: RegExp;
78
+ SAFE_AGENT_ID: RegExp;
24
79
  VALID_SCOPES: ReadonlySet<string>;
25
80
  INSTALL_TIMEOUT_MS: number;
26
81
  buildArgs: typeof buildArgs;
82
+ normalizeInstallScope: typeof normalizeInstallScope;
83
+ validateAgentIds: typeof validateAgentIds;
84
+ isValidParsedSkill: typeof isValidParsedSkill;
85
+ resolveParsedSkillFromIdentifier: typeof resolveParsedSkillFromIdentifier;
86
+ resolveParsedSkillFromPlatform: typeof resolveParsedSkillFromPlatform;
87
+ fetchSkillMdFromGitHub: typeof fetchSkillMdFromGitHub;
88
+ runMultiInstallJob: typeof runMultiInstallJob;
89
+ writeMultiInstallLockfile: typeof writeMultiInstallLockfile;
27
90
  };
28
91
  export {};