vibe-coding-master 0.0.17 → 0.2.1
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 +60 -28
- package/dist/backend/api/artifact-routes.js +5 -5
- package/dist/backend/api/harness-routes.js +8 -0
- package/dist/backend/server.js +8 -2
- package/dist/backend/services/artifact-service.js +12 -12
- package/dist/backend/services/harness-service.js +586 -5
- package/dist/backend/services/project-service.js +4 -1
- package/dist/backend/services/session-service.js +1 -3
- package/dist/backend/services/task-service.js +16 -17
- package/dist/backend/templates/handoff.js +64 -26
- package/dist/backend/templates/harness/architect-agent.js +42 -12
- package/dist/backend/templates/harness/claude-root.js +42 -18
- package/dist/backend/templates/harness/coder-agent.js +15 -11
- package/dist/backend/templates/harness/known-issues-doc.js +22 -0
- package/dist/backend/templates/harness/project-manager-agent.js +66 -16
- package/dist/backend/templates/harness/pull-request-template.js +29 -0
- package/dist/backend/templates/harness/reviewer-agent.js +40 -12
- package/dist/backend/templates/harness/vcm-final-acceptance-skill.js +105 -0
- package/dist/backend/templates/harness/vcm-harness-bootstrap-skill.js +78 -0
- package/dist/backend/templates/harness/vcm-long-running-validation-skill.js +50 -0
- package/dist/backend/templates/harness/vcm-route-message-skill.js +86 -0
- package/dist/backend/templates/message-envelope.js +1 -0
- package/dist/backend/templates/role-command.js +7 -1
- package/dist/shared/validation/artifact-check.js +14 -9
- package/dist-frontend/assets/index-BmpJxnNx.css +32 -0
- package/dist-frontend/assets/index-CGUkhVAP.js +90 -0
- package/dist-frontend/index.html +2 -2
- package/docs/cc-best-practices.md +433 -192
- package/docs/full-harness-baseline.md +258 -0
- package/docs/product-design.md +9 -9
- package/docs/v0.2-implementation-plan.md +379 -0
- package/docs/vcm-cc-best-practices.md +449 -0
- package/package.json +3 -1
- package/scripts/harness-tools/generate-module-index +298 -0
- package/scripts/harness-tools/generate-public-surface +692 -0
- package/scripts/install-vcm-harness.mjs +1690 -0
- package/scripts/uninstall-vcm-harness.mjs +490 -0
- package/scripts/verify-package.mjs +4 -0
- package/dist-frontend/assets/index-D40qaonx.css +0 -32
- package/dist-frontend/assets/index-DK2F4LFT.js +0 -90
- package/docs/v1-architecture-design.md +0 -1014
- package/docs/v1-implementation-plan.md +0 -1379
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
import argparse
|
|
3
|
+
import fnmatch
|
|
4
|
+
import json
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
import tomllib
|
|
11
|
+
except ModuleNotFoundError:
|
|
12
|
+
tomllib = None
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def relative_path(path: Path, root: Path) -> str:
|
|
16
|
+
try:
|
|
17
|
+
rel = path.absolute().relative_to(root.absolute())
|
|
18
|
+
except ValueError:
|
|
19
|
+
rel = path.resolve().relative_to(root.resolve())
|
|
20
|
+
return "." if str(rel) == "." else rel.as_posix()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def find_cargo_root(project_root: Path) -> Path:
|
|
24
|
+
if (project_root / "Cargo.toml").is_file():
|
|
25
|
+
return project_root
|
|
26
|
+
|
|
27
|
+
for child in sorted(project_root.iterdir(), key=lambda path: path.name):
|
|
28
|
+
if child.is_dir() and (child / "Cargo.toml").is_file():
|
|
29
|
+
return child
|
|
30
|
+
|
|
31
|
+
raise SystemExit(f"Could not find Cargo.toml in {project_root} or its direct child directories.")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def load_toml(path: Path) -> dict:
|
|
35
|
+
if tomllib is None:
|
|
36
|
+
raise SystemExit("Python 3.11+ is required to parse Cargo.toml files.")
|
|
37
|
+
return tomllib.loads(path.read_text())
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def load_cargo_metadata(cargo_root: Path) -> dict | None:
|
|
41
|
+
result = subprocess.run(
|
|
42
|
+
["cargo", "metadata", "--format-version", "1", "--no-deps"],
|
|
43
|
+
cwd=cargo_root,
|
|
44
|
+
check=False,
|
|
45
|
+
text=True,
|
|
46
|
+
stdout=subprocess.PIPE,
|
|
47
|
+
stderr=subprocess.PIPE,
|
|
48
|
+
)
|
|
49
|
+
if result.returncode != 0:
|
|
50
|
+
return None
|
|
51
|
+
return json.loads(result.stdout)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def path_is_excluded(relative: str, excludes: list[str]) -> bool:
|
|
55
|
+
normalized = relative.rstrip("/")
|
|
56
|
+
for pattern in excludes:
|
|
57
|
+
normalized_pattern = pattern.rstrip("/")
|
|
58
|
+
if (
|
|
59
|
+
normalized == normalized_pattern
|
|
60
|
+
or normalized.startswith(f"{normalized_pattern}/")
|
|
61
|
+
or fnmatch.fnmatch(normalized, normalized_pattern)
|
|
62
|
+
):
|
|
63
|
+
return True
|
|
64
|
+
return False
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def valid_workspace_member_manifests(cargo_root: Path) -> list[Path]:
|
|
68
|
+
data = load_toml(cargo_root / "Cargo.toml")
|
|
69
|
+
workspace = data.get("workspace", {})
|
|
70
|
+
members = workspace.get("members", [])
|
|
71
|
+
excludes = workspace.get("exclude", [])
|
|
72
|
+
|
|
73
|
+
manifests: list[Path] = []
|
|
74
|
+
seen: set[Path] = set()
|
|
75
|
+
|
|
76
|
+
if data.get("package", {}).get("name"):
|
|
77
|
+
manifests.append(cargo_root / "Cargo.toml")
|
|
78
|
+
seen.add(cargo_root / "Cargo.toml")
|
|
79
|
+
|
|
80
|
+
for member in members:
|
|
81
|
+
candidates = sorted(cargo_root.glob(member)) if "*" in member else [cargo_root / member]
|
|
82
|
+
for candidate in candidates:
|
|
83
|
+
if not candidate.is_dir():
|
|
84
|
+
continue
|
|
85
|
+
member_rel = relative_path(candidate, cargo_root)
|
|
86
|
+
if path_is_excluded(member_rel, excludes):
|
|
87
|
+
continue
|
|
88
|
+
manifest = candidate / "Cargo.toml"
|
|
89
|
+
if not manifest.is_file() or manifest in seen:
|
|
90
|
+
continue
|
|
91
|
+
manifests.append(manifest)
|
|
92
|
+
seen.add(manifest)
|
|
93
|
+
|
|
94
|
+
return manifests
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def package_name(manifest: Path) -> str | None:
|
|
98
|
+
package = load_toml(manifest).get("package", {})
|
|
99
|
+
name = package.get("name")
|
|
100
|
+
return name if isinstance(name, str) else None
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def dependency_names_from_table(table: dict) -> set[str]:
|
|
104
|
+
names: set[str] = set()
|
|
105
|
+
for name, value in table.items():
|
|
106
|
+
if isinstance(value, dict):
|
|
107
|
+
package = value.get("package")
|
|
108
|
+
names.add(package if isinstance(package, str) else name)
|
|
109
|
+
else:
|
|
110
|
+
names.add(name)
|
|
111
|
+
return names
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def manifest_dependency_names(manifest: Path) -> set[str]:
|
|
115
|
+
data = load_toml(manifest)
|
|
116
|
+
names: set[str] = set()
|
|
117
|
+
for key in ("dependencies", "dev-dependencies", "build-dependencies"):
|
|
118
|
+
table = data.get(key, {})
|
|
119
|
+
if isinstance(table, dict):
|
|
120
|
+
names.update(dependency_names_from_table(table))
|
|
121
|
+
|
|
122
|
+
target = data.get("target", {})
|
|
123
|
+
if isinstance(target, dict):
|
|
124
|
+
for target_table in target.values():
|
|
125
|
+
if not isinstance(target_table, dict):
|
|
126
|
+
continue
|
|
127
|
+
for key in ("dependencies", "dev-dependencies", "build-dependencies"):
|
|
128
|
+
table = target_table.get(key, {})
|
|
129
|
+
if isinstance(table, dict):
|
|
130
|
+
names.update(dependency_names_from_table(table))
|
|
131
|
+
return names
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def infer_layer(module_cargo_path: str, cargo_root: Path, project_root: Path) -> tuple[str, str]:
|
|
135
|
+
if module_cargo_path == ".":
|
|
136
|
+
return ("root", relative_path(cargo_root, project_root))
|
|
137
|
+
first = module_cargo_path.split("/", 1)[0]
|
|
138
|
+
return (first, relative_path(cargo_root / first, project_root))
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def rust_files_under(module_dir: Path, project_root: Path, child: str) -> list[str]:
|
|
142
|
+
root = module_dir / child
|
|
143
|
+
if not root.is_dir():
|
|
144
|
+
return []
|
|
145
|
+
return sorted(
|
|
146
|
+
relative_path(path, project_root)
|
|
147
|
+
for path in root.rglob("*.rs")
|
|
148
|
+
if path.is_file()
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def package_records_from_metadata(project_root: Path, cargo_root: Path, metadata: dict) -> list[dict]:
|
|
153
|
+
workspace_root = Path(metadata["workspace_root"])
|
|
154
|
+
workspace_member_ids = set(metadata["workspace_members"])
|
|
155
|
+
member_order = {member_id: index for index, member_id in enumerate(metadata["workspace_members"])}
|
|
156
|
+
|
|
157
|
+
packages = [
|
|
158
|
+
package
|
|
159
|
+
for package in metadata["packages"]
|
|
160
|
+
if package["id"] in workspace_member_ids
|
|
161
|
+
]
|
|
162
|
+
packages.sort(key=lambda package: member_order[package["id"]])
|
|
163
|
+
|
|
164
|
+
workspace_names = {package["name"] for package in packages}
|
|
165
|
+
records = []
|
|
166
|
+
for package in packages:
|
|
167
|
+
dependency_names = {
|
|
168
|
+
dependency["name"]
|
|
169
|
+
for dependency in package.get("dependencies", [])
|
|
170
|
+
if dependency.get("name") in workspace_names
|
|
171
|
+
}
|
|
172
|
+
records.append(
|
|
173
|
+
{
|
|
174
|
+
"name": package["name"],
|
|
175
|
+
"manifest": Path(package["manifest_path"]),
|
|
176
|
+
"workspaceDependencies": sorted(dependency_names),
|
|
177
|
+
}
|
|
178
|
+
)
|
|
179
|
+
return records
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def package_records_from_manifests(cargo_root: Path) -> list[dict]:
|
|
183
|
+
manifests = valid_workspace_member_manifests(cargo_root)
|
|
184
|
+
names_by_manifest = {
|
|
185
|
+
manifest: name
|
|
186
|
+
for manifest in manifests
|
|
187
|
+
if (name := package_name(manifest)) is not None
|
|
188
|
+
}
|
|
189
|
+
workspace_names = set(names_by_manifest.values())
|
|
190
|
+
records = []
|
|
191
|
+
|
|
192
|
+
for manifest, name in names_by_manifest.items():
|
|
193
|
+
dependency_names = manifest_dependency_names(manifest) & workspace_names
|
|
194
|
+
records.append(
|
|
195
|
+
{
|
|
196
|
+
"name": name,
|
|
197
|
+
"manifest": manifest,
|
|
198
|
+
"workspaceDependencies": sorted(dependency_names),
|
|
199
|
+
}
|
|
200
|
+
)
|
|
201
|
+
return records
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def build_index(project_root: Path) -> dict:
|
|
205
|
+
cargo_root = find_cargo_root(project_root)
|
|
206
|
+
metadata = load_cargo_metadata(cargo_root)
|
|
207
|
+
records = (
|
|
208
|
+
package_records_from_metadata(project_root, cargo_root, metadata)
|
|
209
|
+
if metadata is not None
|
|
210
|
+
else package_records_from_manifests(cargo_root)
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
layers: list[dict] = []
|
|
214
|
+
layer_by_name: dict[str, dict] = {}
|
|
215
|
+
|
|
216
|
+
for record in records:
|
|
217
|
+
manifest_path = record["manifest"]
|
|
218
|
+
module_dir = manifest_path.parent
|
|
219
|
+
module_path = relative_path(module_dir, project_root)
|
|
220
|
+
manifest_rel = relative_path(manifest_path, project_root)
|
|
221
|
+
module_cargo_path = relative_path(module_dir, cargo_root)
|
|
222
|
+
layer_name, layer_path = infer_layer(module_cargo_path, cargo_root, project_root)
|
|
223
|
+
|
|
224
|
+
if layer_name not in layer_by_name:
|
|
225
|
+
layer = {
|
|
226
|
+
"name": layer_name,
|
|
227
|
+
"path": layer_path,
|
|
228
|
+
"modules": [],
|
|
229
|
+
}
|
|
230
|
+
layer_by_name[layer_name] = layer
|
|
231
|
+
layers.append(layer)
|
|
232
|
+
|
|
233
|
+
layer_by_name[layer_name]["modules"].append(
|
|
234
|
+
{
|
|
235
|
+
"name": record["name"],
|
|
236
|
+
"path": module_path,
|
|
237
|
+
"manifest": manifest_rel,
|
|
238
|
+
"architectureDoc": f"{module_path}/ARCHITECTURE.md"
|
|
239
|
+
if module_path != "."
|
|
240
|
+
else "ARCHITECTURE.md",
|
|
241
|
+
"workspaceDependencies": record["workspaceDependencies"],
|
|
242
|
+
"files": {
|
|
243
|
+
"source": rust_files_under(module_dir, project_root, "src"),
|
|
244
|
+
"tests": rust_files_under(module_dir, project_root, "tests"),
|
|
245
|
+
},
|
|
246
|
+
}
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
return {
|
|
250
|
+
"schemaVersion": 1,
|
|
251
|
+
"kind": "module-index",
|
|
252
|
+
"generatedBy": ".ai/tools/generate-module-index",
|
|
253
|
+
"workspace": {
|
|
254
|
+
"root": relative_path(cargo_root, project_root),
|
|
255
|
+
"manifest": relative_path(cargo_root / "Cargo.toml", project_root),
|
|
256
|
+
},
|
|
257
|
+
"layerInference": {
|
|
258
|
+
"method": "path-first-segment-from-cargo-root",
|
|
259
|
+
"rootPackageLayer": "root",
|
|
260
|
+
},
|
|
261
|
+
"layers": layers,
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def main() -> int:
|
|
266
|
+
parser = argparse.ArgumentParser(description="Generate .ai/generated/module-index.json from cargo metadata.")
|
|
267
|
+
parser.add_argument("--check", action="store_true", help="Fail if the generated module index differs from the current file.")
|
|
268
|
+
parser.add_argument("--print", action="store_true", help="Print generated JSON instead of writing it.")
|
|
269
|
+
parser.add_argument("--output", default=".ai/generated/module-index.json", help="Output path relative to the project root.")
|
|
270
|
+
args = parser.parse_args()
|
|
271
|
+
|
|
272
|
+
root = Path(__file__).resolve().parents[2]
|
|
273
|
+
generated = json.dumps(build_index(root), indent=2, sort_keys=False) + "\n"
|
|
274
|
+
output_path = root / args.output
|
|
275
|
+
|
|
276
|
+
if args.check:
|
|
277
|
+
if not output_path.is_file():
|
|
278
|
+
sys.stderr.write(f"Missing generated module index: {output_path.relative_to(root)}\n")
|
|
279
|
+
return 1
|
|
280
|
+
current = output_path.read_text()
|
|
281
|
+
if current != generated:
|
|
282
|
+
sys.stderr.write(f"Stale generated module index: {output_path.relative_to(root)}\n")
|
|
283
|
+
return 1
|
|
284
|
+
print("generate-module-index check passed")
|
|
285
|
+
return 0
|
|
286
|
+
|
|
287
|
+
if args.print:
|
|
288
|
+
sys.stdout.write(generated)
|
|
289
|
+
return 0
|
|
290
|
+
|
|
291
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
292
|
+
output_path.write_text(generated)
|
|
293
|
+
print(f"wrote {output_path.relative_to(root)}")
|
|
294
|
+
return 0
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
if __name__ == "__main__":
|
|
298
|
+
raise SystemExit(main())
|