voidmachine 7.0.1 → 7.0.2

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/dist/main.js CHANGED
@@ -7395,62 +7395,6 @@ var require_dist = __commonJS({
7395
7395
  }
7396
7396
  });
7397
7397
 
7398
- // ../../node_modules/.pnpm/sisteransi@1.0.5/node_modules/sisteransi/src/index.js
7399
- var require_src = __commonJS({
7400
- "../../node_modules/.pnpm/sisteransi@1.0.5/node_modules/sisteransi/src/index.js"(exports, module) {
7401
- init_esm_shims();
7402
- var ESC2 = "\x1B";
7403
- var CSI2 = `${ESC2}[`;
7404
- var beep = "\x07";
7405
- var cursor = {
7406
- to(x3, y) {
7407
- if (!y) return `${CSI2}${x3 + 1}G`;
7408
- return `${CSI2}${y + 1};${x3 + 1}H`;
7409
- },
7410
- move(x3, y) {
7411
- let ret = "";
7412
- if (x3 < 0) ret += `${CSI2}${-x3}D`;
7413
- else if (x3 > 0) ret += `${CSI2}${x3}C`;
7414
- if (y < 0) ret += `${CSI2}${-y}A`;
7415
- else if (y > 0) ret += `${CSI2}${y}B`;
7416
- return ret;
7417
- },
7418
- up: (count = 1) => `${CSI2}${count}A`,
7419
- down: (count = 1) => `${CSI2}${count}B`,
7420
- forward: (count = 1) => `${CSI2}${count}C`,
7421
- backward: (count = 1) => `${CSI2}${count}D`,
7422
- nextLine: (count = 1) => `${CSI2}E`.repeat(count),
7423
- prevLine: (count = 1) => `${CSI2}F`.repeat(count),
7424
- left: `${CSI2}G`,
7425
- hide: `${CSI2}?25l`,
7426
- show: `${CSI2}?25h`,
7427
- save: `${ESC2}7`,
7428
- restore: `${ESC2}8`
7429
- };
7430
- var scroll = {
7431
- up: (count = 1) => `${CSI2}S`.repeat(count),
7432
- down: (count = 1) => `${CSI2}T`.repeat(count)
7433
- };
7434
- var erase = {
7435
- screen: `${CSI2}2J`,
7436
- up: (count = 1) => `${CSI2}1J`.repeat(count),
7437
- down: (count = 1) => `${CSI2}J`.repeat(count),
7438
- line: `${CSI2}2K`,
7439
- lineEnd: `${CSI2}K`,
7440
- lineStart: `${CSI2}1K`,
7441
- lines(count) {
7442
- let clear = "";
7443
- for (let i = 0; i < count; i++)
7444
- clear += this.line + (i < count - 1 ? cursor.up() : "");
7445
- if (count)
7446
- clear += cursor.left;
7447
- return clear;
7448
- }
7449
- };
7450
- module.exports = { cursor, scroll, erase, beep };
7451
- }
7452
- });
7453
-
7454
7398
  // ../../node_modules/.pnpm/picomatch@4.0.5/node_modules/picomatch/lib/constants.js
7455
7399
  var require_constants = __commonJS({
7456
7400
  "../../node_modules/.pnpm/picomatch@4.0.5/node_modules/picomatch/lib/constants.js"(exports, module) {
@@ -9218,6 +9162,62 @@ var require_picomatch2 = __commonJS({
9218
9162
  }
9219
9163
  });
9220
9164
 
9165
+ // ../../node_modules/.pnpm/sisteransi@1.0.5/node_modules/sisteransi/src/index.js
9166
+ var require_src = __commonJS({
9167
+ "../../node_modules/.pnpm/sisteransi@1.0.5/node_modules/sisteransi/src/index.js"(exports, module) {
9168
+ init_esm_shims();
9169
+ var ESC2 = "\x1B";
9170
+ var CSI2 = `${ESC2}[`;
9171
+ var beep = "\x07";
9172
+ var cursor = {
9173
+ to(x3, y) {
9174
+ if (!y) return `${CSI2}${x3 + 1}G`;
9175
+ return `${CSI2}${y + 1};${x3 + 1}H`;
9176
+ },
9177
+ move(x3, y) {
9178
+ let ret = "";
9179
+ if (x3 < 0) ret += `${CSI2}${-x3}D`;
9180
+ else if (x3 > 0) ret += `${CSI2}${x3}C`;
9181
+ if (y < 0) ret += `${CSI2}${-y}A`;
9182
+ else if (y > 0) ret += `${CSI2}${y}B`;
9183
+ return ret;
9184
+ },
9185
+ up: (count = 1) => `${CSI2}${count}A`,
9186
+ down: (count = 1) => `${CSI2}${count}B`,
9187
+ forward: (count = 1) => `${CSI2}${count}C`,
9188
+ backward: (count = 1) => `${CSI2}${count}D`,
9189
+ nextLine: (count = 1) => `${CSI2}E`.repeat(count),
9190
+ prevLine: (count = 1) => `${CSI2}F`.repeat(count),
9191
+ left: `${CSI2}G`,
9192
+ hide: `${CSI2}?25l`,
9193
+ show: `${CSI2}?25h`,
9194
+ save: `${ESC2}7`,
9195
+ restore: `${ESC2}8`
9196
+ };
9197
+ var scroll = {
9198
+ up: (count = 1) => `${CSI2}S`.repeat(count),
9199
+ down: (count = 1) => `${CSI2}T`.repeat(count)
9200
+ };
9201
+ var erase = {
9202
+ screen: `${CSI2}2J`,
9203
+ up: (count = 1) => `${CSI2}1J`.repeat(count),
9204
+ down: (count = 1) => `${CSI2}J`.repeat(count),
9205
+ line: `${CSI2}2K`,
9206
+ lineEnd: `${CSI2}K`,
9207
+ lineStart: `${CSI2}1K`,
9208
+ lines(count) {
9209
+ let clear = "";
9210
+ for (let i = 0; i < count; i++)
9211
+ clear += this.line + (i < count - 1 ? cursor.up() : "");
9212
+ if (count)
9213
+ clear += cursor.left;
9214
+ return clear;
9215
+ }
9216
+ };
9217
+ module.exports = { cursor, scroll, erase, beep };
9218
+ }
9219
+ });
9220
+
9221
9221
  // ../../node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/constants.js
9222
9222
  var require_constants2 = __commonJS({
9223
9223
  "../../node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/constants.js"(exports, module) {
@@ -17955,7 +17955,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
17955
17955
  var NONE = 0;
17956
17956
  var ASSUMED = 1;
17957
17957
  var PROVEN = 2;
17958
- function isRecursive(inst, stack, resolve43) {
17958
+ function isRecursive(inst, stack, resolve45) {
17959
17959
  const cached2 = recursive.get(inst);
17960
17960
  if (cached2 !== void 0)
17961
17961
  return cached2 ? PROVEN : NONE;
@@ -17965,7 +17965,7 @@ function isRecursive(inst, stack, resolve43) {
17965
17965
  let result = NONE;
17966
17966
  const check3 = (child) => {
17967
17967
  if (result !== PROVEN && child?._zod) {
17968
- const answer2 = isRecursive(child, stack, resolve43);
17968
+ const answer2 = isRecursive(child, stack, resolve45);
17969
17969
  if (answer2 > result)
17970
17970
  result = answer2;
17971
17971
  }
@@ -17976,7 +17976,7 @@ function isRecursive(inst, stack, resolve43) {
17976
17976
  const desc = Object.getOwnPropertyDescriptor(sh, key);
17977
17977
  if (!desc.enumerable)
17978
17978
  continue;
17979
- const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve43) : NONE;
17979
+ const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve45) : NONE;
17980
17980
  if (child > answer2)
17981
17981
  answer2 = child;
17982
17982
  }
@@ -18040,7 +18040,7 @@ function isRecursive(inst, stack, resolve43) {
18040
18040
  break;
18041
18041
  // `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
18042
18042
  case "lazy": {
18043
- const inner = def._cachedInner ?? (resolve43 ? inst._zod.innerType : void 0);
18043
+ const inner = def._cachedInner ?? (resolve45 ? inst._zod.innerType : void 0);
18044
18044
  merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
18045
18045
  break;
18046
18046
  }
@@ -33518,6 +33518,12 @@ init_esm_shims();
33518
33518
  // ../hook-runner/src/enforcement/shell-writes.ts
33519
33519
  init_esm_shims();
33520
33520
 
33521
+ // ../hook-runner/src/enforcement/shell-reads.ts
33522
+ init_esm_shims();
33523
+
33524
+ // ../hook-runner/src/enforcement/secret-read.ts
33525
+ init_esm_shims();
33526
+
33521
33527
  // ../hook-runner/src/enforcement/original-source.ts
33522
33528
  init_esm_shims();
33523
33529
 
@@ -33564,6 +33570,14 @@ function discoverProjectRoot(start) {
33564
33570
  current2 = parent;
33565
33571
  }
33566
33572
  }
33573
+ var DEFAULT_PROJECT_PATHS = {
33574
+ business: ["src/**", "apps/*/src/**"],
33575
+ tests: ["src/**/*.test.{ts,tsx}", "apps/*/src/**/*.test.{ts,tsx}"],
33576
+ spikes: ["scripts/spike-*", "apps/*/scripts/spike-*"],
33577
+ serverActions: ["src/app/(api|actions)/**", "apps/*/src/app/(api|actions)/**"],
33578
+ contracts: ["src/lib/contracts/**", "apps/*/src/lib/contracts/**"],
33579
+ e2e: ["tests/e2e/**", "apps/*/tests/e2e/**"]
33580
+ };
33567
33581
 
33568
33582
  // ../hook-runner/src/project-roots.ts
33569
33583
  var GIT_TIMEOUT_MS = 5e3;
@@ -36142,6 +36156,9 @@ function authorizedTargetedRequest(events, request, history) {
36142
36156
  const recoveredBlockers = writerBindingCorrectionFindings(events);
36143
36157
  return recovery !== void 0 && correction.seq > recovery.seq && count === 1 && reviewField(writer, "writerId") === original.writerId && binding3 !== void 0 && typeof binding3 === "object" && binding3 !== null && "completionEventId" in binding3 && binding3.completionEventId === previous.event.eventId && history.length === 1 && recoveredBlockers.length > 0 && sameMembers(recoveredBlockers.map((finding) => finding.findingId), knownBlockers.map((finding) => finding.findingId)) && events.filter((event) => event.kind === "lead-writer.requested" && reviewField(event, "actionKind") === "run-correction").length === 1 && events.filter((event) => event.kind === "specialist.requested" && event.subject === request.subject && event.seq > recovery.seq && event.seq <= request.seq).length === 1;
36144
36158
  }
36159
+ function hasBlockingReview(completion) {
36160
+ return completion.review !== void 0 && completion.findings.some((finding) => finding.classification === "blocking") && completion.findings.every((finding) => finding.classification !== void 0);
36161
+ }
36145
36162
  function canContinueNativeReview(events, request, contextId) {
36146
36163
  const start = events[0];
36147
36164
  if (!start || start.kind !== "mission.started" || reviewField(request, "planHash") !== reviewField(start, "planHash") || reviewField(request, "runtime") !== reviewField(start, "runtime") || request.kind !== "specialist.requested" || request.source !== "void-harness:mission.dispatch" || request.subject !== "core:independent-code-reviewer" || reviewField(request, "stage") !== "post-implementation" || !validNativeContextId(contextId) || events.some((event) => event.missionId !== request.missionId))
@@ -36152,7 +36169,7 @@ function canContinueNativeReview(events, request, contextId) {
36152
36169
  const prior = history.filter((item) => item !== void 0);
36153
36170
  const first = prior[0];
36154
36171
  const amendment = writerBindingRecovery(events);
36155
- if (!first || first.completion.review?.scope.kind !== "general" || first.completion.verdict !== "changes-requested" && !(first.completion.verdict === "degraded" && amendment && prior.length === 1) || amendment !== void 0 && prior.length !== 1 || new Set(prior.map((item) => item.completion.completionId)).size !== prior.length || events.some((event) => event.seq < request.seq && ["specialist.started", "specialist.completed"].includes(event.kind) && reviewField(event, "contextId") === contextId && (event.subject !== request.subject || reviewField(event, "stage") !== "post-implementation")) || events.filter((event) => event.kind === "specialist.completed" && event.subject === request.subject && reviewField(event, "stage") === "post-implementation" && event.seq < request.seq).at(-1)?.eventId !== prior.at(-1)?.event.eventId)
36172
+ if (!first || first.completion.review?.scope.kind !== "general" || !hasBlockingReview(first.completion) || amendment !== void 0 && prior.length !== 1 || new Set(prior.map((item) => item.completion.completionId)).size !== prior.length || events.some((event) => event.seq < request.seq && ["specialist.started", "specialist.completed"].includes(event.kind) && reviewField(event, "contextId") === contextId && (event.subject !== request.subject || reviewField(event, "stage") !== "post-implementation")) || events.filter((event) => event.kind === "specialist.completed" && event.subject === request.subject && reviewField(event, "stage") === "post-implementation" && event.seq < request.seq).at(-1)?.eventId !== prior.at(-1)?.event.eventId)
36156
36173
  return false;
36157
36174
  for (const [index, item] of prior.entries()) {
36158
36175
  const bound = boundNativeRequest(events, item);
@@ -36415,7 +36432,7 @@ function mergeFindings(completions2) {
36415
36432
  function decideStatus(input2) {
36416
36433
  if (input2.issues.length > 0)
36417
36434
  return "degraded";
36418
- if (input2.current.some((item) => item.completion.verdict === "degraded")) {
36435
+ if (input2.current.some((item) => item.completion.verdict === "degraded" && (input2.correctionBatches === void 0 || !hasBlockingReview(item.completion) || !input2.findings.some((finding) => finding.classification === "blocking")))) {
36419
36436
  return "degraded";
36420
36437
  }
36421
36438
  if (input2.stale.length > 0) {
@@ -37266,17 +37283,17 @@ function admitStoppedMission(input2, projectedHistory = input2.stream.events) {
37266
37283
  const migration = validatedSpecialistContractMigrationBoundary(events);
37267
37284
  if (!migration.ok)
37268
37285
  return refuse3("invalid-migration-receipt", migration.reasons.join("; "));
37269
- const boundary = observation3.stage === "post-implementation" ? migration.migration : void 0;
37270
- if (boundary !== void 0 && observation3.contractVersions[boundary.receipt.specialistId] !== boundary.receipt.toVersion) {
37286
+ const boundary2 = observation3.stage === "post-implementation" ? migration.migration : void 0;
37287
+ if (boundary2 !== void 0 && observation3.contractVersions[boundary2.receipt.specialistId] !== boundary2.receipt.toVersion) {
37271
37288
  return refuse3("inconsistent-review", "Recovery must observe the authenticated effective specialist contract");
37272
37289
  }
37273
37290
  const reviewInput = {
37274
37291
  stage: observation3.stage,
37275
37292
  expectedSource: observation3.expectedSource,
37276
- ...boundary === void 0 ? {} : { contractMigration: {
37277
- specialistId: boundary.receipt.specialistId,
37278
- afterSeq: boundary.seq,
37279
- reviewRound: boundary.receipt.reviewRound
37293
+ ...boundary2 === void 0 ? {} : { contractMigration: {
37294
+ specialistId: boundary2.receipt.specialistId,
37295
+ afterSeq: boundary2.seq,
37296
+ reviewRound: boundary2.receipt.reviewRound
37280
37297
  } },
37281
37298
  ...stageStart === void 0 ? {} : { stageStartSeqExclusive: stageStart },
37282
37299
  ...lastWriter === void 0 ? {} : { afterSeqExclusive: lastWriter },
@@ -39210,13 +39227,16 @@ function decideReviewPhase(start, review, baseVerdict, stage) {
39210
39227
  }
39211
39228
  function boundedReceiptReasons(input2, start, events) {
39212
39229
  const lastWriter = writerCompletions(input2).at(-1)?.seq ?? 0;
39230
+ const recovery = writerBindingRecovery(events);
39231
+ const binding3 = recovery && record15(lifecycleField(recovery, "writerBinding"));
39213
39232
  return events.filter((event) => event.kind === "specialist.completed" && event.seq > lastWriter && event.subject === "core:independent-code-reviewer" && lifecycleField(event, "stage") === "post-implementation").flatMap((event) => {
39214
39233
  const result = parseSpecialistCompletionValue(lifecycleField(event, "completion"));
39215
39234
  const receipt2 = result?.review;
39216
39235
  if (result === void 0 || receipt2 === void 0 || input2.reviewSubject === void 0) {
39217
39236
  return ["Independent review requires its durable committed subject and reviewer receipt"];
39218
39237
  }
39219
- if (!sameReviewSubject(receipt2, input2.reviewSubject) || receipt2.taskId !== event.missionId || receipt2.writerId !== start.leadWriterId || receipt2.reviewerId === start.leadWriterId) {
39238
+ const subject = binding3?.["completionEventId"] === event.eventId ? lifecycleField(event, "reviewSubject") : input2.reviewSubject;
39239
+ if (!isReviewSubject(subject) || !sameReviewSubject(receipt2, subject) || receipt2.taskId !== event.missionId || receipt2.writerId !== start.leadWriterId || receipt2.reviewerId === start.leadWriterId) {
39220
39240
  return ["Independent review receipt does not match the observed task, commit, base, or writer"];
39221
39241
  }
39222
39242
  if (receipt2.provenance.kind === "native-context" && receipt2.provenance.contextId !== lifecycleField(event, "contextId")) {
@@ -39225,7 +39245,7 @@ function boundedReceiptReasons(input2, start, events) {
39225
39245
  if (result.findings.some((finding) => finding.classification === void 0)) {
39226
39246
  return ["Bounded findings require an explicit consequence classification"];
39227
39247
  }
39228
- return [];
39248
+ return unboundCompletionReasons(input2, start.runtime, [event]);
39229
39249
  });
39230
39250
  }
39231
39251
  function recoveredPreparationTargets(events) {
@@ -39247,11 +39267,11 @@ function recoveredPreparationTargets(events) {
39247
39267
  specialistIds: events.filter((item) => item.kind === "specialist.completed" && ids.includes(item.eventId)).map((item) => item.subject)
39248
39268
  };
39249
39269
  }
39250
- function retainedPreparationSpecialists(input2, events, boundary, targets) {
39270
+ function retainedPreparationSpecialists(input2, events, boundary2, targets) {
39251
39271
  return requiredSpecialists(input2.plan, "pre-implementation").filter((id4) => {
39252
39272
  if (targets.includes(id4))
39253
39273
  return false;
39254
- const latest = events.filter((item) => item.kind === "specialist.completed" && item.subject === id4 && item.seq < boundary && lifecycleField(item, "stage") === "pre-implementation").at(-1);
39274
+ const latest = events.filter((item) => item.kind === "specialist.completed" && item.subject === id4 && item.seq < boundary2 && lifecycleField(item, "stage") === "pre-implementation").at(-1);
39255
39275
  if (latest === void 0)
39256
39276
  return false;
39257
39277
  const result = record15(lifecycleField(latest, "completion") ?? null);
@@ -39444,7 +39464,7 @@ function orchestrateMissionTeam(originalInput) {
39444
39464
  }, input2.specialistRuntime);
39445
39465
  }
39446
39466
  }
39447
- const postReview = firstImplementationSeq === void 0 || lastWriterSeq === void 0 ? void 0 : reduceReviewLoop({
39467
+ let postReview = firstImplementationSeq === void 0 || lastWriterSeq === void 0 ? void 0 : reduceReviewLoop({
39448
39468
  stage: "post-implementation",
39449
39469
  expectedSource,
39450
39470
  stageStartSeqExclusive: firstImplementationSeq,
@@ -39470,27 +39490,26 @@ function orchestrateMissionTeam(originalInput) {
39470
39490
  if (canonicalJsonHash(subject) !== canonicalJsonHash(input2.reviewSubject) || canonicalJsonHash(observation3?.["currentInputHashes"]) !== canonicalJsonHash(Object.fromEntries(Object.keys(record15(observation3?.["currentInputHashes"] ?? null) ?? {}).map((id4) => [id4, input2.currentInputHashesByStage["post-implementation"][id4]])))) {
39471
39491
  return stopped("blocked", postReview, baseVerdict, ["Writer binding recovery observations changed before correction"]);
39472
39492
  }
39473
- const reasons = ["Author-confirmed writer binding permits one correction and one targeted continuation; original review remains degraded"];
39474
- return applyRuntimeCertification({
39475
- phase: "correction",
39476
- action: {
39477
- kind: "run-correction",
39478
- writerId: start.leadWriterId,
39479
- findingIds: writerBindingCorrectionFindings(reviewEvents).map((finding) => finding.findingId)
39480
- },
39481
- review: postReview,
39482
- verdict: overrideVerdict(baseVerdict, "blocked", reasons),
39483
- reasons
39484
- }, input2.specialistRuntime);
39493
+ postReview = {
39494
+ ...postReview,
39495
+ status: "correction-required",
39496
+ readyForVerdict: false,
39497
+ findings: writerBindingCorrectionFindings(reviewEvents)
39498
+ };
39485
39499
  }
39486
39500
  if (bindingRecovery && postReview && input2.stream.events.some((event) => event.seq > bindingRecovery.seq && event.kind === "specialist.completed") && !postReview.readyForVerdict) {
39487
39501
  return stopped("blocked", postReview, baseVerdict, ["The single targeted continuation is spent; retain the original review budget"]);
39488
39502
  }
39503
+ if (start.boundedReview && postReview) {
39504
+ const receiptReasons = boundedReceiptReasons(input2, start, reviewEvents);
39505
+ if (receiptReasons.length > 0)
39506
+ return stopped("degraded", postReview, baseVerdict, receiptReasons);
39507
+ }
39489
39508
  if (postReview?.status === "blocked" || postReview?.status === "degraded") {
39490
39509
  return applyRuntimeCertification(decideReviewPhase(start, postReview, baseVerdict, "post-implementation"), input2.specialistRuntime);
39491
39510
  }
39492
39511
  const correctiveFindingIds = pendingRecoveredCorrectionFindingIds(input2.stream.events);
39493
- const correctiveContinuation = pendingEvidence !== void 0 && obligations.issues.length === 0 && firstImplementationSeq !== void 0 && correctiveFindingIds.length > 0;
39512
+ const correctiveContinuation = pendingEvidence !== void 0 && obligations.issues.length === 0 && firstImplementationSeq !== void 0 && (correctiveFindingIds.length > 0 || postReview?.status === "correction-required" && postReview.findings.some((finding) => finding.classification === "blocking"));
39494
39513
  if (pendingEvidence !== void 0 && !correctiveContinuation) {
39495
39514
  return applyRuntimeCertification(pendingEvidence, input2.specialistRuntime);
39496
39515
  }
@@ -39548,11 +39567,6 @@ function orchestrateMissionTeam(originalInput) {
39548
39567
  if (firstWriterSeq === void 0 || firstImplementationSeq === void 0 || lastWriterSeq === void 0 || postReview === void 0) {
39549
39568
  throw new Error("MISSION_TEAM_INVARIANT: writer completion boundary is missing");
39550
39569
  }
39551
- if (start.boundedReview && postReview.missingSpecialists.length === 0) {
39552
- const receiptReasons = boundedReceiptReasons(input2, start, reviewEvents);
39553
- if (receiptReasons.length > 0)
39554
- return stopped("degraded", postReview, baseVerdict, receiptReasons);
39555
- }
39556
39570
  if (postReview.readyForVerdict) {
39557
39571
  const completionEvidence = obligationStop(evidenceObligations(input2, expectedSource, "completion"), postReview, baseVerdict);
39558
39572
  if (completionEvidence !== void 0) {
@@ -41355,13 +41369,13 @@ function estimateTokens2(text8) {
41355
41369
  }
41356
41370
  var MAX_SOURCE_BYTES2 = 1024 * 1024;
41357
41371
  var MAX_DIRECTORY_ENTRIES = 1e4;
41358
- function within2(boundary, target) {
41359
- const path3 = relative(boundary, target);
41372
+ function within2(boundary2, target) {
41373
+ const path3 = relative(boundary2, target);
41360
41374
  return path3 === "" || !path3.startsWith("..") && !isAbsolute(path3);
41361
41375
  }
41362
- function sourceNames(boundary, directory) {
41376
+ function sourceNames(boundary2, directory) {
41363
41377
  if (!existsSync(directory)) return [];
41364
- const canonicalBoundary = realpathSync(boundary);
41378
+ const canonicalBoundary = realpathSync(boundary2);
41365
41379
  const metadata2 = lstatSync(directory);
41366
41380
  if (metadata2.isSymbolicLink()) {
41367
41381
  throw new Error(`GRAPH_SOURCE_PATH_ESCAPE: directory is a symlink: ${directory}`);
@@ -41376,13 +41390,13 @@ function sourceNames(boundary, directory) {
41376
41390
  }
41377
41391
  return names;
41378
41392
  }
41379
- function sourceText(boundary, path3) {
41393
+ function sourceText(boundary2, path3) {
41380
41394
  if (!existsSync(path3)) return void 0;
41381
41395
  const metadata2 = lstatSync(path3);
41382
41396
  if (metadata2.isSymbolicLink()) {
41383
41397
  throw new Error(`GRAPH_SOURCE_PATH_ESCAPE: source is a symlink: ${path3}`);
41384
41398
  }
41385
- const canonicalBoundary = realpathSync(boundary);
41399
+ const canonicalBoundary = realpathSync(boundary2);
41386
41400
  const canonicalPath = realpathSync(path3);
41387
41401
  if (!metadata2.isFile() || !within2(canonicalBoundary, canonicalPath)) {
41388
41402
  throw new Error(`GRAPH_SOURCE_PATH_ESCAPE: source leaves its declared root: ${path3}`);
@@ -41490,14 +41504,14 @@ function scanSourceTree(coreDir, packsDir) {
41490
41504
  }
41491
41505
  return { skills, agents: agents2, hooks, commands, packs, profiles, workflowDefs };
41492
41506
  }
41493
- function readMdDir(boundary, dir, rel) {
41494
- return readDir(boundary, dir, ".md", rel);
41507
+ function readMdDir(boundary2, dir, rel) {
41508
+ return readDir(boundary2, dir, ".md", rel);
41495
41509
  }
41496
- function readDir(boundary, dir, ext, rel) {
41510
+ function readDir(boundary2, dir, ext, rel) {
41497
41511
  if (!existsSync(dir)) return [];
41498
- return sourceNames(boundary, dir).filter((f2) => f2.endsWith(ext)).flatMap((f2) => {
41512
+ return sourceNames(boundary2, dir).filter((f2) => f2.endsWith(ext)).flatMap((f2) => {
41499
41513
  const full = join(dir, f2);
41500
- const text8 = sourceText(boundary, full);
41514
+ const text8 = sourceText(boundary2, full);
41501
41515
  return text8 === void 0 ? [] : [{ name: f2.slice(0, -ext.length), source: rel(full), text: text8 }];
41502
41516
  });
41503
41517
  }
@@ -44011,6 +44025,432 @@ function observeKeptTracked(projectRoot2) {
44011
44025
  });
44012
44026
  }
44013
44027
 
44028
+ // src/lib/lint-exclusion.ts
44029
+ init_esm_shims();
44030
+ var import_picomatch = __toESM(require_picomatch2());
44031
+
44032
+ // src/lib/void-migration.ts
44033
+ init_esm_shims();
44034
+ var EMPTY = Object.freeze({
44035
+ moved: [],
44036
+ conflicts: [],
44037
+ parked: [],
44038
+ gitignoreBlockRemoved: false
44039
+ });
44040
+ async function freeParkedName(target) {
44041
+ if (!existsSync(`${target}.legacy`)) return `${target}.legacy`;
44042
+ for (let attempt = 2; attempt < 100; attempt += 1) {
44043
+ const candidate = `${target}.legacy.${String(attempt)}`;
44044
+ if (!existsSync(candidate)) return candidate;
44045
+ }
44046
+ return `${target}.legacy.overflow`;
44047
+ }
44048
+ async function mergeInto(source2, destination) {
44049
+ const info = await stat(source2);
44050
+ if (!info.isDirectory()) {
44051
+ if (!existsSync(destination)) {
44052
+ await mkdir(join(destination, ".."), { recursive: true });
44053
+ await rename(source2, destination);
44054
+ return false;
44055
+ }
44056
+ await rename(source2, await freeParkedName(destination));
44057
+ return true;
44058
+ }
44059
+ await mkdir(destination, { recursive: true });
44060
+ let parked = false;
44061
+ for (const entry of await readdir(source2)) {
44062
+ if (await mergeInto(join(source2, entry), join(destination, entry))) parked = true;
44063
+ }
44064
+ await rm(source2, { recursive: true, force: true });
44065
+ return parked;
44066
+ }
44067
+ function planVoidMigration(root) {
44068
+ const movable = [];
44069
+ const conflicts = [];
44070
+ for (const entry of pendingMigrations(root)) {
44071
+ if (existsSync(voidMachinePath(root, entry))) conflicts.push(entry);
44072
+ else movable.push(entry);
44073
+ }
44074
+ return { movable, conflicts };
44075
+ }
44076
+ async function ownedInstallPaths(root) {
44077
+ const manifestPath = join(root, ...INSTALL_MANIFEST_PATH.split("/"));
44078
+ if (existsSync(manifestPath)) {
44079
+ try {
44080
+ const manifest = parseInstallManifest(await readFile(manifestPath, "utf8"));
44081
+ if (manifest !== void 0) {
44082
+ return new Set(manifest.files.map((file2) => file2.path));
44083
+ }
44084
+ } catch {
44085
+ }
44086
+ }
44087
+ const receipt2 = await readInstallReceipt(root);
44088
+ if (receipt2 === void 0) return void 0;
44089
+ return new Set(receipt2.files.map((file2) => file2.path));
44090
+ }
44091
+ async function ownedDerivedPaths(root) {
44092
+ const paths = await ownedInstallPaths(root);
44093
+ return paths === void 0 ? void 0 : new Set([...paths].filter(isOwnedDerived));
44094
+ }
44095
+ async function untrackDerived(root, dryRun = false) {
44096
+ const owned = await ownedDerivedPaths(root);
44097
+ if (owned === void 0) {
44098
+ return { untracked: [], error: "no readable install manifest or receipt \u2014 nothing here can be proven harness-owned" };
44099
+ }
44100
+ let listed;
44101
+ try {
44102
+ listed = execFileSync("git", ["ls-files", "-z", "--", ".void", ".claude", ".agents", ".codex"], {
44103
+ cwd: root,
44104
+ encoding: "utf8",
44105
+ stdio: ["ignore", "pipe", "ignore"]
44106
+ });
44107
+ } catch {
44108
+ return { untracked: [], error: "not a git repository, or git is unavailable" };
44109
+ }
44110
+ const untracked = listed.split("\0").filter((path3) => path3 !== "" && owned.has(path3.split("\\").join("/")));
44111
+ if (untracked.length === 0 || dryRun) return { untracked };
44112
+ try {
44113
+ for (let index = 0; index < untracked.length; index += 200) {
44114
+ execFileSync("git", ["rm", "--cached", "--quiet", "--", ...untracked.slice(index, index + 200)], {
44115
+ cwd: root,
44116
+ stdio: ["ignore", "ignore", "pipe"]
44117
+ });
44118
+ }
44119
+ } catch (error62) {
44120
+ return { untracked: [], error: error62 instanceof Error ? error62.message.split("\n")[0] ?? "git rm failed" : "git rm failed" };
44121
+ }
44122
+ return { untracked };
44123
+ }
44124
+ async function migrateVoidLayout(root, dryRun = false) {
44125
+ if (!existsSync(join(root, ".void"))) return EMPTY;
44126
+ const { movable, conflicts } = planVoidMigration(root);
44127
+ if (!dryRun) writeExcludeBlock(root, [...await ownedDerivedPaths(root) ?? []]);
44128
+ const gitignorePath = join(root, ".gitignore");
44129
+ const original = existsSync(gitignorePath) ? await readFile(gitignorePath, "utf8") : "";
44130
+ const stripped = stripManagedBlock(original);
44131
+ const gitignoreBlockRemoved = stripped !== original;
44132
+ const pending = [...movable, ...conflicts].sort();
44133
+ const failed2 = [];
44134
+ if (dryRun) return { moved: pending, conflicts: [], parked: [], gitignoreBlockRemoved };
44135
+ if (pending.length > 0) {
44136
+ await mkdir(voidMachineDir(root), { recursive: true });
44137
+ await mkdir(voidInstalledDir(root), { recursive: true });
44138
+ }
44139
+ const moved = [];
44140
+ const parked = [];
44141
+ for (const entry of pending) {
44142
+ try {
44143
+ const sources = [legacyVoidPath(root, entry), previousMachinePath(root, entry)].filter((source2) => existsSync(source2));
44144
+ if (ownershipOf(entry) === "derived") {
44145
+ for (const source2 of sources) await rm(source2, { recursive: true, force: true });
44146
+ if (sources.length > 0) moved.push(entry);
44147
+ continue;
44148
+ }
44149
+ let touched = false;
44150
+ for (const source2 of sources) {
44151
+ if (await mergeInto(source2, voidMachinePath(root, migratedName(entry)))) touched = true;
44152
+ }
44153
+ if (touched) parked.push(entry);
44154
+ moved.push(entry);
44155
+ } catch {
44156
+ failed2.push(entry);
44157
+ }
44158
+ }
44159
+ try {
44160
+ const previous = join(root, ".void", "local");
44161
+ if (existsSync(previous)) {
44162
+ for (const entry of await readdir(previous)) {
44163
+ await mergeInto(join(previous, entry), voidMachinePath(root, entry));
44164
+ }
44165
+ }
44166
+ } catch {
44167
+ }
44168
+ try {
44169
+ const previous = join(root, ".void", "local");
44170
+ if (existsSync(previous) && (await readdir(previous)).length === 0) {
44171
+ await rm(previous, { recursive: true, force: true });
44172
+ }
44173
+ } catch {
44174
+ }
44175
+ if (gitignoreBlockRemoved) await writeFile(gitignorePath, stripped);
44176
+ return { moved, conflicts: failed2.sort(), parked: parked.sort(), gitignoreBlockRemoved };
44177
+ }
44178
+
44179
+ // src/lib/lint-exclusion.ts
44180
+ var BIOME_FILES = ["biome.json", "biome.jsonc"];
44181
+ var KNIP_FILES = [
44182
+ "knip.json",
44183
+ "knip.jsonc",
44184
+ ".knip.json",
44185
+ ".knip.jsonc",
44186
+ "knip.ts",
44187
+ "knip.js",
44188
+ "knip.config.ts",
44189
+ "knip.config.js"
44190
+ ];
44191
+ var MAX_BIOME_CONFIG_READS = 32;
44192
+ var MAX_EXAMPLES = 5;
44193
+ var SCRIPT = /\.[cm]?[jt]sx?$/i;
44194
+ var BIOME_ASSET = /\.(?:[cm]?[jt]sx?|jsonc?|css|graphql|gql)$/i;
44195
+ var OTHER_LINTERS = [
44196
+ "eslint.config.js",
44197
+ "eslint.config.mjs",
44198
+ "eslint.config.ts",
44199
+ ".eslintrc.json",
44200
+ ".eslintrc.cjs",
44201
+ ".oxlintrc.json"
44202
+ ];
44203
+ async function inspectHarnessLintExclusion(root) {
44204
+ const checks = [];
44205
+ const biome = BIOME_FILES.find((name) => existsSync(join(root, name)));
44206
+ const knip = KNIP_FILES.find((name) => existsSync(join(root, name)));
44207
+ const other = OTHER_LINTERS.find((name) => existsSync(join(root, name)));
44208
+ const packageKnip = knip === void 0 ? await readPackageKnip(root) : void 0;
44209
+ if (biome === void 0 && knip === void 0 && packageKnip === void 0 && other === void 0) {
44210
+ return [{ name: "lint boundary", ok: true, status: "pass", message: "no analyzer config found" }];
44211
+ }
44212
+ const owned = await analyzerPaths(root);
44213
+ if (biome !== void 0) {
44214
+ const scope = await resolveBiomeIncludes(root, biome);
44215
+ checks.push(owned.kind === "failure" ? manual("lint boundary", biome, owned.reason) : scope.kind === "failure" ? manual("lint boundary", biome, scope.reason) : inspectBiome(biome, owned.paths, scope.includes));
44216
+ } else if (other !== void 0) {
44217
+ checks.push(manual("lint boundary", other, "this analyzer configuration needs manual inspection"));
44218
+ }
44219
+ if (knip !== void 0 || packageKnip !== void 0) {
44220
+ const file2 = knip ?? "package.json";
44221
+ checks.push(owned.kind === "failure" ? manual("knip boundary", file2, owned.reason) : await inspectKnip(root, file2, owned.paths.filter((path3) => SCRIPT.test(path3)), packageKnip));
44222
+ }
44223
+ return checks;
44224
+ }
44225
+ async function analyzerPaths(root) {
44226
+ const owned = await ownedInstallPaths(root);
44227
+ if (owned === void 0) return { kind: "failure", reason: "ownership unknown: no valid manifest or receipt" };
44228
+ const paths = [];
44229
+ try {
44230
+ const canonicalRoot = await realpath(root);
44231
+ for (const path3 of [...owned].sort()) {
44232
+ if (isCoOwned(path3) || classifyMaterialized(path3) !== "derived" || !BIOME_ASSET.test(path3)) continue;
44233
+ const full = join(root, path3);
44234
+ if (!existsSync(full)) continue;
44235
+ if (!isInside(canonicalRoot, await realpath(full))) {
44236
+ return { kind: "failure", reason: `owned path resolves outside the project: ${path3}` };
44237
+ }
44238
+ if ((await lstat(full)).isFile()) paths.push(path3);
44239
+ }
44240
+ } catch {
44241
+ return { kind: "failure", reason: "cannot inspect owned analyzer files" };
44242
+ }
44243
+ return { kind: "paths", paths };
44244
+ }
44245
+ function inspectBiome(file2, paths, includes) {
44246
+ const exposed = [];
44247
+ for (const path3 of paths) {
44248
+ const scope = harnessCanEnter(path3, includes);
44249
+ if (scope.kind === "failure") return manual("lint boundary", file2, scope.reason);
44250
+ if (scope.included) exposed.push(path3);
44251
+ }
44252
+ return boundary("lint boundary", file2, exposed, "files.includes", true);
44253
+ }
44254
+ async function readPackageKnip(root) {
44255
+ if (!existsSync(join(root, "package.json"))) return void 0;
44256
+ const parsed = await readAnalyzerConfig(root, "package.json");
44257
+ return parsed.kind === "parsed" && isRecord6(parsed.value) ? parsed.value.knip : void 0;
44258
+ }
44259
+ async function readAnalyzerConfig(root, file2) {
44260
+ try {
44261
+ const canonicalRoot = await realpath(root);
44262
+ const path3 = await realpath(join(root, file2));
44263
+ if (!isInside(canonicalRoot, path3)) return { kind: "failure", reason: "config resolves outside the project" };
44264
+ return { kind: "parsed", value: JSON.parse(await readFile(path3, "utf8")) };
44265
+ } catch {
44266
+ return { kind: "failure", reason: "config is unreadable or not plain JSON" };
44267
+ }
44268
+ }
44269
+ async function inspectKnip(root, file2, paths, embedded) {
44270
+ if (!file2.endsWith(".json") && !file2.endsWith(".jsonc")) {
44271
+ return manual("knip boundary", file2, "executable configuration is not evaluated");
44272
+ }
44273
+ const read = embedded === void 0 ? await readAnalyzerConfig(root, file2) : { kind: "parsed", value: embedded };
44274
+ if (read.kind === "failure") return manual("knip boundary", file2, read.reason);
44275
+ if (!isRecord6(read.value)) return manual("knip boundary", file2, "config must be an object");
44276
+ const config2 = read.value;
44277
+ const unsupported = Object.keys(config2).some((key) => !["$schema", "ignore", "ignoreFiles"].includes(key));
44278
+ const ignore = stringArray(config2.ignore);
44279
+ const unused = stringArray(config2.ignoreFiles);
44280
+ if (unsupported || ignore === "invalid" || unused === "invalid" || [...ignore ?? [], ...unused ?? []].some((pattern2) => pattern2.startsWith("!") || pattern2.endsWith("!") || pattern2.trim() === "")) {
44281
+ return manual("knip boundary", file2, "unsupported static config or mode-specific patterns; inspect manually");
44282
+ }
44283
+ try {
44284
+ const matches = (0, import_picomatch.default)([...ignore ?? []], { dot: true });
44285
+ const check3 = boundary(
44286
+ "knip boundary",
44287
+ file2,
44288
+ paths.filter((path3) => !matches(path3)),
44289
+ file2 === "package.json" ? "knip.ignore" : "ignore",
44290
+ false
44291
+ );
44292
+ return unused !== void 0 && check3.status === "advisory" ? { ...check3, message: `${check3.message}; ignoreFiles suppresses unused files only` } : check3;
44293
+ } catch {
44294
+ return manual("knip boundary", file2, "invalid ignore patterns");
44295
+ }
44296
+ }
44297
+ function boundary(name, file2, exposed, field11, negate) {
44298
+ if (exposed.length === 0) return { name, ok: true, status: "pass", message: `${file2}: no owned analyzer files exposed` };
44299
+ const sample = exposed.slice(0, MAX_EXAMPLES);
44300
+ const patterns2 = sample.map((path3) => `\`${negate ? "!" : ""}${path3}\``).join(", ");
44301
+ const remainder = exposed.length > MAX_EXAMPLES ? `; inspect the remaining ${exposed.length - MAX_EXAMPLES} owned files in the install manifest` : "";
44302
+ return {
44303
+ name,
44304
+ ok: true,
44305
+ status: "advisory",
44306
+ message: `${file2}: ${exposed.length} owned file(s) lack an explicit analyzer exclusion: ${sample.join(", ")}`,
44307
+ fix: `review ${field11} in ${file2}: exclude ${patterns2}${remainder}` + (negate ? " (keep a positive pattern such as `**` before exclusions; a lone negation matches nothing in Biome)" : "") + "; keep project-owned neighbors in scope"
44308
+ };
44309
+ }
44310
+ async function resolveBiomeIncludes(projectRoot2, configName) {
44311
+ let canonicalRoot;
44312
+ try {
44313
+ canonicalRoot = await realpath(projectRoot2);
44314
+ } catch {
44315
+ return { kind: "failure", reason: "cannot read the project root" };
44316
+ }
44317
+ return readBiomeIncludes(canonicalRoot, join(canonicalRoot, configName), /* @__PURE__ */ new Set(), {
44318
+ remaining: MAX_BIOME_CONFIG_READS
44319
+ });
44320
+ }
44321
+ async function readBiomeIncludes(projectRoot2, configPath, ancestors, budget) {
44322
+ if (budget.remaining === 0) {
44323
+ return { kind: "failure", reason: `extends chain exceeds ${MAX_BIOME_CONFIG_READS} config reads` };
44324
+ }
44325
+ budget.remaining -= 1;
44326
+ const boundedPath = resolve(configPath);
44327
+ if (!isInside(projectRoot2, boundedPath)) {
44328
+ return { kind: "failure", reason: `extended config is outside the project: ${configPath}` };
44329
+ }
44330
+ let canonicalPath;
44331
+ let text8;
44332
+ try {
44333
+ canonicalPath = await realpath(boundedPath);
44334
+ if (!isInside(projectRoot2, canonicalPath)) {
44335
+ return { kind: "failure", reason: `extended config is outside the project: ${configPath}` };
44336
+ }
44337
+ text8 = await readFile(canonicalPath, "utf8");
44338
+ } catch {
44339
+ return { kind: "failure", reason: `cannot read extended config ${displayPath(projectRoot2, boundedPath)}` };
44340
+ }
44341
+ if (ancestors.has(canonicalPath)) {
44342
+ return { kind: "failure", reason: `extends cycle at ${displayPath(projectRoot2, canonicalPath)}` };
44343
+ }
44344
+ const parsed = parseBiomeConfig(text8, displayPath(projectRoot2, canonicalPath));
44345
+ if (parsed.kind === "failure") return parsed;
44346
+ const nextAncestors = new Set(ancestors);
44347
+ nextAncestors.add(canonicalPath);
44348
+ let inheritedIncludes;
44349
+ for (const extendedConfig of parsed.config.extendedConfigs) {
44350
+ const inherited = await readBiomeIncludes(
44351
+ projectRoot2,
44352
+ resolve(dirname(canonicalPath), extendedConfig),
44353
+ nextAncestors,
44354
+ budget
44355
+ );
44356
+ if (inherited.kind === "failure") return inherited;
44357
+ if (inherited.includes !== void 0) inheritedIncludes = inherited.includes;
44358
+ }
44359
+ return {
44360
+ kind: "resolved",
44361
+ includes: parsed.config.includes ?? inheritedIncludes
44362
+ };
44363
+ }
44364
+ function parseBiomeConfig(text8, file2) {
44365
+ let value;
44366
+ try {
44367
+ value = JSON.parse(text8);
44368
+ } catch {
44369
+ return { kind: "failure", reason: `${file2} is not plain JSON` };
44370
+ }
44371
+ if (!isRecord6(value)) return { kind: "failure", reason: `${file2} does not contain a JSON object` };
44372
+ const extendedConfigs = extendedConfigList(value.extends);
44373
+ if (extendedConfigs === "invalid") {
44374
+ return { kind: "failure", reason: `${file2} has an invalid extends value` };
44375
+ }
44376
+ const files = value.files;
44377
+ if (!isAbsent(files) && !isRecord6(files)) {
44378
+ return { kind: "failure", reason: `${file2} has an invalid files value` };
44379
+ }
44380
+ const includesValue = isRecord6(files) ? files.includes : void 0;
44381
+ const includes = stringArray(includesValue);
44382
+ if (includes === "invalid") {
44383
+ return { kind: "failure", reason: `${file2} has an invalid files.includes value` };
44384
+ }
44385
+ return {
44386
+ kind: "parsed",
44387
+ config: {
44388
+ extendedConfigs: extendedConfigs ?? [],
44389
+ includes
44390
+ }
44391
+ };
44392
+ }
44393
+ function extendedConfigList(value) {
44394
+ if (isAbsent(value)) return void 0;
44395
+ if (typeof value === "string") return [value];
44396
+ return stringArray(value);
44397
+ }
44398
+ function stringArray(value) {
44399
+ if (isAbsent(value)) return void 0;
44400
+ if (!Array.isArray(value) || !value.every((entry) => typeof entry === "string")) return "invalid";
44401
+ return value;
44402
+ }
44403
+ function harnessCanEnter(path3, includes) {
44404
+ if (includes === void 0) return { kind: "scope", included: true };
44405
+ let included = false;
44406
+ for (const entry of includes) {
44407
+ const parsed = parseInclude(entry);
44408
+ if (parsed === void 0) {
44409
+ return { kind: "failure", reason: `files.includes contains an empty pattern: ${JSON.stringify(entry)}` };
44410
+ }
44411
+ try {
44412
+ const matches = (0, import_picomatch.default)(parsed.pattern, { dot: true });
44413
+ const segments2 = path3.split("/");
44414
+ const candidates = segments2.map((_, index) => segments2.slice(0, index + 1).join("/"));
44415
+ if (candidates.some((candidate) => matches(candidate))) included = !parsed.excluded;
44416
+ } catch {
44417
+ return { kind: "failure", reason: `files.includes contains an invalid pattern: ${entry}` };
44418
+ }
44419
+ }
44420
+ return { kind: "scope", included };
44421
+ }
44422
+ function parseInclude(entry) {
44423
+ let pattern2 = entry.trim();
44424
+ const excluded = pattern2.startsWith("!");
44425
+ if (pattern2.startsWith("!!")) pattern2 = pattern2.slice(2);
44426
+ else if (excluded) pattern2 = pattern2.slice(1);
44427
+ if (pattern2.startsWith("./")) pattern2 = pattern2.slice(2);
44428
+ return pattern2 === "" ? void 0 : { excluded, pattern: pattern2 };
44429
+ }
44430
+ function isRecord6(value) {
44431
+ return Object.prototype.toString.call(value) === "[object Object]";
44432
+ }
44433
+ function isAbsent(value) {
44434
+ return value === void 0 || Object.prototype.toString.call(value) === "[object Null]";
44435
+ }
44436
+ function isInside(root, candidate) {
44437
+ const path3 = relative(root, candidate);
44438
+ return path3 === "" || !isAbsolute(path3) && path3 !== ".." && !path3.startsWith(`..${sep}`);
44439
+ }
44440
+ function displayPath(root, path3) {
44441
+ const displayed = relative(root, path3);
44442
+ return displayed === "" ? "." : displayed;
44443
+ }
44444
+ function manual(name, file2, reason2) {
44445
+ return {
44446
+ name,
44447
+ ok: true,
44448
+ status: "unknown",
44449
+ message: `${file2}: ${reason2}`,
44450
+ fix: "inspect analyzer scope manually for attested harness assets; keep project-owned files in scope"
44451
+ };
44452
+ }
44453
+
44014
44454
  // ../../node_modules/.pnpm/@clack+prompts@1.5.0/node_modules/@clack/prompts/dist/index.mjs
44015
44455
  init_esm_shims();
44016
44456
 
@@ -45770,7 +46210,7 @@ async function readOrUndefined2(path3) {
45770
46210
  return void 0;
45771
46211
  }
45772
46212
  }
45773
- function isRecord6(value) {
46213
+ function isRecord7(value) {
45774
46214
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
45775
46215
  }
45776
46216
  async function readHarnessMeta(skillDir) {
@@ -45778,7 +46218,7 @@ async function readHarnessMeta(skillDir) {
45778
46218
  if (text8 === void 0) return {};
45779
46219
  try {
45780
46220
  const parsed = (0, import_yaml4.parse)(text8);
45781
- if (isRecord6(parsed)) return parsed;
46221
+ if (isRecord7(parsed)) return parsed;
45782
46222
  } catch {
45783
46223
  }
45784
46224
  return {};
@@ -45981,184 +46421,6 @@ async function smokeInstalledHook(hookPath, runtime2) {
45981
46421
  }
45982
46422
  }
45983
46423
 
45984
- // src/lib/lint-exclusion.ts
45985
- init_esm_shims();
45986
- var import_picomatch = __toESM(require_picomatch2());
45987
- var HARNESS_LINT_EXCLUSION = "!.claude";
45988
- var BIOME_FILES = ["biome.json", "biome.jsonc"];
45989
- var HARNESS_PROBES = [".claude", ".claude/workflows/autopilot.workflow.js"];
45990
- var MAX_BIOME_CONFIG_READS = 32;
45991
- var OTHER_LINTERS = [
45992
- "eslint.config.js",
45993
- "eslint.config.mjs",
45994
- "eslint.config.ts",
45995
- ".eslintrc.json",
45996
- ".eslintrc.cjs",
45997
- ".oxlintrc.json"
45998
- ];
45999
- async function inspectHarnessLintExclusion(projectRoot2) {
46000
- const biome = BIOME_FILES.map((name) => join(projectRoot2, name)).find((path3) => existsSync(path3));
46001
- if (biome !== void 0) {
46002
- const name = relative(projectRoot2, biome);
46003
- const scope = await resolveBiomeIncludes(projectRoot2, name);
46004
- if (scope.kind === "failure") return manual(name, scope.reason);
46005
- const harnessScope = harnessCanEnter(scope.includes);
46006
- if (harnessScope.kind === "failure") return manual(name, harnessScope.reason);
46007
- if (!harnessScope.included) {
46008
- return { kind: "excluded", file: name };
46009
- }
46010
- return {
46011
- kind: "missing",
46012
- file: name,
46013
- instruction: `add \`${HARNESS_LINT_EXCLUSION}\` to files.includes in ${name} (keep a positive pattern such as \`**\` before it \u2014 a lone negation matches nothing in Biome)`
46014
- };
46015
- }
46016
- const other = OTHER_LINTERS.find((name) => existsSync(join(projectRoot2, name)));
46017
- if (other !== void 0) {
46018
- return manual(other, "this linter is configured in code");
46019
- }
46020
- return { kind: "no-linter" };
46021
- }
46022
- async function resolveBiomeIncludes(projectRoot2, configName) {
46023
- let canonicalRoot;
46024
- try {
46025
- canonicalRoot = await realpath(projectRoot2);
46026
- } catch {
46027
- return { kind: "failure", reason: "cannot read the project root" };
46028
- }
46029
- return readBiomeIncludes(canonicalRoot, join(canonicalRoot, configName), /* @__PURE__ */ new Set(), {
46030
- remaining: MAX_BIOME_CONFIG_READS
46031
- });
46032
- }
46033
- async function readBiomeIncludes(projectRoot2, configPath, ancestors, budget) {
46034
- if (budget.remaining === 0) {
46035
- return { kind: "failure", reason: `extends chain exceeds ${MAX_BIOME_CONFIG_READS} config reads` };
46036
- }
46037
- budget.remaining -= 1;
46038
- const boundedPath = resolve(configPath);
46039
- if (!isInside(projectRoot2, boundedPath)) {
46040
- return { kind: "failure", reason: `extended config is outside the project: ${configPath}` };
46041
- }
46042
- let canonicalPath;
46043
- let text8;
46044
- try {
46045
- canonicalPath = await realpath(boundedPath);
46046
- if (!isInside(projectRoot2, canonicalPath)) {
46047
- return { kind: "failure", reason: `extended config is outside the project: ${configPath}` };
46048
- }
46049
- text8 = await readFile(canonicalPath, "utf8");
46050
- } catch {
46051
- return { kind: "failure", reason: `cannot read extended config ${displayPath(projectRoot2, boundedPath)}` };
46052
- }
46053
- if (ancestors.has(canonicalPath)) {
46054
- return { kind: "failure", reason: `extends cycle at ${displayPath(projectRoot2, canonicalPath)}` };
46055
- }
46056
- const parsed = parseBiomeConfig(text8, displayPath(projectRoot2, canonicalPath));
46057
- if (parsed.kind === "failure") return parsed;
46058
- const nextAncestors = new Set(ancestors);
46059
- nextAncestors.add(canonicalPath);
46060
- let inheritedIncludes;
46061
- for (const extendedConfig of parsed.config.extendedConfigs) {
46062
- const inherited = await readBiomeIncludes(
46063
- projectRoot2,
46064
- resolve(dirname(canonicalPath), extendedConfig),
46065
- nextAncestors,
46066
- budget
46067
- );
46068
- if (inherited.kind === "failure") return inherited;
46069
- if (inherited.includes !== void 0) inheritedIncludes = inherited.includes;
46070
- }
46071
- return {
46072
- kind: "resolved",
46073
- includes: parsed.config.includes ?? inheritedIncludes
46074
- };
46075
- }
46076
- function parseBiomeConfig(text8, file2) {
46077
- let value;
46078
- try {
46079
- value = JSON.parse(text8);
46080
- } catch {
46081
- return { kind: "failure", reason: `${file2} is not plain JSON` };
46082
- }
46083
- if (!isRecord7(value)) return { kind: "failure", reason: `${file2} does not contain a JSON object` };
46084
- const extendedConfigs = extendedConfigList(value.extends);
46085
- if (extendedConfigs === "invalid") {
46086
- return { kind: "failure", reason: `${file2} has an invalid extends value` };
46087
- }
46088
- const files = value.files;
46089
- if (!isAbsent(files) && !isRecord7(files)) {
46090
- return { kind: "failure", reason: `${file2} has an invalid files value` };
46091
- }
46092
- const includesValue = isRecord7(files) ? files.includes : void 0;
46093
- const includes = stringArray(includesValue);
46094
- if (includes === "invalid") {
46095
- return { kind: "failure", reason: `${file2} has an invalid files.includes value` };
46096
- }
46097
- return {
46098
- kind: "parsed",
46099
- config: {
46100
- extendedConfigs: extendedConfigs ?? [],
46101
- includes
46102
- }
46103
- };
46104
- }
46105
- function extendedConfigList(value) {
46106
- if (isAbsent(value)) return void 0;
46107
- if (typeof value === "string") return [value];
46108
- return stringArray(value);
46109
- }
46110
- function stringArray(value) {
46111
- if (isAbsent(value)) return void 0;
46112
- if (!Array.isArray(value) || !value.every((entry) => typeof entry === "string")) return "invalid";
46113
- return value;
46114
- }
46115
- function harnessCanEnter(includes) {
46116
- if (includes === void 0) return { kind: "scope", included: true };
46117
- let included = false;
46118
- for (const entry of includes) {
46119
- const parsed = parseInclude(entry);
46120
- if (parsed === void 0) {
46121
- return { kind: "failure", reason: `files.includes contains an empty pattern: ${JSON.stringify(entry)}` };
46122
- }
46123
- try {
46124
- const matches = (0, import_picomatch.default)(parsed.pattern, { dot: true });
46125
- if (HARNESS_PROBES.some((probe) => matches(probe))) included = !parsed.excluded;
46126
- } catch {
46127
- return { kind: "failure", reason: `files.includes contains an invalid pattern: ${entry}` };
46128
- }
46129
- }
46130
- return { kind: "scope", included };
46131
- }
46132
- function parseInclude(entry) {
46133
- let pattern2 = entry.trim();
46134
- const excluded = pattern2.startsWith("!");
46135
- if (pattern2.startsWith("!!")) pattern2 = pattern2.slice(2);
46136
- else if (excluded) pattern2 = pattern2.slice(1);
46137
- if (pattern2.startsWith("./")) pattern2 = pattern2.slice(2);
46138
- return pattern2 === "" ? void 0 : { excluded, pattern: pattern2 };
46139
- }
46140
- function isRecord7(value) {
46141
- return Object.prototype.toString.call(value) === "[object Object]";
46142
- }
46143
- function isAbsent(value) {
46144
- return value === void 0 || Object.prototype.toString.call(value) === "[object Null]";
46145
- }
46146
- function isInside(root, candidate) {
46147
- const path3 = relative(root, candidate);
46148
- return path3 === "" || !isAbsolute(path3) && path3 !== ".." && !path3.startsWith(`..${sep}`);
46149
- }
46150
- function displayPath(root, path3) {
46151
- const displayed = relative(root, path3);
46152
- return displayed === "" ? "." : displayed;
46153
- }
46154
- function manual(file2, why2) {
46155
- return {
46156
- kind: "manual",
46157
- file: file2,
46158
- instruction: `${why2}: add \`${HARNESS_LINT_EXCLUSION}\` to ${file2} (after a positive pattern such as \`**\`) so the harness is not linted as project source`
46159
- };
46160
- }
46161
-
46162
46424
  // src/lib/plugin-cache.ts
46163
46425
  init_esm_shims();
46164
46426
  function wiredHooks(manifest) {
@@ -46712,14 +46974,10 @@ var claudeAdapter = {
46712
46974
  enabledPacks: ctx.enabledPacks,
46713
46975
  channel: ctx.source
46714
46976
  });
46715
- const lint = await inspectHarnessLintExclusion(ctx.installRoot);
46716
- const lintLine = lint.kind === "excluded" ? `${lint.file}: .claude excluded from lint` : lint.kind === "no-linter" ? "lint: no linter config found, nothing to exclude" : `lint: ${lint.file} lints .claude as project source`;
46717
- if (lint.kind === "missing" || lint.kind === "manual") nextSteps.push(lint.instruction);
46718
46977
  return {
46719
46978
  statusLines: [
46720
46979
  status3,
46721
- `CLAUDE.md: ${docResult}`,
46722
- lintLine
46980
+ `CLAUDE.md: ${docResult}`
46723
46981
  ],
46724
46982
  nextSteps
46725
46983
  };
@@ -47211,14 +47469,7 @@ function buildDefaultConfig(seed) {
47211
47469
  const config2 = {
47212
47470
  packs: {},
47213
47471
  stack: { ...seed.stack },
47214
- paths: {
47215
- business: "apps/*/src/**",
47216
- tests: "apps/*/src/**/*.test.{ts,tsx}",
47217
- spikes: "apps/*/scripts/spike-*",
47218
- serverActions: "apps/*/src/app/(api|actions)/**",
47219
- contracts: "apps/*/src/lib/contracts/**",
47220
- e2e: "apps/*/tests/e2e/**"
47221
- },
47472
+ paths: DEFAULT_PROJECT_PATHS,
47222
47473
  commands: commandsFor(seed.stack),
47223
47474
  modes: { tdd: "auto", codeReview: "auto" }
47224
47475
  };
@@ -47361,6 +47612,10 @@ async function init(args) {
47361
47612
  line(`${c.green(glyph.check)} ${c.dim("transaction".padEnd(18))}${prepared.receipt.files.length} owned files committed + receipt written`);
47362
47613
  claimOwnedPaths(projectRoot2, prepared.receipt.files.map((file2) => file2.path));
47363
47614
  reportHiddenByProject(projectRoot2);
47615
+ for (const check3 of await inspectHarnessLintExclusion(projectRoot2)) {
47616
+ line(`${c.dim(check3.name.padEnd(18))}${check3.message}`);
47617
+ if (check3.fix !== void 0) nextSteps.push(check3.fix);
47618
+ }
47364
47619
  if (keptByProject.length > 0) {
47365
47620
  line(`${c.yellow("!")} ${c.dim("kept".padEnd(18))}${keptByProject.length} skill(s) the project already had, left untouched`);
47366
47621
  for (const path3 of keptByProject.slice(0, 5)) line(c.dim(` ${path3}`));
@@ -48483,7 +48738,7 @@ var FROZEN_MARKER = /frozen legacy (?:snapshot|landing page)/i;
48483
48738
  var RECENT_LIMIT = 5;
48484
48739
  var MAX_TITLE = 200;
48485
48740
  var MAX_INPUT2 = 2e6;
48486
- var EMPTY = Object.freeze({
48741
+ var EMPTY2 = Object.freeze({
48487
48742
  format: "none",
48488
48743
  count: 0,
48489
48744
  recent: [],
@@ -48539,7 +48794,7 @@ function observeDecisions(input2) {
48539
48794
  liveMonolithEntries
48540
48795
  };
48541
48796
  }
48542
- if (monolithEntries.length === 0) return EMPTY;
48797
+ if (monolithEntries.length === 0) return EMPTY2;
48543
48798
  return {
48544
48799
  format: frozen ? "frozen-monolith" : "live-monolith",
48545
48800
  count: monolithEntries.length,
@@ -49189,149 +49444,6 @@ function judgeLayout(observation3) {
49189
49444
  ]);
49190
49445
  }
49191
49446
 
49192
- // src/lib/void-migration.ts
49193
- init_esm_shims();
49194
- var EMPTY2 = Object.freeze({
49195
- moved: [],
49196
- conflicts: [],
49197
- parked: [],
49198
- gitignoreBlockRemoved: false
49199
- });
49200
- async function freeParkedName(target) {
49201
- if (!existsSync(`${target}.legacy`)) return `${target}.legacy`;
49202
- for (let attempt = 2; attempt < 100; attempt += 1) {
49203
- const candidate = `${target}.legacy.${String(attempt)}`;
49204
- if (!existsSync(candidate)) return candidate;
49205
- }
49206
- return `${target}.legacy.overflow`;
49207
- }
49208
- async function mergeInto(source2, destination) {
49209
- const info = await stat(source2);
49210
- if (!info.isDirectory()) {
49211
- if (!existsSync(destination)) {
49212
- await mkdir(join(destination, ".."), { recursive: true });
49213
- await rename(source2, destination);
49214
- return false;
49215
- }
49216
- await rename(source2, await freeParkedName(destination));
49217
- return true;
49218
- }
49219
- await mkdir(destination, { recursive: true });
49220
- let parked = false;
49221
- for (const entry of await readdir(source2)) {
49222
- if (await mergeInto(join(source2, entry), join(destination, entry))) parked = true;
49223
- }
49224
- await rm(source2, { recursive: true, force: true });
49225
- return parked;
49226
- }
49227
- function planVoidMigration(root) {
49228
- const movable = [];
49229
- const conflicts = [];
49230
- for (const entry of pendingMigrations(root)) {
49231
- if (existsSync(voidMachinePath(root, entry))) conflicts.push(entry);
49232
- else movable.push(entry);
49233
- }
49234
- return { movable, conflicts };
49235
- }
49236
- async function ownedDerivedPaths(root) {
49237
- const manifestPath = join(root, ...INSTALL_MANIFEST_PATH.split("/"));
49238
- if (existsSync(manifestPath)) {
49239
- try {
49240
- const manifest = parseInstallManifest(await readFile(manifestPath, "utf8"));
49241
- if (manifest !== void 0) {
49242
- return new Set(manifest.files.map((file2) => file2.path).filter((path3) => isOwnedDerived(path3)));
49243
- }
49244
- } catch {
49245
- }
49246
- }
49247
- const receipt2 = await readInstallReceipt(root);
49248
- if (receipt2 === void 0) return void 0;
49249
- return new Set(receipt2.files.map((file2) => file2.path).filter((path3) => isOwnedDerived(path3)));
49250
- }
49251
- async function untrackDerived(root, dryRun = false) {
49252
- const owned = await ownedDerivedPaths(root);
49253
- if (owned === void 0) {
49254
- return { untracked: [], error: "no readable install manifest or receipt \u2014 nothing here can be proven harness-owned" };
49255
- }
49256
- let listed;
49257
- try {
49258
- listed = execFileSync("git", ["ls-files", "-z", "--", ".void", ".claude", ".agents", ".codex"], {
49259
- cwd: root,
49260
- encoding: "utf8",
49261
- stdio: ["ignore", "pipe", "ignore"]
49262
- });
49263
- } catch {
49264
- return { untracked: [], error: "not a git repository, or git is unavailable" };
49265
- }
49266
- const untracked = listed.split("\0").filter((path3) => path3 !== "" && owned.has(path3.split("\\").join("/")));
49267
- if (untracked.length === 0 || dryRun) return { untracked };
49268
- try {
49269
- for (let index = 0; index < untracked.length; index += 200) {
49270
- execFileSync("git", ["rm", "--cached", "--quiet", "--", ...untracked.slice(index, index + 200)], {
49271
- cwd: root,
49272
- stdio: ["ignore", "ignore", "pipe"]
49273
- });
49274
- }
49275
- } catch (error62) {
49276
- return { untracked: [], error: error62 instanceof Error ? error62.message.split("\n")[0] ?? "git rm failed" : "git rm failed" };
49277
- }
49278
- return { untracked };
49279
- }
49280
- async function migrateVoidLayout(root, dryRun = false) {
49281
- if (!existsSync(join(root, ".void"))) return EMPTY2;
49282
- const { movable, conflicts } = planVoidMigration(root);
49283
- if (!dryRun) writeExcludeBlock(root, [...await ownedDerivedPaths(root) ?? []]);
49284
- const gitignorePath = join(root, ".gitignore");
49285
- const original = existsSync(gitignorePath) ? await readFile(gitignorePath, "utf8") : "";
49286
- const stripped = stripManagedBlock(original);
49287
- const gitignoreBlockRemoved = stripped !== original;
49288
- const pending = [...movable, ...conflicts].sort();
49289
- const failed2 = [];
49290
- if (dryRun) return { moved: pending, conflicts: [], parked: [], gitignoreBlockRemoved };
49291
- if (pending.length > 0) {
49292
- await mkdir(voidMachineDir(root), { recursive: true });
49293
- await mkdir(voidInstalledDir(root), { recursive: true });
49294
- }
49295
- const moved = [];
49296
- const parked = [];
49297
- for (const entry of pending) {
49298
- try {
49299
- const sources = [legacyVoidPath(root, entry), previousMachinePath(root, entry)].filter((source2) => existsSync(source2));
49300
- if (ownershipOf(entry) === "derived") {
49301
- for (const source2 of sources) await rm(source2, { recursive: true, force: true });
49302
- if (sources.length > 0) moved.push(entry);
49303
- continue;
49304
- }
49305
- let touched = false;
49306
- for (const source2 of sources) {
49307
- if (await mergeInto(source2, voidMachinePath(root, migratedName(entry)))) touched = true;
49308
- }
49309
- if (touched) parked.push(entry);
49310
- moved.push(entry);
49311
- } catch {
49312
- failed2.push(entry);
49313
- }
49314
- }
49315
- try {
49316
- const previous = join(root, ".void", "local");
49317
- if (existsSync(previous)) {
49318
- for (const entry of await readdir(previous)) {
49319
- await mergeInto(join(previous, entry), voidMachinePath(root, entry));
49320
- }
49321
- }
49322
- } catch {
49323
- }
49324
- try {
49325
- const previous = join(root, ".void", "local");
49326
- if (existsSync(previous) && (await readdir(previous)).length === 0) {
49327
- await rm(previous, { recursive: true, force: true });
49328
- }
49329
- } catch {
49330
- }
49331
- if (gitignoreBlockRemoved) await writeFile(gitignorePath, stripped);
49332
- return { moved, conflicts: failed2.sort(), parked: parked.sort(), gitignoreBlockRemoved };
49333
- }
49334
-
49335
49447
  // src/commands/self-host.ts
49336
49448
  init_esm_shims();
49337
49449
 
@@ -50268,18 +50380,7 @@ async function doctor(args) {
50268
50380
  });
50269
50381
  }
50270
50382
  }
50271
- if (claudeDetected) {
50272
- const lint = await inspectHarnessLintExclusion(root);
50273
- checks.push(
50274
- lint.kind === "excluded" ? { name: "lint boundary", ok: true, message: `${lint.file}: .claude excluded from project lint` } : lint.kind === "no-linter" ? { name: "lint boundary", ok: true, message: "no linter config found, nothing to exclude" } : {
50275
- name: "lint boundary",
50276
- ok: true,
50277
- status: "advisory",
50278
- message: `${lint.file} lints .claude as project source; harness files are written in engine formats a JS parser rejects`,
50279
- fix: lint.instruction
50280
- }
50281
- );
50282
- }
50383
+ checks.push(...await inspectHarnessLintExclusion(root));
50283
50384
  checks.push(checkEnforceWorkflow(root));
50284
50385
  if (claudeDetected && marketplaceInstall) {
50285
50386
  if (!skipRemote) {
@@ -50765,131 +50866,6 @@ async function hydrate(args) {
50765
50866
 
50766
50867
  // src/commands/check.ts
50767
50868
  init_esm_shims();
50768
- var GH_REMOTE = {
50769
- fetchRemoteMarketplace,
50770
- fetchPinnedPluginVersion,
50771
- fetchRemotePhilosophy
50772
- };
50773
- async function check2(args, options2 = {}) {
50774
- const doctrine = args.includes("--doctrine");
50775
- const remote = options2.remote ?? GH_REMOTE;
50776
- const roots = resolveProjectRoots(options2.cwd);
50777
- const installRoot = roots.installRoot;
50778
- const where = remedyPrefix(roots);
50779
- const repo = await resolveMarketplaceRepo(installRoot);
50780
- const local = await readLocalConfig(installRoot);
50781
- banner("check");
50782
- meta3("marketplace", repo);
50783
- blank();
50784
- const marketplace = remote.fetchRemoteMarketplace(repo);
50785
- if (!marketplace.ok) {
50786
- status(`could not fetch remote marketplace: ${marketplace.error}`, "err");
50787
- line(c.dim("verify `gh auth status` and that you have access to the repo."));
50788
- process.exit(1);
50789
- }
50790
- const drift = reportVersionDrift(local, marketplace.value, repo, remote);
50791
- if (doctrine) {
50792
- blank();
50793
- await reportDoctrineDrift(installRoot, where, marketplace.value, repo, remote);
50794
- }
50795
- if (drift > 0) {
50796
- footer(
50797
- `${c.yellow(`${drift} plugin${drift > 1 ? "s" : ""} behind`)} ${glyph.emdash} run ${where}${c.bold(
50798
- `${PRODUCT_COMMAND} update`
50799
- )} ${c.dim("(refreshes the plugin cache + bumps the pins this check measures), then restart Claude Code")}`
50800
- );
50801
- } else {
50802
- footer(c.dim("all up to date"));
50803
- }
50804
- }
50805
- async function resolveMarketplaceRepo(installRoot) {
50806
- const settings = await readSettings(settingsPathFor(installRoot));
50807
- const entry = settings.extraKnownMarketplaces?.[MARKETPLACE_NAME];
50808
- if (entry && typeof entry === "object") {
50809
- const source2 = entry.source;
50810
- if (source2?.repo) return source2.repo;
50811
- }
50812
- return MARKETPLACE_REPO;
50813
- }
50814
- async function readLocalConfig(installRoot) {
50815
- const configPath = join(installRoot, ".void", "config.json");
50816
- if (!existsSync(configPath)) return {};
50817
- try {
50818
- return JSON.parse(await readFile(configPath, "utf8"));
50819
- } catch {
50820
- return {};
50821
- }
50822
- }
50823
- function reportVersionDrift(local, marketplace, marketplaceRepo, remote) {
50824
- const localVersions = {
50825
- [CORE_PLUGIN_NAME]: local.core
50826
- };
50827
- for (const pack2 of PACKS) {
50828
- localVersions[pack2.name] = local.packs?.[`@voidcorp/${pack2.name}`];
50829
- }
50830
- let drift = 0;
50831
- for (const plugin of marketplace.plugins) {
50832
- const declaredRaw = localVersions[plugin.name];
50833
- const localStr = declaredRaw ? normalizeVersion(declaredRaw) : glyph.emdash;
50834
- const remoteFetch = remote.fetchPinnedPluginVersion(plugin, marketplaceRepo);
50835
- if (!remoteFetch.ok) {
50836
- row({ mark: "info", label: plugin.name, versions: [localStr, glyph.emdash], suffix: c.dim(remoteFetch.error) });
50837
- continue;
50838
- }
50839
- const remoteStr = remoteFetch.value;
50840
- if (!declaredRaw) {
50841
- row({
50842
- mark: "info",
50843
- label: plugin.name,
50844
- versions: [localStr, remoteStr],
50845
- suffix: c.dim("not installed")
50846
- });
50847
- } else if (compareVersions(localStr, remoteStr) < 0) {
50848
- drift += 1;
50849
- row({
50850
- mark: "warn",
50851
- label: plugin.name,
50852
- versions: [localStr, remoteStr],
50853
- suffix: c.yellow("update available")
50854
- });
50855
- } else {
50856
- row({
50857
- mark: "ok",
50858
- label: plugin.name,
50859
- versions: [localStr, remoteStr],
50860
- suffix: c.dim("up to date")
50861
- });
50862
- }
50863
- }
50864
- return drift;
50865
- }
50866
- async function reportDoctrineDrift(installRoot, where, marketplace, marketplaceRepo, remote) {
50867
- const migrated = join(installRoot, ".void", "installed", "PHILOSOPHY.md");
50868
- const localPath = existsSync(migrated) ? migrated : join(installRoot, ".void", "PHILOSOPHY.md");
50869
- if (!existsSync(localPath)) {
50870
- status(`PHILOSOPHY.md missing locally \u2014 run ${where}\`${PRODUCT_COMMAND} init\` to install.`, "warn");
50871
- return;
50872
- }
50873
- const localText = await readFile(localPath, "utf8");
50874
- const fetched = remote.fetchRemotePhilosophy(marketplace, CORE_PLUGIN_NAME, marketplaceRepo);
50875
- if (!fetched.ok) {
50876
- status(`could not fetch remote PHILOSOPHY.md: ${fetched.error}`, "warn");
50877
- return;
50878
- }
50879
- if (normalizeNewlines(localText) === normalizeNewlines(fetched.value)) {
50880
- status(`PHILOSOPHY.md ${c.dim("in sync")}`);
50881
- return;
50882
- }
50883
- const localLines = localText.split("\n").length;
50884
- const remoteLines = fetched.value.split("\n").length;
50885
- status(
50886
- `PHILOSOPHY.md drift (local ${localLines}L, remote ${remoteLines}L) \u2014 run ${where}\`${PRODUCT_COMMAND} init\` to overwrite`,
50887
- "warn"
50888
- );
50889
- }
50890
- function normalizeNewlines(s) {
50891
- return s.replace(/\r\n/g, "\n").trimEnd();
50892
- }
50893
50869
 
50894
50870
  // src/commands/update.ts
50895
50871
  init_esm_shims();
@@ -51149,7 +51125,7 @@ async function update(args) {
51149
51125
  }
51150
51126
  banner("update");
51151
51127
  renderLegacyRegistryNotice(legacyRegistryNotice);
51152
- const repo = await resolveMarketplaceRepo2(projectRoot2);
51128
+ const repo = await resolveMarketplaceRepo(projectRoot2);
51153
51129
  meta3("marketplace", repo);
51154
51130
  const remote = fetchRemoteMarketplace(repo);
51155
51131
  if (!remote.ok) {
@@ -51505,7 +51481,7 @@ async function bumpPins(projectRoot2, head, dryRun) {
51505
51481
  `);
51506
51482
  return changes.length;
51507
51483
  }
51508
- async function resolveMarketplaceRepo2(projectRoot2) {
51484
+ async function resolveMarketplaceRepo(projectRoot2) {
51509
51485
  const settings = await readSettings(settingsPathFor(projectRoot2));
51510
51486
  const entry = settings.extraKnownMarketplaces?.[MARKETPLACE_NAME];
51511
51487
  if (entry && typeof entry === "object") {
@@ -51515,6 +51491,166 @@ async function resolveMarketplaceRepo2(projectRoot2) {
51515
51491
  return MARKETPLACE_REPO;
51516
51492
  }
51517
51493
 
51494
+ // src/commands/check.ts
51495
+ var GH_REMOTE = {
51496
+ fetchRemoteMarketplace,
51497
+ fetchPinnedPluginVersion,
51498
+ fetchRemotePhilosophy
51499
+ };
51500
+ async function check2(args, options2 = {}) {
51501
+ const doctrine = args.includes("--doctrine");
51502
+ const remote = options2.remote ?? GH_REMOTE;
51503
+ const roots = resolveProjectRoots(options2.cwd);
51504
+ const installRoot = roots.installRoot;
51505
+ const where = remedyPrefix(roots);
51506
+ const receipt2 = await readInstallReceipt(installRoot);
51507
+ const hasManifest = existsSync(join(installRoot, INSTALL_MANIFEST_PATH));
51508
+ const unknownChannel = receipt2 === void 0 && !hasManifest && await receiptEvidenceExists(installRoot);
51509
+ const route = updateRouteFor(receipt2, hasManifest);
51510
+ banner("check");
51511
+ if (unknownChannel) {
51512
+ status("unknown (install receipt is unreadable or invalid; installation channel cannot be established)", "warn");
51513
+ if (!doctrine) return;
51514
+ blank();
51515
+ } else if (route !== "marketplace") {
51516
+ const installed = receipt2?.version ?? readInstallManifest(installRoot)?.version ?? "unknown";
51517
+ const freshness = await (options2.resolveFreshness ?? resolveFreshness)({
51518
+ installed,
51519
+ env: process.env,
51520
+ now: Date.now(),
51521
+ cwd: installRoot
51522
+ });
51523
+ const published2 = publishedVersionCheck(freshness, "local");
51524
+ meta3("source", "bundled local package");
51525
+ blank();
51526
+ status(published2.message, published2.status === "pass" ? "ok" : "warn");
51527
+ if (published2.fix !== void 0) line(c.dim(`${where}${published2.fix}`));
51528
+ if (!doctrine) return;
51529
+ blank();
51530
+ }
51531
+ const repo = await resolveMarketplaceRepo2(installRoot);
51532
+ const local = await readLocalConfig(installRoot);
51533
+ meta3("marketplace", repo);
51534
+ blank();
51535
+ const marketplace = remote.fetchRemoteMarketplace(repo);
51536
+ if (!marketplace.ok) {
51537
+ status(`could not fetch remote marketplace: ${marketplace.error}`, "err");
51538
+ line(c.dim("verify `gh auth status` and that you have access to the repo."));
51539
+ process.exit(1);
51540
+ }
51541
+ const drift = route === "marketplace" && !unknownChannel ? reportVersionDrift(local, marketplace.value, repo, remote) : 0;
51542
+ if (doctrine) {
51543
+ blank();
51544
+ await reportDoctrineDrift(installRoot, where, marketplace.value, repo, remote);
51545
+ }
51546
+ if (route !== "marketplace" || unknownChannel) return;
51547
+ if (drift > 0) {
51548
+ footer(
51549
+ `${c.yellow(`${drift} plugin${drift > 1 ? "s" : ""} behind`)} ${glyph.emdash} run ${where}${c.bold(
51550
+ `${PRODUCT_COMMAND} update`
51551
+ )} ${c.dim("(refreshes the plugin cache + bumps the pins this check measures), then restart Claude Code")}`
51552
+ );
51553
+ } else {
51554
+ footer(c.dim("all up to date"));
51555
+ }
51556
+ }
51557
+ async function receiptEvidenceExists(root) {
51558
+ try {
51559
+ await lstat(voidReadPath(root, "receipts", "install-v1.json"));
51560
+ return true;
51561
+ } catch (error62) {
51562
+ return !(error62 instanceof Error && "code" in error62 && error62.code === "ENOENT");
51563
+ }
51564
+ }
51565
+ async function resolveMarketplaceRepo2(installRoot) {
51566
+ const settings = await readSettings(settingsPathFor(installRoot));
51567
+ const entry = settings.extraKnownMarketplaces?.[MARKETPLACE_NAME];
51568
+ if (entry && typeof entry === "object") {
51569
+ const source2 = entry.source;
51570
+ if (source2?.repo) return source2.repo;
51571
+ }
51572
+ return MARKETPLACE_REPO;
51573
+ }
51574
+ async function readLocalConfig(installRoot) {
51575
+ const configPath = join(installRoot, ".void", "config.json");
51576
+ if (!existsSync(configPath)) return {};
51577
+ try {
51578
+ return JSON.parse(await readFile(configPath, "utf8"));
51579
+ } catch {
51580
+ return {};
51581
+ }
51582
+ }
51583
+ function reportVersionDrift(local, marketplace, marketplaceRepo, remote) {
51584
+ const localVersions = {
51585
+ [CORE_PLUGIN_NAME]: local.core
51586
+ };
51587
+ for (const pack2 of PACKS) {
51588
+ localVersions[pack2.name] = local.packs?.[`@voidcorp/${pack2.name}`];
51589
+ }
51590
+ let drift = 0;
51591
+ for (const plugin of marketplace.plugins) {
51592
+ const declaredRaw = localVersions[plugin.name];
51593
+ const localStr = declaredRaw ? normalizeVersion(declaredRaw) : glyph.emdash;
51594
+ const remoteFetch = remote.fetchPinnedPluginVersion(plugin, marketplaceRepo);
51595
+ if (!remoteFetch.ok) {
51596
+ row({ mark: "info", label: plugin.name, versions: [localStr, glyph.emdash], suffix: c.dim(remoteFetch.error) });
51597
+ continue;
51598
+ }
51599
+ const remoteStr = remoteFetch.value;
51600
+ if (!declaredRaw) {
51601
+ row({
51602
+ mark: "info",
51603
+ label: plugin.name,
51604
+ versions: [localStr, remoteStr],
51605
+ suffix: c.dim("not installed")
51606
+ });
51607
+ } else if (compareVersions(localStr, remoteStr) < 0) {
51608
+ drift += 1;
51609
+ row({
51610
+ mark: "warn",
51611
+ label: plugin.name,
51612
+ versions: [localStr, remoteStr],
51613
+ suffix: c.yellow("update available")
51614
+ });
51615
+ } else {
51616
+ row({
51617
+ mark: "ok",
51618
+ label: plugin.name,
51619
+ versions: [localStr, remoteStr],
51620
+ suffix: c.dim("up to date")
51621
+ });
51622
+ }
51623
+ }
51624
+ return drift;
51625
+ }
51626
+ async function reportDoctrineDrift(installRoot, where, marketplace, marketplaceRepo, remote) {
51627
+ const migrated = join(installRoot, ".void", "installed", "PHILOSOPHY.md");
51628
+ const localPath = existsSync(migrated) ? migrated : join(installRoot, ".void", "PHILOSOPHY.md");
51629
+ if (!existsSync(localPath)) {
51630
+ status(`PHILOSOPHY.md missing locally \u2014 run ${where}\`${PRODUCT_COMMAND} init\` to install.`, "warn");
51631
+ return;
51632
+ }
51633
+ const localText = await readFile(localPath, "utf8");
51634
+ const fetched = remote.fetchRemotePhilosophy(marketplace, CORE_PLUGIN_NAME, marketplaceRepo);
51635
+ if (!fetched.ok) {
51636
+ status(`could not fetch remote PHILOSOPHY.md: ${fetched.error}`, "warn");
51637
+ return;
51638
+ }
51639
+ if (normalizeNewlines(localText) === normalizeNewlines(fetched.value)) {
51640
+ status(`PHILOSOPHY.md ${c.dim("in sync")}`);
51641
+ return;
51642
+ }
51643
+ const localLines = localText.split("\n").length;
51644
+ const remoteLines = fetched.value.split("\n").length;
51645
+ status(
51646
+ `PHILOSOPHY.md drift (local ${localLines}L, remote ${remoteLines}L) \u2014 run ${where}\`${PRODUCT_COMMAND} init\` to overwrite`,
51647
+ "warn"
51648
+ );
51649
+ }
51650
+ function normalizeNewlines(s) {
51651
+ return s.replace(/\r\n/g, "\n").trimEnd();
51652
+ }
51653
+
51518
51654
  // src/commands/autopilot.ts
51519
51655
  init_esm_shims();
51520
51656
 
@@ -52489,9 +52625,9 @@ function resultHookWiring(settings) {
52489
52625
  return document.success ? stopWiring(document.data.hooks) : "missing";
52490
52626
  }
52491
52627
  function collect(stream2, onLimit) {
52492
- return new Promise((resolve43) => {
52628
+ return new Promise((resolve45) => {
52493
52629
  if (stream2 === null) {
52494
- resolve43("");
52630
+ resolve45("");
52495
52631
  return;
52496
52632
  }
52497
52633
  const chunks = [];
@@ -52504,18 +52640,18 @@ function collect(stream2, onLimit) {
52504
52640
  else
52505
52641
  chunks.push(bytes);
52506
52642
  });
52507
- stream2.once("close", () => resolve43(Buffer.concat(chunks).toString("utf8")));
52508
- stream2.once("error", () => resolve43(Buffer.concat(chunks).toString("utf8")));
52643
+ stream2.once("close", () => resolve45(Buffer.concat(chunks).toString("utf8")));
52644
+ stream2.once("error", () => resolve45(Buffer.concat(chunks).toString("utf8")));
52509
52645
  });
52510
52646
  }
52511
52647
  function runBounded(config2, args, cwd, timeoutMs) {
52512
52648
  const spawn4 = config2.spawn ?? ((executable2, argv, options2) => spawn(executable2, argv, options2));
52513
- return new Promise((resolve43) => {
52649
+ return new Promise((resolve45) => {
52514
52650
  let child;
52515
52651
  try {
52516
52652
  child = spawn4(config2.executable, args, { cwd, env: config2.env, shell: false, stdio: ["ignore", "pipe", "pipe"] });
52517
52653
  } catch (error62) {
52518
- resolve43({ kind: "not-started", cause: error62 instanceof Error ? error62.message : String(error62) });
52654
+ resolve45({ kind: "not-started", cause: error62 instanceof Error ? error62.message : String(error62) });
52519
52655
  return;
52520
52656
  }
52521
52657
  let timedOut = false;
@@ -52530,11 +52666,11 @@ function runBounded(config2, args, cwd, timeoutMs) {
52530
52666
  const output2 = Promise.all([collect(child.stdout, terminate), collect(child.stderr, terminate)]);
52531
52667
  child.once("error", (error62) => {
52532
52668
  clearTimeout(timer);
52533
- resolve43({ kind: "not-started", cause: error62 instanceof Error ? error62.message : String(error62) });
52669
+ resolve45({ kind: "not-started", cause: error62 instanceof Error ? error62.message : String(error62) });
52534
52670
  });
52535
52671
  child.once("close", (code2) => {
52536
52672
  clearTimeout(timer);
52537
- void output2.then(([stdout, stderr]) => resolve43(timedOut ? { kind: "timed-out" } : { kind: "exited", code: typeof code2 === "number" ? code2 : void 0, stdout, stderr }));
52673
+ void output2.then(([stdout, stderr]) => resolve45(timedOut ? { kind: "timed-out" } : { kind: "exited", code: typeof code2 === "number" ? code2 : void 0, stdout, stderr }));
52538
52674
  });
52539
52675
  });
52540
52676
  }
@@ -52950,7 +53086,7 @@ async function socketRefusal(socket) {
52950
53086
  return void 0;
52951
53087
  }
52952
53088
  function connect(socket, limits) {
52953
- return new Promise((resolve43) => {
53089
+ return new Promise((resolve45) => {
52954
53090
  const ws = new wrapper_default(`ws+unix://${socket}:/`, {
52955
53091
  perMessageDeflate: false,
52956
53092
  handshakeTimeout: limits.timeouts.callMs,
@@ -52984,13 +53120,13 @@ function connect(socket, limits) {
52984
53120
  if (error62.code === "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH") {
52985
53121
  closeAll(`a reply of the Codex daemon exceeded the ${String(limits.maxFrameBytes)}-byte frame bound`);
52986
53122
  }
52987
- resolve43({
53123
+ resolve45({
52988
53124
  cause: `the Codex daemon does not answer on ${socket}: ${printable2(error62.message, MESSAGE_MAX)}`,
52989
53125
  action: DAEMON_START
52990
53126
  });
52991
53127
  });
52992
53128
  ws.on("close", () => closeAll("the connection closed"));
52993
- ws.once("open", () => resolve43({
53129
+ ws.once("open", () => resolve45({
52994
53130
  call(method, params, timeoutMs) {
52995
53131
  if (closed !== void 0)
52996
53132
  return Promise.resolve({ ok: false, kind: "closed", message: closed });
@@ -58250,13 +58386,13 @@ async function autopilotReview(argv, root) {
58250
58386
  }
58251
58387
  }
58252
58388
  function readAllStdin() {
58253
- return new Promise((resolve43, reject) => {
58389
+ return new Promise((resolve45, reject) => {
58254
58390
  let data2 = "";
58255
58391
  process.stdin.setEncoding("utf8");
58256
58392
  process.stdin.on("data", (chunk) => {
58257
58393
  data2 += chunk;
58258
58394
  });
58259
- process.stdin.on("end", () => resolve43(data2));
58395
+ process.stdin.on("end", () => resolve45(data2));
58260
58396
  process.stdin.on("error", reject);
58261
58397
  });
58262
58398
  }
@@ -60667,11 +60803,11 @@ function parseUntracked(output2) {
60667
60803
  function parseGitOwnership(output2, knownPaths) {
60668
60804
  const owners = {};
60669
60805
  for (const record32 of output2.split("").slice(1)) {
60670
- const boundary = record32.indexOf("");
60671
- if (boundary < 1) continue;
60672
- const owner = record32.slice(0, boundary);
60806
+ const boundary2 = record32.indexOf("");
60807
+ if (boundary2 < 1) continue;
60808
+ const owner = record32.slice(0, boundary2);
60673
60809
  if (owner.length > 256 || containsControl2(owner)) continue;
60674
- const paths = record32.slice(boundary + 1).split("\0");
60810
+ const paths = record32.slice(boundary2 + 1).split("\0");
60675
60811
  for (const rawPath of paths) {
60676
60812
  const path3 = rawPath.startsWith("\n") ? rawPath.slice(1) : rawPath;
60677
60813
  if (path3.length === 0) continue;
@@ -65993,7 +66129,7 @@ function requestedPort(args) {
65993
66129
  async function ui(args) {
65994
66130
  const launchToken = randomBytes(32).toString("base64url");
65995
66131
  banner("ui");
65996
- await new Promise((resolve43) => {
66132
+ await new Promise((resolve45) => {
65997
66133
  const server = startCommandCenter({
65998
66134
  port: requestedPort(args),
65999
66135
  launchToken,
@@ -66011,7 +66147,7 @@ async function ui(args) {
66011
66147
  }
66012
66148
  });
66013
66149
  const stop2 = () => {
66014
- server.close(() => resolve43());
66150
+ server.close(() => resolve45());
66015
66151
  };
66016
66152
  process.once("SIGINT", stop2);
66017
66153
  process.once("SIGTERM", stop2);
@@ -68908,7 +69044,7 @@ async function recordSpecialistRequests(root, missionId, envelopes, planHash) {
68908
69044
  init_esm_shims();
68909
69045
 
68910
69046
  // package.json
68911
- var version2 = "7.0.1";
69047
+ var version2 = "7.0.2";
68912
69048
 
68913
69049
  // src/lib/runs/verify.ts
68914
69050
  var MAX_CAPTURE_BYTES = 64 * 1024;