vibe-coding-master 0.8.3 → 0.8.4

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.
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>VibeCodingMaster</title>
7
- <script type="module" crossorigin src="/assets/index-C21rIHsU.js"></script>
7
+ <script type="module" crossorigin src="/assets/index-ClaVB8jM.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="/assets/index-Dc0_KSf4.css">
9
9
  </head>
10
10
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibe-coding-master",
3
- "version": "0.8.3",
3
+ "version": "0.8.4",
4
4
  "description": "Local GUI session cockpit for Claude Code role sessions.",
5
5
  "type": "module",
6
6
  "files": [
@@ -49,11 +49,14 @@
49
49
  "react-dom": "^19.1.0",
50
50
  "react-markdown": "^10.1.0",
51
51
  "remark-gfm": "^4.0.1",
52
+ "remark-parse": "^11.0.0",
53
+ "unified": "^11.0.5",
52
54
  "ws": "^8.18.2",
53
55
  "zod": "^3.25.28"
54
56
  },
55
57
  "devDependencies": {
56
58
  "@playwright/test": "^1.52.0",
59
+ "@types/mdast": "^4.0.4",
57
60
  "@types/node": "^22.15.24",
58
61
  "@types/react": "^19.1.6",
59
62
  "@types/react-dom": "^19.1.5",
@@ -17,6 +17,7 @@ Only one validation job may be active at a time.
17
17
  """
18
18
  import json
19
19
  import os
20
+ import shutil
20
21
  import signal
21
22
  import subprocess
22
23
  import sys
@@ -206,7 +207,48 @@ def find_active_job() -> dict | None:
206
207
  return None
207
208
 
208
209
 
210
+ def resolve_executable(executable: str) -> str:
211
+ root = root_dir()
212
+ if os.path.dirname(executable):
213
+ candidate = root / executable
214
+ if not candidate.exists():
215
+ raise ValueError(f"executable does not exist: {candidate}")
216
+ if not candidate.is_file():
217
+ raise ValueError(f"executable is not a regular file: {candidate}")
218
+ if not os.access(candidate, os.X_OK):
219
+ raise ValueError(f"file is not executable: {candidate}")
220
+ return str(candidate)
221
+
222
+ # Popen runs in the worktree root, including for relative PATH entries.
223
+ search_path = os.pathsep.join(str(root / entry) for entry in os.get_exec_path())
224
+ resolved = shutil.which(executable, path=search_path)
225
+ if resolved is None:
226
+ raise ValueError(f"executable not found or not executable on PATH: {executable}")
227
+ return resolved
228
+
229
+
230
+ def record_launch_failure(directory: Path, status: dict, stage: str, error: OSError) -> str:
231
+ message = (
232
+ f"Unable to start {stage} for job {status['jobId']}: "
233
+ f"command={status['command'][0]!r}, cwd={root_dir()}: {error}"
234
+ )
235
+ with (directory / "stderr.log").open("a", encoding="utf-8") as stderr:
236
+ stderr.write(message + "\n")
237
+ write_json(
238
+ directory / "status.json",
239
+ {**status, "status": "failed", "finishedAt": now_iso(), "exitCode": None},
240
+ )
241
+ return message
242
+
243
+
209
244
  def start_job(command: list[str], timeout_seconds: float) -> int:
245
+ try:
246
+ executable = resolve_executable(command[0])
247
+ except (OSError, ValueError) as error:
248
+ print(f"error: cannot start {command[0]!r} in {root_dir()}: {error}", file=sys.stderr)
249
+ return 2
250
+ command = [executable, *command[1:]]
251
+
210
252
  active = find_active_job()
211
253
  if active:
212
254
  print(
@@ -234,31 +276,34 @@ def start_job(command: list[str], timeout_seconds: float) -> int:
234
276
  )
235
277
  + "\n"
236
278
  )
237
- write_json(
238
- directory / "status.json",
239
- {
240
- "jobId": job,
241
- "status": "queued",
242
- "command": command,
243
- "cwd": ".",
244
- "timeoutSeconds": timeout_seconds,
245
- "startedAt": None,
246
- "finishedAt": None,
247
- "exitCode": None,
248
- "durationSeconds": None,
249
- "workerPid": None,
250
- "processId": None,
251
- },
252
- )
279
+ queued = {
280
+ "jobId": job,
281
+ "status": "queued",
282
+ "command": command,
283
+ "cwd": ".",
284
+ "timeoutSeconds": timeout_seconds,
285
+ "startedAt": None,
286
+ "finishedAt": None,
287
+ "exitCode": None,
288
+ "durationSeconds": None,
289
+ "workerPid": None,
290
+ "processId": None,
291
+ }
292
+ write_json(directory / "status.json", queued)
253
293
 
254
- subprocess.Popen(
255
- [sys.executable, str(Path(__file__).resolve()), "--worker", job],
256
- cwd=root_dir(),
257
- stdin=subprocess.DEVNULL,
258
- stdout=subprocess.DEVNULL,
259
- stderr=subprocess.DEVNULL,
260
- start_new_session=True,
261
- )
294
+ try:
295
+ subprocess.Popen(
296
+ [sys.executable, str(Path(__file__).resolve()), "--worker", job],
297
+ cwd=root_dir(),
298
+ stdin=subprocess.DEVNULL,
299
+ stdout=subprocess.DEVNULL,
300
+ stderr=subprocess.DEVNULL,
301
+ start_new_session=True,
302
+ )
303
+ except OSError as error:
304
+ message = record_launch_failure(directory, queued, "job worker", error)
305
+ print(f"error: {message}", file=sys.stderr)
306
+ return 1
262
307
 
263
308
  print(f"job: {job}")
264
309
  print(f"ceiling: {int(timeout_seconds)}s (worker-enforced)")
@@ -290,30 +335,32 @@ def run_worker(job: str) -> int:
290
335
  "timeoutSeconds": timeout_seconds,
291
336
  "workerPid": os.getpid(),
292
337
  }
293
- write_json(
294
- status_path,
295
- {
296
- **base,
297
- "status": "starting",
298
- "startedAt": None,
299
- "finishedAt": None,
300
- "exitCode": None,
301
- "durationSeconds": None,
302
- "processId": None,
303
- },
304
- )
338
+ starting = {
339
+ **base,
340
+ "status": "starting",
341
+ "startedAt": None,
342
+ "finishedAt": None,
343
+ "exitCode": None,
344
+ "durationSeconds": None,
345
+ "processId": None,
346
+ }
347
+ write_json(status_path, starting)
305
348
 
306
349
  started = time.time()
307
350
  started_at = now_iso()
308
351
  verdict = None
309
352
  with (directory / "stdout.log").open("wb") as stdout, (directory / "stderr.log").open("wb") as stderr:
310
- process = subprocess.Popen(
311
- command,
312
- cwd=root_dir(),
313
- stdout=stdout,
314
- stderr=stderr,
315
- start_new_session=True,
316
- )
353
+ try:
354
+ process = subprocess.Popen(
355
+ command,
356
+ cwd=root_dir(),
357
+ stdout=stdout,
358
+ stderr=stderr,
359
+ start_new_session=True,
360
+ )
361
+ except OSError as error:
362
+ record_launch_failure(directory, starting, "validation command", error)
363
+ return 1
317
364
  running = {
318
365
  **base,
319
366
  "status": "running",