vibe-coding-master 0.4.20 → 0.4.22

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.
@@ -0,0 +1,12 @@
1
+ import { readFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ export function readVcmPackageVersion(appRoot) {
4
+ const packageJsonPath = path.join(appRoot, "package.json");
5
+ try {
6
+ const raw = JSON.parse(readFileSync(packageJsonPath, "utf8"));
7
+ return typeof raw.version === "string" && raw.version.trim() ? raw.version : "unknown";
8
+ }
9
+ catch {
10
+ return process.env.npm_package_version || "unknown";
11
+ }
12
+ }
@@ -18,9 +18,10 @@ import { renderVcmHarnessBootstrapSkillRules } from "../templates/harness/vcm-ha
18
18
  import { renderVcmLongRunningValidationSkillRules } from "../templates/harness/vcm-long-running-validation-skill.js";
19
19
  import { renderVcmReportHarnessIssueSkillRules } from "../templates/harness/vcm-report-harness-issue-skill.js";
20
20
  import { renderVcmRouteMessageSkillRules } from "../templates/harness/vcm-route-message-skill.js";
21
- const HARNESS_VERSION = "0.3.0-fixed";
21
+ import { readVcmPackageVersion } from "../app-version.js";
22
22
  const CLI_DIR = path.dirname(fileURLToPath(import.meta.url));
23
23
  const APP_ROOT = path.resolve(CLI_DIR, "../../..");
24
+ const VCM_PACKAGE_VERSION = readVcmPackageVersion(APP_ROOT);
24
25
  const MANIFEST_PATH = ".ai/vcm-harness-manifest.json";
25
26
  const HTML_BLOCK_PATTERN = /<!-- VCM:BEGIN(?:\s+version=\d+)? -->[\s\S]*?<!-- VCM:END -->/m;
26
27
  const HASH_BLOCK_PATTERN = /# VCM:BEGIN(?:\s+version=\d+)?\n[\s\S]*?# VCM:END/m;
@@ -331,7 +332,7 @@ async function buildManifest(projectRoot) {
331
332
  return {
332
333
  schemaVersion: 1,
333
334
  manager: "vcm",
334
- harnessVersion: HARNESS_VERSION,
335
+ harnessVersion: VCM_PACKAGE_VERSION,
335
336
  installMode: "fixed",
336
337
  installedAt: typeof current?.installedAt === "string" ? current.installedAt : now,
337
338
  updatedAt: now,
@@ -46,6 +46,7 @@ import { registerTaskRoutes } from "./api/task-routes.js";
46
46
  import { registerTranslationRoutes } from "./api/translation-routes.js";
47
47
  import { registerTerminalWs } from "./ws/terminal-ws.js";
48
48
  import { toVcmError } from "./errors.js";
49
+ import { readVcmPackageVersion } from "./app-version.js";
49
50
  export async function createServer(deps, options = {}) {
50
51
  const app = Fastify({
51
52
  logger: false
@@ -161,6 +162,8 @@ export async function startServer(options = {}) {
161
162
  }
162
163
  export function createDefaultServerDeps(options = {}) {
163
164
  const fs = createNodeFileSystemAdapter();
165
+ const appRoot = getAppRoot();
166
+ const vcmVersion = readVcmPackageVersion(appRoot);
164
167
  const runner = createCommandRunner();
165
168
  const git = createGitAdapter(runner);
166
169
  const claude = createClaudeAdapter(runner);
@@ -185,7 +188,8 @@ export function createDefaultServerDeps(options = {}) {
185
188
  git,
186
189
  runtime,
187
190
  harnessEngineerSessions: sessionService,
188
- runFixedInstaller: createScriptFixedHarnessInstaller(path.join(getAppRoot(), "scripts/install-vcm-harness.mjs"))
191
+ runFixedInstaller: createScriptFixedHarnessInstaller(path.join(appRoot, "scripts/install-vcm-harness.mjs")),
192
+ vcmVersion
189
193
  });
190
194
  const harnessFeedbackService = createHarnessFeedbackService({
191
195
  fs,
@@ -277,7 +281,7 @@ export function createDefaultServerDeps(options = {}) {
277
281
  translationWorkerService
278
282
  });
279
283
  const diagnosticsService = createDiagnosticsService({
280
- appRoot: getAppRoot(),
284
+ appRoot,
281
285
  runtime,
282
286
  gatewayService,
283
287
  translationService
@@ -1,8 +1,7 @@
1
- import { readFileSync } from "node:fs";
2
1
  import fs from "node:fs/promises";
3
- import path from "node:path";
2
+ import { readVcmPackageVersion } from "../app-version.js";
4
3
  export function createDiagnosticsService(deps) {
5
- const version = readPackageVersion(deps.appRoot);
4
+ const version = readVcmPackageVersion(deps.appRoot);
6
5
  return {
7
6
  async getRuntimeDiagnostics() {
8
7
  const runtimeSessions = deps.runtime.listSessions();
@@ -34,16 +33,6 @@ export function createDiagnosticsService(deps) {
34
33
  }
35
34
  };
36
35
  }
37
- function readPackageVersion(appRoot) {
38
- const packageJsonPath = path.join(appRoot, "package.json");
39
- try {
40
- const raw = JSON.parse(readFileSync(packageJsonPath, "utf8"));
41
- return typeof raw.version === "string" && raw.version.trim() ? raw.version : "unknown";
42
- }
43
- catch {
44
- return process.env.npm_package_version || "unknown";
45
- }
46
- }
47
36
  async function readFdCount() {
48
37
  try {
49
38
  return (await fs.readdir("/proc/self/fd")).length;
@@ -21,6 +21,7 @@ import { bumpHarnessRevision, readHarnessRevisionState } from "./harness-revisio
21
21
  const execFileAsync = promisify(execFile);
22
22
  const BOOTSTRAP_SESSION_PATH = ".ai/vcm/bootstrap/session.json";
23
23
  const HARNESS_ENGINEER_SESSION_PATH = ".ai/vcm/harness-engineer/session.json";
24
+ const MANIFEST_PATH = ".ai/vcm-harness-manifest.json";
24
25
  export const VCM_HARNESS_VERSION = 1;
25
26
  const MANAGED_BLOCK_PATTERN = /<!-- VCM:BEGIN(?:\s+version=(\d+))? -->[\s\S]*?<!-- VCM:END -->/m;
26
27
  const HASH_MANAGED_BLOCK_PATTERN = /# VCM:BEGIN(?:\s+version=(\d+))?\n[\s\S]*?# VCM:END/m;
@@ -173,11 +174,15 @@ const HARNESS_FILES = [
173
174
  ];
174
175
  export function createHarnessService(deps) {
175
176
  const now = deps.now ?? (() => new Date().toISOString());
177
+ const vcmVersion = deps.vcmVersion ?? "unknown";
176
178
  return {
177
179
  async getHarnessStatus(repoRoot) {
178
180
  const analyses = await analyzeHarnessFiles(deps.fs, repoRoot);
179
181
  const legacyChanges = await analyzeLegacyCodexHarnessPaths(deps.fs, repoRoot);
180
- return renderHarnessStatus(await readHarnessRevisionValue(deps.fs, repoRoot), analyses, legacyChanges);
182
+ const manifestChange = deps.runFixedInstaller
183
+ ? await analyzeHarnessManifest(deps.fs, repoRoot, vcmVersion)
184
+ : undefined;
185
+ return renderHarnessStatus(await readHarnessRevisionValue(deps.fs, repoRoot), analyses, legacyChanges, manifestChange);
181
186
  },
182
187
  async getHarnessFileContent(repoRoot, filePath) {
183
188
  return readHarnessFileContent(deps.fs, repoRoot, filePath);
@@ -208,9 +213,12 @@ export function createHarnessService(deps) {
208
213
  const file = await readHarnessFileContent(deps.fs, repoRoot, definition.path);
209
214
  const analyses = await analyzeHarnessFiles(deps.fs, repoRoot);
210
215
  const legacyChanges = await analyzeLegacyCodexHarnessPaths(deps.fs, repoRoot);
216
+ const manifestChange = deps.runFixedInstaller
217
+ ? await analyzeHarnessManifest(deps.fs, repoRoot, vcmVersion)
218
+ : undefined;
211
219
  return {
212
220
  file,
213
- status: renderHarnessStatus(await readHarnessRevisionValue(deps.fs, repoRoot), analyses, legacyChanges),
221
+ status: renderHarnessStatus(await readHarnessRevisionValue(deps.fs, repoRoot), analyses, legacyChanges, manifestChange),
214
222
  harnessCommit
215
223
  };
216
224
  },
@@ -262,11 +270,11 @@ export function createHarnessService(deps) {
262
270
  return mergeRepositoryDiffToCurrentBranch(requireRepositoryMergeGit(deps.git), baseRepoRoot, input, now());
263
271
  },
264
272
  async getBootstrapStatus(repoRoot, targetRepoRoot = repoRoot) {
265
- return getHarnessBootstrapStatus(deps, repoRoot, targetRepoRoot, now);
273
+ return getHarnessBootstrapStatus(deps, repoRoot, targetRepoRoot, now, vcmVersion);
266
274
  },
267
275
  async startHarnessBootstrap(repoRoot, targetRepoRoot = repoRoot, input = {}) {
268
- const session = await ensureHarnessEngineerForBootstrap(deps, repoRoot, targetRepoRoot, now, input);
269
- const nextStatus = await getHarnessBootstrapStatus(deps, repoRoot, targetRepoRoot, now);
276
+ const session = await ensureHarnessEngineerForBootstrap(deps, repoRoot, targetRepoRoot, now, vcmVersion, input);
277
+ const nextStatus = await getHarnessBootstrapStatus(deps, repoRoot, targetRepoRoot, now, vcmVersion);
270
278
  return {
271
279
  status: {
272
280
  ...nextStatus,
@@ -277,8 +285,8 @@ export function createHarnessService(deps) {
277
285
  };
278
286
  },
279
287
  async restartHarnessBootstrap(repoRoot, targetRepoRoot = repoRoot, input = {}) {
280
- const session = await restartHarnessEngineerForBootstrap(deps, repoRoot, targetRepoRoot, now, input);
281
- const nextStatus = await getHarnessBootstrapStatus(deps, repoRoot, targetRepoRoot, now);
288
+ const session = await restartHarnessEngineerForBootstrap(deps, repoRoot, targetRepoRoot, now, vcmVersion, input);
289
+ const nextStatus = await getHarnessBootstrapStatus(deps, repoRoot, targetRepoRoot, now, vcmVersion);
282
290
  return {
283
291
  status: {
284
292
  ...nextStatus,
@@ -299,7 +307,7 @@ export function createHarnessService(deps) {
299
307
  }
300
308
  await deps.harnessEngineerSessions?.stopProjectHarnessEngineerSession(repoRoot);
301
309
  await clearHarnessBootstrapRunState(deps.fs, repoRoot);
302
- return getHarnessBootstrapStatus(deps, repoRoot, repoRoot, now);
310
+ return getHarnessBootstrapStatus(deps, repoRoot, repoRoot, now, vcmVersion);
303
311
  },
304
312
  async runHarnessBootstrap(repoRoot, targetRepoRoot = repoRoot) {
305
313
  if (!deps.runtime || !deps.harnessEngineerSessions) {
@@ -310,7 +318,7 @@ export function createHarnessService(deps) {
310
318
  });
311
319
  }
312
320
  await assertHarnessWorktreeClean(deps.git, targetRepoRoot);
313
- const status = await getHarnessBootstrapStatus(deps, repoRoot, targetRepoRoot, now);
321
+ const status = await getHarnessBootstrapStatus(deps, repoRoot, targetRepoRoot, now, vcmVersion);
314
322
  const session = status.session;
315
323
  if (!session || session.status !== "running" || !deps.runtime.getSession(session.id)) {
316
324
  throw new VcmError({
@@ -331,7 +339,7 @@ export function createHarnessService(deps) {
331
339
  updatedAt: timestamp
332
340
  });
333
341
  await submitTerminalInput(deps.runtime, session.id, prompt);
334
- const nextStatus = await getHarnessBootstrapStatus(deps, repoRoot, targetRepoRoot, now);
342
+ const nextStatus = await getHarnessBootstrapStatus(deps, repoRoot, targetRepoRoot, now, vcmVersion);
335
343
  return {
336
344
  status: {
337
345
  ...nextStatus,
@@ -345,7 +353,7 @@ export function createHarnessService(deps) {
345
353
  async recordHarnessBootstrapHook(repoRoot, input) {
346
354
  const state = await loadPersistedHarnessBootstrapRunState(deps.fs, repoRoot);
347
355
  if (state?.status !== "running" || !matchesBootstrapRunState(state, input)) {
348
- return getHarnessBootstrapStatus(deps, repoRoot, state?.targetRepoRoot ?? repoRoot, now);
356
+ return getHarnessBootstrapStatus(deps, repoRoot, state?.targetRepoRoot ?? repoRoot, now, vcmVersion);
349
357
  }
350
358
  const timestamp = now();
351
359
  if (input.eventName === "Stop" && state.targetRepoRoot) {
@@ -358,11 +366,11 @@ export function createHarnessService(deps) {
358
366
  updatedAt: timestamp,
359
367
  lastHookEvent: input.eventName
360
368
  });
361
- return getHarnessBootstrapStatus(deps, repoRoot, state.targetRepoRoot ?? repoRoot, now);
369
+ return getHarnessBootstrapStatus(deps, repoRoot, state.targetRepoRoot ?? repoRoot, now, vcmVersion);
362
370
  }
363
371
  };
364
372
  }
365
- async function ensureHarnessEngineerForBootstrap(deps, repoRoot, targetRepoRoot, now, input) {
373
+ async function ensureHarnessEngineerForBootstrap(deps, repoRoot, targetRepoRoot, now, vcmVersion, input) {
366
374
  if (!deps.harnessEngineerSessions) {
367
375
  throw new VcmError({
368
376
  code: "HARNESS_BOOTSTRAP_UNAVAILABLE",
@@ -370,7 +378,7 @@ async function ensureHarnessEngineerForBootstrap(deps, repoRoot, targetRepoRoot,
370
378
  statusCode: 501
371
379
  });
372
380
  }
373
- const currentStatus = await getHarnessBootstrapStatus(deps, repoRoot, targetRepoRoot, now);
381
+ const currentStatus = await getHarnessBootstrapStatus(deps, repoRoot, targetRepoRoot, now, vcmVersion);
374
382
  if (currentStatus.session?.status === "running") {
375
383
  return currentStatus.session;
376
384
  }
@@ -383,7 +391,7 @@ async function ensureHarnessEngineerForBootstrap(deps, repoRoot, targetRepoRoot,
383
391
  }
384
392
  return toHarnessBootstrapSession(await deps.harnessEngineerSessions.ensureProjectHarnessEngineerSession(repoRoot, input));
385
393
  }
386
- async function restartHarnessEngineerForBootstrap(deps, repoRoot, targetRepoRoot, now, input) {
394
+ async function restartHarnessEngineerForBootstrap(deps, repoRoot, targetRepoRoot, now, vcmVersion, input) {
387
395
  if (!deps.harnessEngineerSessions) {
388
396
  throw new VcmError({
389
397
  code: "HARNESS_BOOTSTRAP_UNAVAILABLE",
@@ -391,7 +399,7 @@ async function restartHarnessEngineerForBootstrap(deps, repoRoot, targetRepoRoot
391
399
  statusCode: 501
392
400
  });
393
401
  }
394
- const currentStatus = await getHarnessBootstrapStatus(deps, repoRoot, targetRepoRoot, now);
402
+ const currentStatus = await getHarnessBootstrapStatus(deps, repoRoot, targetRepoRoot, now, vcmVersion);
395
403
  if (!currentStatus.canStart) {
396
404
  throw new VcmError({
397
405
  code: "HARNESS_BOOTSTRAP_NOT_READY",
@@ -1075,12 +1083,13 @@ async function removeLegacyCodexHarnessPaths(fs, repoRoot) {
1075
1083
  }
1076
1084
  return changes;
1077
1085
  }
1078
- function renderHarnessStatus(harnessRevision, analyses, legacyChanges = []) {
1086
+ function renderHarnessStatus(harnessRevision, analyses, legacyChanges = [], manifestChange) {
1079
1087
  const files = analyses.map((analysis) => analysis.status);
1080
1088
  const plannedChanges = analyses
1081
1089
  .map((analysis) => analysis.plannedChange)
1082
1090
  .filter((change) => Boolean(change))
1083
- .concat(legacyChanges);
1091
+ .concat(legacyChanges)
1092
+ .concat(manifestChange ? [manifestChange] : []);
1084
1093
  // Derive `initialized`: the VCM harness is considered installed when at least one
1085
1094
  // VCM-exclusive marker is present (per analysis):
1086
1095
  // - status.hasManagedBlock === true (a managed block already lives in the file), OR
@@ -1253,10 +1262,40 @@ function resolveHarnessPath(repoRoot, relativePath) {
1253
1262
  function ensureTrailingNewline(content) {
1254
1263
  return content.endsWith("\n") ? content : `${content}\n`;
1255
1264
  }
1256
- async function getHarnessBootstrapStatus(deps, repoRoot, targetRepoRoot, now) {
1265
+ async function analyzeHarnessManifest(fs, repoRoot, vcmVersion) {
1266
+ if (!vcmVersion || vcmVersion === "unknown") {
1267
+ return undefined;
1268
+ }
1269
+ const manifestPath = resolveHarnessPath(repoRoot, MANIFEST_PATH);
1270
+ if (!await fs.pathExists(manifestPath)) {
1271
+ return {
1272
+ path: MANIFEST_PATH,
1273
+ action: "create",
1274
+ reason: `VCM fixed harness manifest is missing; current VCM version is ${vcmVersion}.`
1275
+ };
1276
+ }
1277
+ const manifest = await readOptionalJsonObject(fs, repoRoot, MANIFEST_PATH);
1278
+ const installedVersion = typeof manifest?.harnessVersion === "string" ? manifest.harnessVersion : undefined;
1279
+ if (!manifest || manifest.manager !== "vcm" || manifest.schemaVersion !== 1) {
1280
+ return {
1281
+ path: MANIFEST_PATH,
1282
+ action: "update",
1283
+ reason: "VCM fixed harness manifest metadata is invalid."
1284
+ };
1285
+ }
1286
+ if (installedVersion !== vcmVersion) {
1287
+ return {
1288
+ path: MANIFEST_PATH,
1289
+ action: "update",
1290
+ reason: `VCM fixed harness manifest version is ${installedVersion ?? "missing"}; current VCM version is ${vcmVersion}.`
1291
+ };
1292
+ }
1293
+ return undefined;
1294
+ }
1295
+ async function getHarnessBootstrapStatus(deps, repoRoot, targetRepoRoot, now, vcmVersion) {
1257
1296
  const moduleIndex = await readOptionalJsonObject(deps.fs, targetRepoRoot, ".ai/generated/module-index.json");
1258
1297
  const checks = [
1259
- await checkFixedHarness(deps.fs, targetRepoRoot),
1298
+ await checkFixedHarness(deps.fs, targetRepoRoot, vcmVersion),
1260
1299
  await checkProjectContext(deps.fs, targetRepoRoot),
1261
1300
  checkGeneratedJson(moduleIndex, ".ai/generated/module-index.json", "module-index", "Module index"),
1262
1301
  checkGeneratedJson(await readOptionalJsonObject(deps.fs, targetRepoRoot, ".ai/generated/public-surface.json"), ".ai/generated/public-surface.json", "public-surface", "Public surface"),
@@ -1288,10 +1327,10 @@ async function getHarnessBootstrapStatus(deps, repoRoot, targetRepoRoot, now) {
1288
1327
  warnings: bootstrapWarnings(status, checks, session, runState)
1289
1328
  };
1290
1329
  }
1291
- async function checkFixedHarness(fs, repoRoot) {
1330
+ async function checkFixedHarness(fs, repoRoot, vcmVersion) {
1292
1331
  const requiredPaths = [
1293
1332
  "CLAUDE.md",
1294
- ".ai/vcm-harness-manifest.json",
1333
+ MANIFEST_PATH,
1295
1334
  ".claude/skills/vcm-harness-bootstrap/SKILL.md",
1296
1335
  ".ai/tools/generate-module-index",
1297
1336
  ".ai/tools/generate-public-surface"
@@ -1320,6 +1359,16 @@ async function checkFixedHarness(fs, repoRoot) {
1320
1359
  detail: "CLAUDE.md is missing the VCM managed block."
1321
1360
  };
1322
1361
  }
1362
+ const manifestChange = await analyzeHarnessManifest(fs, repoRoot, vcmVersion);
1363
+ if (manifestChange) {
1364
+ return {
1365
+ key: "fixed-harness",
1366
+ label: "Fixed harness",
1367
+ status: "incomplete",
1368
+ path: MANIFEST_PATH,
1369
+ detail: manifestChange.reason
1370
+ };
1371
+ }
1323
1372
  return {
1324
1373
  key: "fixed-harness",
1325
1374
  label: "Fixed harness",
package/dist/main.js CHANGED
@@ -3,6 +3,7 @@ import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { DEFAULT_BACKEND_PORT, DEFAULT_FRONTEND_PORT } from "./shared/constants.js";
6
+ import { readVcmPackageVersion } from "./backend/app-version.js";
6
7
  import { getDefaultStaticDir, startServer } from "./backend/server.js";
7
8
  export function parseMainArgs(argv) {
8
9
  const options = {};
@@ -75,17 +76,7 @@ export async function main(argv = process.argv.slice(2)) {
75
76
  });
76
77
  }
77
78
  function readPackageVersion() {
78
- const packageJsonPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "package.json");
79
- try {
80
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
81
- if (typeof packageJson.version === "string" && packageJson.version.trim()) {
82
- return packageJson.version;
83
- }
84
- }
85
- catch {
86
- // Fall through to an explicit unknown version instead of starting the server.
87
- }
88
- return "unknown";
79
+ return readVcmPackageVersion(path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."));
89
80
  }
90
81
  function renderHelp() {
91
82
  return `Usage: