snipara-companion 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -3628,6 +3628,7 @@ interface OrchestratorHandoffOptions {
3628
3628
  rootDir?: string;
3629
3629
  changedFiles?: string[];
3630
3630
  contextRefs?: string[];
3631
+ decisionIds?: string[];
3631
3632
  resumeSummary?: string;
3632
3633
  featureTitle?: string;
3633
3634
  workstreams?: string[];
package/dist/index.js CHANGED
@@ -2899,6 +2899,7 @@ var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Map([
2899
2899
  var DEFAULT_MAX_FILES = 2e3;
2900
2900
  var DEFAULT_MAX_FILE_BYTES = 1024 * 1024;
2901
2901
  var DEFAULT_HOSTED_OVERLAY_TTL_HOURS = 48;
2902
+ var MAX_HOSTED_OVERLAY_TTL_HOURS = 168;
2902
2903
  var DEFAULT_HOOK_REINDEX_DELAY_SECONDS = 5;
2903
2904
  var CACHE_RELATIVE_PATH = import_path.default.join(".snipara", "code-overlay", "latest.json");
2904
2905
  var PROMOTION_RELATIVE_PATH = import_path.default.join(".snipara", "code-overlay", "promotion.json");
@@ -2961,8 +2962,14 @@ function ensureTrailingNewline2(content) {
2961
2962
  return content.endsWith("\n") ? content : `${content}
2962
2963
  `;
2963
2964
  }
2964
- function positiveInteger2(value, fallback) {
2965
- return Number.isFinite(value) && value !== void 0 && value > 0 ? Math.floor(value) : fallback;
2965
+ function positiveInteger2(value, fallback, label = "value") {
2966
+ if (value === void 0) {
2967
+ return fallback;
2968
+ }
2969
+ if (Number.isFinite(value) && value > 0) {
2970
+ return Math.floor(value);
2971
+ }
2972
+ throw new Error(`${label} must be a positive integer.`);
2966
2973
  }
2967
2974
  function nonNegativeInteger(value, fallback) {
2968
2975
  return Number.isFinite(value) && value !== void 0 && value >= 0 ? Math.floor(value) : fallback;
@@ -3344,8 +3351,12 @@ function buildLocalCodeOverlay(options = {}) {
3344
3351
  const repoRoot = resolveRepoRoot2(options.cwd ?? process.cwd());
3345
3352
  const mode = options.mode ?? "working_tree";
3346
3353
  const commit = mode === "local_commit" ? options.commit ?? "HEAD" : options.commit ?? "HEAD";
3347
- const maxFiles = positiveInteger2(options.maxFiles, DEFAULT_MAX_FILES);
3348
- const maxFileBytes = positiveInteger2(options.maxFileBytes, DEFAULT_MAX_FILE_BYTES);
3354
+ const maxFiles = positiveInteger2(options.maxFiles, DEFAULT_MAX_FILES, "--max-files");
3355
+ const maxFileBytes = positiveInteger2(
3356
+ options.maxFileBytes,
3357
+ DEFAULT_MAX_FILE_BYTES,
3358
+ "--max-file-bytes"
3359
+ );
3349
3360
  const now = (/* @__PURE__ */ new Date()).toISOString();
3350
3361
  const branch = readBranch(repoRoot);
3351
3362
  const localHeadSha = readHeadSha(repoRoot);
@@ -4193,7 +4204,14 @@ function buildHostedCodeOverlayUploadPayload(options = {}) {
4193
4204
  maxFiles: options.maxFiles
4194
4205
  });
4195
4206
  const cachePath = writeLocalCodeOverlayCache(manifest);
4196
- const ttlHours = positiveInteger2(options.ttlHours, DEFAULT_HOSTED_OVERLAY_TTL_HOURS);
4207
+ const ttlHours = positiveInteger2(
4208
+ options.ttlHours,
4209
+ DEFAULT_HOSTED_OVERLAY_TTL_HOURS,
4210
+ "--ttl-hours"
4211
+ );
4212
+ if (ttlHours > MAX_HOSTED_OVERLAY_TTL_HOURS) {
4213
+ throw new Error(`--ttl-hours must be less than or equal to ${MAX_HOSTED_OVERLAY_TTL_HOURS}.`);
4214
+ }
4197
4215
  return {
4198
4216
  manifest,
4199
4217
  cachePath,
@@ -10119,6 +10137,12 @@ function buildOrchestratorHandoff(options) {
10119
10137
  const changedFiles = normalizeStringList(
10120
10138
  options.changedFiles ?? (Array.isArray(workflowState?.currentPhase?.files) ? workflowState.currentPhase.files : [])
10121
10139
  );
10140
+ const contextRefs = normalizeStringList(options.contextRefs);
10141
+ const decisionIds = normalizeDecisionIds([
10142
+ ...normalizeStringList(workflowState?.decisionIds),
10143
+ ...normalizeStringList(options.decisionIds),
10144
+ ...extractDecisionIdsFromRefs(contextRefs)
10145
+ ]);
10122
10146
  const requiresProofGate = options.recommendation.reasons.includes("proof_gate_intent") || options.recommendation.reasons.includes("team_sync_collision");
10123
10147
  const requiresDriftCheck = options.recommendation.reasons.includes("production_validation_intent") || options.recommendation.reasons.includes("workflow_mode_orchestrate");
10124
10148
  return {
@@ -10187,8 +10211,8 @@ function buildOrchestratorHandoff(options) {
10187
10211
  ] : []
10188
10212
  },
10189
10213
  memory: {
10190
- decisionIds: ["DEC-002"],
10191
- contextRefs: normalizeStringList(options.contextRefs),
10214
+ decisionIds,
10215
+ contextRefs,
10192
10216
  resumeSummary: options.resumeSummary ?? null
10193
10217
  }
10194
10218
  };
@@ -10424,6 +10448,22 @@ function normalizeEndpointTypes(values) {
10424
10448
  )
10425
10449
  ).sort();
10426
10450
  }
10451
+ function normalizeDecisionIds(values) {
10452
+ return Array.from(
10453
+ new Set(
10454
+ normalizeStringList(values).map((value) => value.toUpperCase()).filter((value) => /^DEC-[A-Z0-9._-]+$/.test(value))
10455
+ )
10456
+ ).sort();
10457
+ }
10458
+ function extractDecisionIdsFromRefs(contextRefs) {
10459
+ const matches = [];
10460
+ for (const ref of contextRefs) {
10461
+ for (const match of ref.matchAll(/\bDEC-[A-Za-z0-9._-]+\b/g)) {
10462
+ matches.push(match[0]);
10463
+ }
10464
+ }
10465
+ return matches;
10466
+ }
10427
10467
  function compactObject2(value) {
10428
10468
  return Object.fromEntries(
10429
10469
  Object.entries(value).filter(
@@ -10481,9 +10521,20 @@ function readWorkflowState(rootDir) {
10481
10521
  currentPhaseId: parsed.currentPhaseId,
10482
10522
  currentPhase,
10483
10523
  phases,
10484
- runtimeSandboxPhases
10524
+ runtimeSandboxPhases,
10525
+ decisionIds: extractWorkflowDecisionIds(parsed)
10485
10526
  };
10486
10527
  }
10528
+ function extractWorkflowDecisionIds(parsed) {
10529
+ const fromTopLevel = normalizeStringList(parsed.decisionIds);
10530
+ const fromDecisions = Array.isArray(parsed.decisions) ? parsed.decisions.map((decision) => {
10531
+ if (typeof decision === "string") {
10532
+ return decision;
10533
+ }
10534
+ return isRecord4(decision) ? stringValue2(decision.decisionId) : void 0;
10535
+ }).filter((decisionId) => Boolean(decisionId)) : [];
10536
+ return normalizeDecisionIds([...fromTopLevel, ...fromDecisions]);
10537
+ }
10487
10538
  function normalizeContextPackIds(value) {
10488
10539
  if (!Array.isArray(value)) {
10489
10540
  return [];
@@ -17907,6 +17958,18 @@ async function taskCommitCommand(options) {
17907
17958
  var SNAPSHOT_RELATIVE_PATH = import_path2.default.join(".snipara", "source", "latest.json");
17908
17959
  var DEFAULT_MAX_FILES2 = 5e3;
17909
17960
  var DEFAULT_MAX_FILE_BYTES2 = 5 * 1024 * 1024;
17961
+ var LOCAL_SOURCE_FILE_KINDS = /* @__PURE__ */ new Set([
17962
+ "DOC",
17963
+ "BINARY",
17964
+ "CODE",
17965
+ "CONFIG",
17966
+ "OTHER"
17967
+ ]);
17968
+ var LOCAL_SOURCE_SKIPPED_REASONS = /* @__PURE__ */ new Set([
17969
+ "ignored",
17970
+ "too_large",
17971
+ "read_error"
17972
+ ]);
17910
17973
  var DOCUMENT_FORMATS = /* @__PURE__ */ new Map([
17911
17974
  [".adoc", { kind: "DOC", format: "adoc" }],
17912
17975
  [".markdown", { kind: "DOC", format: "markdown" }],
@@ -17979,12 +18042,27 @@ var DEFAULT_IGNORED_DIRS = /* @__PURE__ */ new Set([
17979
18042
  "target",
17980
18043
  "venv"
17981
18044
  ]);
17982
- function positiveInteger3(value, fallback) {
17983
- return Number.isFinite(value) && value !== void 0 && value > 0 ? Math.floor(value) : fallback;
18045
+ function positiveInteger3(value, fallback, label = "value") {
18046
+ if (value === void 0) {
18047
+ return fallback;
18048
+ }
18049
+ if (Number.isFinite(value) && value > 0) {
18050
+ return Math.floor(value);
18051
+ }
18052
+ throw new Error(`${label} must be a positive integer.`);
17984
18053
  }
17985
18054
  function normalizeRepoPath2(value) {
17986
18055
  return value.split(import_path2.default.sep).join("/").replace(/^\/+/, "");
17987
18056
  }
18057
+ function comparePaths(left, right) {
18058
+ if (left < right) {
18059
+ return -1;
18060
+ }
18061
+ if (left > right) {
18062
+ return 1;
18063
+ }
18064
+ return 0;
18065
+ }
17988
18066
  function sha2564(value) {
17989
18067
  return import_crypto2.default.createHash("sha256").update(value).digest("hex");
17990
18068
  }
@@ -18070,8 +18148,12 @@ function getLocalSourceSnapshotPath(cwd = process.cwd()) {
18070
18148
  function buildLocalSourceSnapshot(options = {}) {
18071
18149
  const root = resolveSourceRoot(options.dir);
18072
18150
  const recursive = options.recursive ?? true;
18073
- const maxFiles = positiveInteger3(options.maxFiles, DEFAULT_MAX_FILES2);
18074
- const maxFileBytes = positiveInteger3(options.maxFileBytes, DEFAULT_MAX_FILE_BYTES2);
18151
+ const maxFiles = positiveInteger3(options.maxFiles, DEFAULT_MAX_FILES2, "--max-files");
18152
+ const maxFileBytes = positiveInteger3(
18153
+ options.maxFileBytes,
18154
+ DEFAULT_MAX_FILE_BYTES2,
18155
+ "--max-file-bytes"
18156
+ );
18075
18157
  const now = (/* @__PURE__ */ new Date()).toISOString();
18076
18158
  const sniparaIgnore = readSniparaIgnore2(root);
18077
18159
  const files = [];
@@ -18150,6 +18232,8 @@ function buildLocalSourceSnapshot(options = {}) {
18150
18232
  if (files.length >= maxFiles) {
18151
18233
  warnings.push(`Stopped after ${maxFiles} files. Increase --max-files for larger folders.`);
18152
18234
  }
18235
+ files.sort((left, right) => comparePaths(left.path, right.path));
18236
+ skippedSamples.sort((left, right) => comparePaths(left.path, right.path));
18153
18237
  const byKind = emptyKindCounts();
18154
18238
  let totalBytes = 0;
18155
18239
  for (const file of files) {
@@ -18204,11 +18288,51 @@ function readLocalSourceSnapshot(cwd = process.cwd()) {
18204
18288
  }
18205
18289
  try {
18206
18290
  const parsed = JSON.parse(import_fs2.default.readFileSync(snapshotPath, "utf8"));
18207
- return parsed?.version === "snipara.local_source_snapshot.v1" ? parsed : null;
18291
+ return isLocalSourceSnapshot(parsed) ? parsed : null;
18208
18292
  } catch {
18209
18293
  return null;
18210
18294
  }
18211
18295
  }
18296
+ function isRecord6(value) {
18297
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
18298
+ }
18299
+ function isLocalSourceFile(value) {
18300
+ if (!isRecord6(value)) {
18301
+ return false;
18302
+ }
18303
+ return typeof value.path === "string" && LOCAL_SOURCE_FILE_KINDS.has(value.kind) && (typeof value.format === "string" || value.format === null) && typeof value.sizeBytes === "number" && Number.isFinite(value.sizeBytes) && typeof value.modifiedAt === "string" && typeof value.sha256 === "string";
18304
+ }
18305
+ function isSkippedFile(value) {
18306
+ if (!isRecord6(value)) {
18307
+ return false;
18308
+ }
18309
+ return typeof value.path === "string" && LOCAL_SOURCE_SKIPPED_REASONS.has(value.reason) && (value.sizeBytes === void 0 || typeof value.sizeBytes === "number" && Number.isFinite(value.sizeBytes));
18310
+ }
18311
+ function hasKindCounts(value) {
18312
+ if (!isRecord6(value)) {
18313
+ return false;
18314
+ }
18315
+ return Array.from(LOCAL_SOURCE_FILE_KINDS).every(
18316
+ (kind) => typeof value[kind] === "number" && Number.isFinite(value[kind])
18317
+ );
18318
+ }
18319
+ function hasSkippedCounts(value) {
18320
+ if (!isRecord6(value)) {
18321
+ return false;
18322
+ }
18323
+ return Array.from(LOCAL_SOURCE_SKIPPED_REASONS).every(
18324
+ (reason) => typeof value[reason] === "number" && Number.isFinite(value[reason])
18325
+ );
18326
+ }
18327
+ function isLocalSourceSnapshot(value) {
18328
+ if (!isRecord6(value) || value.version !== "snipara.local_source_snapshot.v1") {
18329
+ return false;
18330
+ }
18331
+ if (!isRecord6(value.summary) || !isRecord6(value.skipped)) {
18332
+ return false;
18333
+ }
18334
+ return typeof value.generatedAt === "string" && typeof value.root === "string" && value.provider === "local_folder" && typeof value.revision === "string" && typeof value.recursive === "boolean" && typeof value.maxFiles === "number" && typeof value.maxFileBytes === "number" && typeof value.summary.totalFiles === "number" && typeof value.summary.totalBytes === "number" && hasKindCounts(value.summary.byKind) && typeof value.summary.skipped === "number" && Array.isArray(value.files) && value.files.every(isLocalSourceFile) && typeof value.skipped.total === "number" && hasSkippedCounts(value.skipped.byReason) && Array.isArray(value.skipped.samples) && value.skipped.samples.every(isSkippedFile) && Array.isArray(value.warnings) && value.warnings.every((warning) => typeof warning === "string");
18335
+ }
18212
18336
  function compareLocalSourceSnapshots(previous, current) {
18213
18337
  if (!previous) {
18214
18338
  return {
@@ -18406,14 +18530,48 @@ async function sourceSyncCommand(options = {}) {
18406
18530
  printSyncResult(result);
18407
18531
  }
18408
18532
  async function sourceWatchCommand(options = {}) {
18409
- const intervalMs = positiveInteger3(options.intervalMs, 5e3);
18533
+ const intervalMs = positiveInteger3(options.intervalMs, 5e3, "--interval-ms");
18410
18534
  if (options.once) {
18411
18535
  await sourceSyncCommand(options);
18412
18536
  return;
18413
18537
  }
18414
- while (true) {
18415
- await sourceSyncCommand(options);
18416
- await new Promise((resolve17) => setTimeout(resolve17, intervalMs));
18538
+ let stopping = false;
18539
+ let activeTimer = null;
18540
+ let resolveWait = null;
18541
+ const stop = () => {
18542
+ stopping = true;
18543
+ if (activeTimer) {
18544
+ clearTimeout(activeTimer);
18545
+ activeTimer = null;
18546
+ }
18547
+ if (resolveWait) {
18548
+ resolveWait();
18549
+ resolveWait = null;
18550
+ }
18551
+ };
18552
+ const signals = ["SIGINT", "SIGTERM"];
18553
+ for (const signal of signals) {
18554
+ process.once(signal, stop);
18555
+ }
18556
+ try {
18557
+ while (!stopping) {
18558
+ await sourceSyncCommand(options);
18559
+ if (stopping) {
18560
+ break;
18561
+ }
18562
+ await new Promise((resolve17) => {
18563
+ resolveWait = resolve17;
18564
+ activeTimer = setTimeout(() => {
18565
+ activeTimer = null;
18566
+ resolveWait = null;
18567
+ resolve17();
18568
+ }, intervalMs);
18569
+ });
18570
+ }
18571
+ } finally {
18572
+ for (const signal of signals) {
18573
+ process.removeListener(signal, stop);
18574
+ }
18417
18575
  }
18418
18576
  }
18419
18577
 
@@ -18467,19 +18625,19 @@ function normalizeTask(task) {
18467
18625
  const normalized = task?.trim();
18468
18626
  return normalized ? normalized : void 0;
18469
18627
  }
18470
- function isRecord6(value) {
18628
+ function isRecord7(value) {
18471
18629
  return typeof value === "object" && value !== null && !Array.isArray(value);
18472
18630
  }
18473
18631
  function stringValue4(value) {
18474
18632
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
18475
18633
  }
18476
18634
  function recordList(value) {
18477
- return Array.isArray(value) ? value.filter(isRecord6) : [];
18635
+ return Array.isArray(value) ? value.filter(isRecord7) : [];
18478
18636
  }
18479
18637
  function safeReadJson(filePath) {
18480
18638
  try {
18481
18639
  const parsed = JSON.parse(fs19.readFileSync(filePath, "utf8"));
18482
- return isRecord6(parsed) ? parsed : void 0;
18640
+ return isRecord7(parsed) ? parsed : void 0;
18483
18641
  } catch {
18484
18642
  return void 0;
18485
18643
  }
@@ -18964,11 +19122,11 @@ function unique3(values) {
18964
19122
  )
18965
19123
  ];
18966
19124
  }
18967
- function isRecord7(value) {
19125
+ function isRecord8(value) {
18968
19126
  return typeof value === "object" && value !== null && !Array.isArray(value);
18969
19127
  }
18970
19128
  function recordList2(value) {
18971
- return Array.isArray(value) ? value.filter(isRecord7) : [];
19129
+ return Array.isArray(value) ? value.filter(isRecord8) : [];
18972
19130
  }
18973
19131
  function stringValue5(value) {
18974
19132
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
@@ -19520,7 +19678,7 @@ function buildLocalEngineeringLeadPlan(input) {
19520
19678
  };
19521
19679
  }
19522
19680
  function normalizeWorkerRecommendation(value, index) {
19523
- const contract = isRecord7(value.contract) ? value.contract : {};
19681
+ const contract = isRecord8(value.contract) ? value.contract : {};
19524
19682
  const role = cockpitEnumValue(
19525
19683
  "worker_role",
19526
19684
  ENGINEERING_LEAD_WORKER_ROLES,
@@ -19738,7 +19896,7 @@ function summarizeSupervisionFromWorkPackages(workPackages) {
19738
19896
  };
19739
19897
  }
19740
19898
  function normalizeSupervision(value, workPackages) {
19741
- if (!isRecord7(value)) {
19899
+ if (!isRecord8(value)) {
19742
19900
  return summarizeSupervisionFromWorkPackages(workPackages);
19743
19901
  }
19744
19902
  const fallback = summarizeSupervisionFromWorkPackages(workPackages);
@@ -19790,7 +19948,7 @@ function normalizeSupervision(value, workPackages) {
19790
19948
  };
19791
19949
  }
19792
19950
  function normalizeCockpitPlan(cockpit) {
19793
- const rawPlan = isRecord7(cockpit.engineeringLeadPlan) ? cockpit.engineeringLeadPlan : cockpit;
19951
+ const rawPlan = isRecord8(cockpit.engineeringLeadPlan) ? cockpit.engineeringLeadPlan : cockpit;
19794
19952
  const score = Math.round(numberValue3(rawPlan.score, 0));
19795
19953
  const workerRecommendations = recordList2(rawPlan.workerRecommendations).map(
19796
19954
  normalizeWorkerRecommendation
@@ -19990,7 +20148,7 @@ function applyReconciliationToPlan(plan, reconciliation) {
19990
20148
  }
19991
20149
  function readJsonFile3(filePath) {
19992
20150
  const parsed = JSON.parse(fs20.readFileSync(path19.resolve(filePath), "utf8"));
19993
- if (!isRecord7(parsed)) {
20151
+ if (!isRecord8(parsed)) {
19994
20152
  throw new Error(`${filePath} must contain a JSON object`);
19995
20153
  }
19996
20154
  return parsed;
@@ -20195,7 +20353,7 @@ var import_node_child_process6 = require("child_process");
20195
20353
  var import_chalk8 = __toESM(require("chalk"));
20196
20354
 
20197
20355
  // src/commands/judgment-card.ts
20198
- function isRecord8(value) {
20356
+ function isRecord9(value) {
20199
20357
  return typeof value === "object" && value !== null && !Array.isArray(value);
20200
20358
  }
20201
20359
  function numberValue4(value) {
@@ -20213,12 +20371,12 @@ function stringListValue(value) {
20213
20371
  function nestedRecord(root, keys) {
20214
20372
  let current = root;
20215
20373
  for (const key of keys) {
20216
- if (!isRecord8(current) || !isRecord8(current[key])) {
20374
+ if (!isRecord9(current) || !isRecord9(current[key])) {
20217
20375
  return {};
20218
20376
  }
20219
20377
  current = current[key];
20220
20378
  }
20221
- return isRecord8(current) ? current : {};
20379
+ return isRecord9(current) ? current : {};
20222
20380
  }
20223
20381
  function nestedArray(root, keys) {
20224
20382
  if (keys.length === 0) {
@@ -20304,7 +20462,7 @@ function advisorRecommendationsFromInput(input) {
20304
20462
  return recommendations;
20305
20463
  }
20306
20464
  function advisorRecommendationFromUnknown(value, index) {
20307
- if (!isRecord8(value)) {
20465
+ if (!isRecord9(value)) {
20308
20466
  return null;
20309
20467
  }
20310
20468
  const title = stringValue6(value.title);
@@ -20327,7 +20485,7 @@ function advisorRecommendationFromUnknown(value, index) {
20327
20485
  };
20328
20486
  }
20329
20487
  function codeImpactRisk(impact) {
20330
- const risk = isRecord8(impact?.risk) ? impact?.risk : {};
20488
+ const risk = isRecord9(impact?.risk) ? impact?.risk : {};
20331
20489
  return {
20332
20490
  level: stringValue6(risk.level),
20333
20491
  score: numberValue4(risk.score)
@@ -20361,19 +20519,19 @@ function collectVerificationChecks(plan) {
20361
20519
  };
20362
20520
  }
20363
20521
  function gapCode(gap) {
20364
- return isRecord8(gap) ? stringValue6(gap.code) ?? "verification_gap" : "verification_gap";
20522
+ return isRecord9(gap) ? stringValue6(gap.code) ?? "verification_gap" : "verification_gap";
20365
20523
  }
20366
20524
  function gapMessage(gap) {
20367
- if (!isRecord8(gap)) {
20525
+ if (!isRecord9(gap)) {
20368
20526
  return String(gap);
20369
20527
  }
20370
20528
  return stringValue6(gap.message) ?? stringValue6(gap.reason) ?? stringValue6(gap.title) ?? "Verification gap";
20371
20529
  }
20372
20530
  function checkCommand(check2) {
20373
- return isRecord8(check2) ? stringValue6(check2.command) : void 0;
20531
+ return isRecord9(check2) ? stringValue6(check2.command) : void 0;
20374
20532
  }
20375
20533
  function checkTitle(check2) {
20376
- if (!isRecord8(check2)) {
20534
+ if (!isRecord9(check2)) {
20377
20535
  return String(check2);
20378
20536
  }
20379
20537
  return stringValue6(check2.title) ?? stringValue6(check2.command) ?? stringValue6(check2.file) ?? "verification check";
@@ -20453,7 +20611,7 @@ function buildProjectJudgmentCard(input) {
20453
20611
  "Code impact was degraded; local reads and broader checks should override confidence."
20454
20612
  );
20455
20613
  }
20456
- const freshness = isRecord8(input.codeImpact?.index_freshness) ? input.codeImpact?.index_freshness : {};
20614
+ const freshness = isRecord9(input.codeImpact?.index_freshness) ? input.codeImpact?.index_freshness : {};
20457
20615
  if (freshness.is_stale === true || freshness.commit_match === false) {
20458
20616
  addReason(reasons, {
20459
20617
  code: "code_graph_stale",
@@ -20476,12 +20634,12 @@ function buildProjectJudgmentCard(input) {
20476
20634
  type: "run_check",
20477
20635
  title: checkTitle(check2),
20478
20636
  command: checkCommand(check2),
20479
- reason: isRecord8(check2) ? stringValue6(check2.reason) : void 0,
20637
+ reason: isRecord9(check2) ? stringValue6(check2.reason) : void 0,
20480
20638
  severity: "medium"
20481
20639
  });
20482
20640
  }
20483
20641
  for (const gap of missingChecks) {
20484
- const severity = normalizeSeverity(isRecord8(gap) ? gap.severity : void 0);
20642
+ const severity = normalizeSeverity(isRecord9(gap) ? gap.severity : void 0);
20485
20643
  const code2 = gapCode(gap);
20486
20644
  addReason(reasons, {
20487
20645
  code: code2,
@@ -20785,7 +20943,7 @@ function formatProjectJudgmentCard(card) {
20785
20943
  var import_fs3 = __toESM(require("fs"));
20786
20944
  var import_path3 = __toESM(require("path"));
20787
20945
  var import_chalk7 = __toESM(require("chalk"));
20788
- function isRecord9(value) {
20946
+ function isRecord10(value) {
20789
20947
  return typeof value === "object" && value !== null && !Array.isArray(value);
20790
20948
  }
20791
20949
  function stringValue7(value) {
@@ -20802,7 +20960,7 @@ function stringList2(value) {
20802
20960
  if (typeof item === "string") {
20803
20961
  return [item];
20804
20962
  }
20805
- if (!isRecord9(item)) {
20963
+ if (!isRecord10(item)) {
20806
20964
  return [];
20807
20965
  }
20808
20966
  return [
@@ -20858,7 +21016,7 @@ function collectActionChecks(impact) {
20858
21016
  const kind2 = checkKindFromText(item);
20859
21017
  return kind2 === "command" || kind2 === "inspection" ? [] : [{ kind: kind2, title: item, source: "code-impact" }];
20860
21018
  }
20861
- if (!isRecord9(item)) {
21019
+ if (!isRecord10(item)) {
20862
21020
  return [];
20863
21021
  }
20864
21022
  const title = actionTitle(item);
@@ -20886,7 +21044,7 @@ function collectDirectTestChecks(impact) {
20886
21044
  impact.related_tests,
20887
21045
  impact.relatedTests,
20888
21046
  impact.tests,
20889
- isRecord9(impact.impact) ? impact.impact.tests : void 0
21047
+ isRecord10(impact.impact) ? impact.impact.tests : void 0
20890
21048
  ];
20891
21049
  return candidates.flatMap((candidate) => {
20892
21050
  if (!Array.isArray(candidate)) {
@@ -20904,7 +21062,7 @@ function collectDirectTestChecks(impact) {
20904
21062
  }
20905
21063
  ];
20906
21064
  }
20907
- if (!isRecord9(item)) {
21065
+ if (!isRecord10(item)) {
20908
21066
  return [];
20909
21067
  }
20910
21068
  const command = stringValue7(item.command);
@@ -20947,7 +21105,7 @@ function findPackageJson(startPath, cwd) {
20947
21105
  function readPackageInfo(packageJsonPath) {
20948
21106
  try {
20949
21107
  const parsed = JSON.parse(import_fs3.default.readFileSync(packageJsonPath, "utf8"));
20950
- const scripts = isRecord9(parsed.scripts) ? Object.fromEntries(
21108
+ const scripts = isRecord10(parsed.scripts) ? Object.fromEntries(
20951
21109
  Object.entries(parsed.scripts).filter((entry) => {
20952
21110
  return typeof entry[1] === "string";
20953
21111
  })
@@ -21004,12 +21162,12 @@ function collectImpactedFiles(impact, changedFiles, filePath) {
21004
21162
  ...stringList2(impact?.impacted_files),
21005
21163
  ...stringList2(impact?.impactedFiles),
21006
21164
  ...stringList2(impact?.matched_targets),
21007
- ...stringList2(isRecord9(impact?.impact) ? impact?.impact.files : void 0)
21165
+ ...stringList2(isRecord10(impact?.impact) ? impact?.impact.files : void 0)
21008
21166
  ];
21009
21167
  return unique4(files);
21010
21168
  }
21011
21169
  function buildRisk(impact) {
21012
- const risk = impact && isRecord9(impact.risk) ? impact.risk : {};
21170
+ const risk = impact && isRecord10(impact.risk) ? impact.risk : {};
21013
21171
  return {
21014
21172
  level: stringValue7(risk.level) ?? "unknown",
21015
21173
  ...numberValue5(risk.score) !== void 0 ? { score: numberValue5(risk.score) } : {},
@@ -21021,7 +21179,7 @@ function collectCoverageGaps(impact) {
21021
21179
  return [];
21022
21180
  }
21023
21181
  return impact.coverage_gaps.map((gap) => {
21024
- if (!isRecord9(gap)) {
21182
+ if (!isRecord10(gap)) {
21025
21183
  return {
21026
21184
  code: "coverage_gap",
21027
21185
  severity: "medium",
@@ -21045,7 +21203,7 @@ function collectCaveats(impact, errors) {
21045
21203
  "Code impact returned degraded results; prefer conservative checks and local reads."
21046
21204
  );
21047
21205
  }
21048
- const freshness = impact && isRecord9(impact.index_freshness) ? impact.index_freshness : {};
21206
+ const freshness = impact && isRecord10(impact.index_freshness) ? impact.index_freshness : {};
21049
21207
  if (freshness.commit_match === false || freshness.is_stale === true) {
21050
21208
  caveats.push(
21051
21209
  "Code graph freshness does not fully match the local working tree; verify exact files locally."
@@ -21053,7 +21211,7 @@ function collectCaveats(impact, errors) {
21053
21211
  }
21054
21212
  const warnings = Array.isArray(freshness.warnings) ? freshness.warnings : [];
21055
21213
  for (const warning of warnings.slice(0, 3)) {
21056
- if (isRecord9(warning) && warning.message) {
21214
+ if (isRecord10(warning) && warning.message) {
21057
21215
  caveats.push(preview2(warning.message, 220));
21058
21216
  }
21059
21217
  }
@@ -21258,7 +21416,7 @@ async function verifyCommand(options) {
21258
21416
  }
21259
21417
 
21260
21418
  // src/commands/intelligence.ts
21261
- function isRecord10(value) {
21419
+ function isRecord11(value) {
21262
21420
  return typeof value === "object" && value !== null && !Array.isArray(value);
21263
21421
  }
21264
21422
  function numberValue6(value) {
@@ -21291,7 +21449,7 @@ function nestedRecord2(root, keys) {
21291
21449
  let current = root;
21292
21450
  for (const key of keys) {
21293
21451
  const next = current[key];
21294
- if (!isRecord10(next)) {
21452
+ if (!isRecord11(next)) {
21295
21453
  return {};
21296
21454
  }
21297
21455
  current = next;
@@ -21312,7 +21470,7 @@ function actionList(value) {
21312
21470
  if (typeof item === "string") {
21313
21471
  return item;
21314
21472
  }
21315
- if (!isRecord10(item)) {
21473
+ if (!isRecord11(item)) {
21316
21474
  return preview3(item);
21317
21475
  }
21318
21476
  const title = item.action ?? item.title ?? item.name ?? item.recommendedAction ?? "action";
@@ -21430,7 +21588,7 @@ function printResumeContext(result) {
21430
21588
  console.log(import_chalk8.default.yellow("Unavailable"));
21431
21589
  return;
21432
21590
  }
21433
- const resumeContext = isRecord10(result.resumeContext) ? result.resumeContext : result;
21591
+ const resumeContext = isRecord11(result.resumeContext) ? result.resumeContext : result;
21434
21592
  const focus = nestedRecord2(resumeContext, ["focus"]);
21435
21593
  const scope = nestedRecord2(resumeContext, ["scope"]);
21436
21594
  if (scope.branch) {
@@ -21469,7 +21627,7 @@ function printMemoryHealth2(result) {
21469
21627
  if (score !== void 0) {
21470
21628
  console.log(`Memory Health: ${formatPercentScore(score)}`);
21471
21629
  }
21472
- const metrics = isRecord10(result.metrics) ? result.metrics : nestedRecord2(result, ["summary", "metrics"]);
21630
+ const metrics = isRecord11(result.metrics) ? result.metrics : nestedRecord2(result, ["summary", "metrics"]);
21473
21631
  const metricEntries = Object.entries(metrics).filter(([, value]) => value !== void 0);
21474
21632
  if (metricEntries.length > 0) {
21475
21633
  console.log(
@@ -21484,11 +21642,11 @@ function printCodeImpact(result) {
21484
21642
  console.log(import_chalk8.default.yellow("Skipped or unavailable"));
21485
21643
  return;
21486
21644
  }
21487
- const risk = isRecord10(result.risk) ? result.risk : {};
21645
+ const risk = isRecord11(result.risk) ? result.risk : {};
21488
21646
  if (risk.level || risk.score !== void 0) {
21489
21647
  console.log(`Risk: ${preview3(risk.level ?? "unknown")} (${preview3(risk.score ?? "n/a")})`);
21490
21648
  }
21491
- const evidence = isRecord10(result.evidence_summary) ? result.evidence_summary : {};
21649
+ const evidence = isRecord11(result.evidence_summary) ? result.evidence_summary : {};
21492
21650
  if (evidence.matched_target_count !== void 0) {
21493
21651
  console.log(`Matched targets: ${preview3(evidence.matched_target_count)}`);
21494
21652
  }
@@ -22006,7 +22164,7 @@ var REGISTRY_VERSION = "project-intelligence.policy-gates.registry.v1";
22006
22164
  function normalizeChangedFiles(changedFiles) {
22007
22165
  return [...new Set((changedFiles ?? []).map((file) => file.trim()).filter(Boolean))];
22008
22166
  }
22009
- function isRecord11(value) {
22167
+ function isRecord12(value) {
22010
22168
  return typeof value === "object" && value !== null && !Array.isArray(value);
22011
22169
  }
22012
22170
  function stringValue8(value) {
@@ -22015,12 +22173,12 @@ function stringValue8(value) {
22015
22173
  function nestedRecord3(root, keys) {
22016
22174
  let current = root;
22017
22175
  for (const key of keys) {
22018
- if (!isRecord11(current) || !isRecord11(current[key])) {
22176
+ if (!isRecord12(current) || !isRecord12(current[key])) {
22019
22177
  return {};
22020
22178
  }
22021
22179
  current = current[key];
22022
22180
  }
22023
- return isRecord11(current) ? current : {};
22181
+ return isRecord12(current) ? current : {};
22024
22182
  }
22025
22183
  function combinedText(input) {
22026
22184
  return [input.task, input.diffSummary, ...input.changedFiles ?? []].filter(Boolean).join("\n").toLowerCase();
@@ -22392,7 +22550,7 @@ var ADVISOR_RECEIPT_WRITE_LIMIT = 6;
22392
22550
  function normalizeStringList3(values) {
22393
22551
  return [...new Set((values ?? []).map((value) => value.trim()).filter(Boolean))];
22394
22552
  }
22395
- function isRecord12(value) {
22553
+ function isRecord13(value) {
22396
22554
  return typeof value === "object" && value !== null && !Array.isArray(value);
22397
22555
  }
22398
22556
  function guardPayload(guard) {
@@ -22415,7 +22573,7 @@ function servedJudgmentIdFromUnknown(value, depth = 0) {
22415
22573
  if (depth > 5 || value === null || value === void 0) {
22416
22574
  return void 0;
22417
22575
  }
22418
- if (!isRecord12(value)) {
22576
+ if (!isRecord13(value)) {
22419
22577
  if (Array.isArray(value)) {
22420
22578
  for (const item of value.slice(0, 12)) {
22421
22579
  const found = servedJudgmentIdFromUnknown(item, depth + 1);
@@ -22772,7 +22930,7 @@ function runGuard(options, changedFiles) {
22772
22930
  let payload;
22773
22931
  try {
22774
22932
  const parsed = JSON.parse(result.stdout);
22775
- if (isRecord12(parsed)) {
22933
+ if (isRecord13(parsed)) {
22776
22934
  payload = parsed;
22777
22935
  }
22778
22936
  } catch {
@@ -22934,10 +23092,10 @@ async function projectIntelligenceRunCommand(options) {
22934
23092
  if (result.guard) {
22935
23093
  console.log(import_chalk10.default.bold("Guard"));
22936
23094
  console.log(`Status: ${result.guard.status}`);
22937
- const actionCards = isRecord12(result.guard.payload) ? result.guard.payload.actionCards : [];
23095
+ const actionCards = isRecord13(result.guard.payload) ? result.guard.payload.actionCards : [];
22938
23096
  if (Array.isArray(actionCards) && actionCards.length > 0) {
22939
23097
  for (const card of actionCards.slice(0, 6)) {
22940
- if (!isRecord12(card)) continue;
23098
+ if (!isRecord13(card)) continue;
22941
23099
  console.log(`- ${card.kind}: ${card.title ?? card.reason ?? "guard action"}`);
22942
23100
  }
22943
23101
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snipara-companion",
3
- "version": "3.0.0",
3
+ "version": "3.0.1",
4
4
  "description": "Local-first CLI that asks your repo what breaks before an AI coding agent edits it.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {