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.
- package/README.md +4 -1
- package/dist/backend/server.js +4 -1
- package/dist/backend/services/artifact-service.js +14 -0
- package/dist/backend/services/claude-hook-service.js +6 -13
- package/dist/backend/services/pm-user-question.js +62 -0
- package/dist/backend/services/workflow-control-service.js +73 -33
- package/dist/backend/templates/harness/project-manager-agent.js +9 -3
- package/dist/backend/templates/harness/vcm-workflow-review-skill.js +7 -1
- package/dist-frontend/assets/{index-C21rIHsU.js → index-ClaVB8jM.js} +33 -33
- package/dist-frontend/index.html +1 -1
- package/package.json +4 -1
- package/scripts/harness-tools/run-long-check +90 -43
package/dist-frontend/index.html
CHANGED
|
@@ -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-
|
|
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
|
+
"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
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
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
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
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",
|