snipara-companion 3.0.6 → 3.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -43,6 +43,7 @@ These commands are useful without hosted Snipara:
43
43
  | ------------------------------------------------------------ | ------------------------------------------------------------ |
44
44
  | `source init` / `source sync` / `source status` | Local source snapshot, document preview, and code overlay |
45
45
  | `impact` / `code impact` | File-level blast-radius from the local code overlay |
46
+ | `reality-check` | Intent/verification checks for local or supplied changes |
46
47
  | `code callers` / `imports` / `neighbors` / `shortest-path` | Structural repo questions from local files |
47
48
  | `workflow start` / `phase-start` / `phase-commit` / `resume` | Agent continuity that survives compaction |
48
49
  | `context-pack` | Reversible local packs for long logs, diffs, and tool output |
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { ProjectIntelligenceEngineeringLeadPlanSummary } from '@snipara/project-intelligence-contracts';
2
+ import { ProjectRealityCheckResult, ProjectIntelligenceEngineeringLeadPlanSummary } from '@snipara/project-intelligence-contracts';
3
3
 
4
4
  declare function resolveQueryFromToolInput(toolInput?: string, tool?: string): string | null;
5
5
 
@@ -1946,6 +1946,23 @@ interface ProjectIntelligenceBrief {
1946
1946
  declare function buildProjectIntelligenceBrief(options: ProjectIntelligenceBriefOptions): Promise<ProjectIntelligenceBrief>;
1947
1947
  declare function projectIntelligenceBriefCommand(options: ProjectIntelligenceBriefOptions): Promise<void>;
1948
1948
 
1949
+ interface RealityCheckCommandOptions {
1950
+ task?: string;
1951
+ branch?: string;
1952
+ base?: string;
1953
+ changedFiles?: string[];
1954
+ diffSummary?: string;
1955
+ decision?: string[];
1956
+ document?: string[];
1957
+ verification?: string[];
1958
+ includeDirty?: boolean;
1959
+ enforce?: boolean;
1960
+ dir?: string;
1961
+ json?: boolean;
1962
+ }
1963
+ declare function buildLocalProjectRealityCheck(options: RealityCheckCommandOptions): ProjectRealityCheckResult;
1964
+ declare function realityCheckCommand(options: RealityCheckCommandOptions): Promise<void>;
1965
+
1949
1966
  interface MemoryHealthCommandOptions {
1950
1967
  scope?: MemoryScope;
1951
1968
  includeInactive?: boolean;
@@ -3935,4 +3952,4 @@ declare function buildOrchestratorHandoff(options: OrchestratorHandoffOptions):
3935
3952
  declare function buildAdaptiveWorkRoutingRecommendation(options: AdaptiveWorkRoutingOptions): AdaptiveWorkRoutingRecommendation;
3936
3953
  declare function writeOrchestratorHandoff(options: OrchestratorHandoffOptions): WrittenOrchestratorHandoff;
3937
3954
 
3938
- export { AUTOMATION_MANIFEST_RELATIVE_PATH, AutomationInstallConflictError, AutomationUnsupportedHookBundleError, CODING_INTELLIGENCE_LEDGER_VERSION, COLLABORATION_STATE_RELATIVE_PATH, ENGINEERING_LEAD_EXECUTION_RECEIPT_STAGES, ENGINEERING_LEAD_EXECUTION_RECEIPT_STATUSES, ENGINEERING_LEAD_POSTURES, ENGINEERING_LEAD_PROOF_VERIFICATION_SOURCES, ENGINEERING_LEAD_PROOF_VERIFICATION_STATUSES, ENGINEERING_LEAD_ROUTING_MODES, ENGINEERING_LEAD_STATUSES, ENGINEERING_LEAD_SUPERVISION_STATUSES, ENGINEERING_LEAD_WORKER_ROLES, ENGINEERING_LEAD_WORK_PACKAGE_STATUSES, ORCHESTRATOR_HANDOFF_RELATIVE_PATH, TEAM_SYNC_STATE_RELATIVE_PATH, WHY_OUTCOME_CAPTURE_VERSION, WORKFLOW_PLANS_RELATIVE_DIR, WORKFLOW_STATE_RELATIVE_PATH, addLocalWorker, agentReadinessAuditCommand, archiveInactiveTeamSyncWork, attachLocalContextPackReceipts, autoArchiveTeamSyncState, buildAdaptiveWorkRoutingRecommendation, buildAgentReadinessAuditReport, buildAgenticHandoffMarkdown, buildAgenticTimeline, buildAgenticWorkStatus, buildAutomationInstallPlan, buildCanonicalEvent, buildCodeHooksInstallPlan, buildCodePromotionResult, buildCodeStatusResult, buildCodeSyncResult, buildCodingIntelligenceLedger, buildCollaborationActor, buildCollaborationGuardActionCards, buildCollaborationHooksInstallPlan, buildCompanionEngineeringLeadPlanReport, buildContextPackStats, buildEvalCaseArtifact, buildGeneratedWorkflowPlanDocument, buildHostedCodeOverlayUploadPayload, buildHostedGuardPayload, buildJournalCheckpointEntry, buildLocalCallersResult, buildLocalCodeOverlay, buildLocalContextPackReceipt, buildLocalContextPackReceipts, buildLocalImpactResult, buildLocalImportsResult, buildLocalNeighborsResult, buildLocalShortestPathResult, buildLocalSourceSnapshot, buildLocalSourceStatus, buildLocalSourceSyncResult, buildMemoryAudit, buildOnboardFolderManifest, buildOrchestratorHandoff, buildProjectIntelligenceBrief, buildProjectIntelligenceRun, buildProjectJudgmentCard, buildSessionBootstrapQuality, buildSyncDocumentsDryRun, buildTeamSyncHandoffRecord, buildTeamSyncStartWorkRecord, buildTeamSyncSummary, buildToolCallPayload, buildToolResultPayload, buildVerificationPlan, buildWhyOutcomeCaptureReport, buildWorkflowImpactGate, buildWorkflowPhaseCommitSummary, buildWorkflowPlanScaffold, categoryFromGuardTag, classifyToolResult, cleanContextPacks, codingLedgerExportCommand, collaborationIdeStatusCommand, collectAgentReadinessLocalSignals, collectSyncDocuments, collectSyncDocumentsInput, compactHostedGuardResources, compareLocalSourceSnapshots, completeTeamSyncStateFromEvidence, completeTeamSyncWorkFromEvidence, contextPackCleanCommand, contextPackPackCommand, contextPackRetrieveCommand, contextPackStatsCommand, createClient, createEmptyCollaborationState, createEmptyTeamSyncState, createLocalQueryCache, deriveLocalCollaborationResourcesFromFiles, detectReleaseSurfacesFromFiles, detectRuntimeEnvironment, evalExportCommand, evalRunCommand, evaluateProjectPolicyGates, extractCommandFromToolInput, extractFilesFromToolInput, formatAgentReadinessAuditReport, formatCompanionEngineeringLeadPlanReport, formatOrchestratorRecommendationReason, formatPolicyGateDecision, formatProjectJudgmentCard, formatStuckGuardDecision, getAutomationManifestPath, getAutomationStatus, getCollaborationStatePath, getConfigPath, getContextPackStoragePaths, getLocalCodeOverlayCachePath, getLocalCodePromotionStatePath, getLocalSourceSnapshotPath, getOrchestratorRecommendation, getPlanStepDisplayTitle, getStagedFiles, getStuckGuardInjection, getTeamSyncStatePath, ingestReferences, installAutomationBundle, leadPlanCommand, listProjectsForApiKey, loadAutomationManifest, loadCollaborationState, loadConfig, loadTeamSyncState, memoryAuditCommand, memoryCleanCandidatesCommand, memoryCompactCommand, memoryHealthCommand, memoryLocalCommand, normalizeCollaborationFiles, normalizeGuardTag, normalizeWorkflowPlanInput, outcomeCapturePreviewCommand, packContext, parseCollaborationResources, projectIntelligenceBriefCommand, projectIntelligenceRunCommand, readLocalCodeOverlayCache, readLocalCodePromotionState, readLocalSourceSnapshot, readLocalWorkersConfig, referencesIngestCommand, referencesScanCommand, resolveContextPackRecord, resolveFullWorkflowTokenBudget, resolveLocalWorkerRoutingDefaults, resolveQueryFromToolInput, retrieveContextPack, runMemoryGuardCheck, saveCollaborationState, saveConfig, saveTeamSyncState, scanReferences, shouldSuggestOrchestratorForWorkflow, shouldSuggestRuntimeForWorkflow, summarizeLocalCodeOverlay, teamSyncSweepCommand, validatePlanResult, verifyCommand, workersLocalAddCommand, workersLocalStatusCommand, writeLocalCodeOverlayCache, writeLocalCodePromotionState, writeLocalSourceSnapshot, writeOrchestratorHandoff };
3955
+ export { AUTOMATION_MANIFEST_RELATIVE_PATH, AutomationInstallConflictError, AutomationUnsupportedHookBundleError, CODING_INTELLIGENCE_LEDGER_VERSION, COLLABORATION_STATE_RELATIVE_PATH, ENGINEERING_LEAD_EXECUTION_RECEIPT_STAGES, ENGINEERING_LEAD_EXECUTION_RECEIPT_STATUSES, ENGINEERING_LEAD_POSTURES, ENGINEERING_LEAD_PROOF_VERIFICATION_SOURCES, ENGINEERING_LEAD_PROOF_VERIFICATION_STATUSES, ENGINEERING_LEAD_ROUTING_MODES, ENGINEERING_LEAD_STATUSES, ENGINEERING_LEAD_SUPERVISION_STATUSES, ENGINEERING_LEAD_WORKER_ROLES, ENGINEERING_LEAD_WORK_PACKAGE_STATUSES, ORCHESTRATOR_HANDOFF_RELATIVE_PATH, TEAM_SYNC_STATE_RELATIVE_PATH, WHY_OUTCOME_CAPTURE_VERSION, WORKFLOW_PLANS_RELATIVE_DIR, WORKFLOW_STATE_RELATIVE_PATH, addLocalWorker, agentReadinessAuditCommand, archiveInactiveTeamSyncWork, attachLocalContextPackReceipts, autoArchiveTeamSyncState, buildAdaptiveWorkRoutingRecommendation, buildAgentReadinessAuditReport, buildAgenticHandoffMarkdown, buildAgenticTimeline, buildAgenticWorkStatus, buildAutomationInstallPlan, buildCanonicalEvent, buildCodeHooksInstallPlan, buildCodePromotionResult, buildCodeStatusResult, buildCodeSyncResult, buildCodingIntelligenceLedger, buildCollaborationActor, buildCollaborationGuardActionCards, buildCollaborationHooksInstallPlan, buildCompanionEngineeringLeadPlanReport, buildContextPackStats, buildEvalCaseArtifact, buildGeneratedWorkflowPlanDocument, buildHostedCodeOverlayUploadPayload, buildHostedGuardPayload, buildJournalCheckpointEntry, buildLocalCallersResult, buildLocalCodeOverlay, buildLocalContextPackReceipt, buildLocalContextPackReceipts, buildLocalImpactResult, buildLocalImportsResult, buildLocalNeighborsResult, buildLocalProjectRealityCheck, buildLocalShortestPathResult, buildLocalSourceSnapshot, buildLocalSourceStatus, buildLocalSourceSyncResult, buildMemoryAudit, buildOnboardFolderManifest, buildOrchestratorHandoff, buildProjectIntelligenceBrief, buildProjectIntelligenceRun, buildProjectJudgmentCard, buildSessionBootstrapQuality, buildSyncDocumentsDryRun, buildTeamSyncHandoffRecord, buildTeamSyncStartWorkRecord, buildTeamSyncSummary, buildToolCallPayload, buildToolResultPayload, buildVerificationPlan, buildWhyOutcomeCaptureReport, buildWorkflowImpactGate, buildWorkflowPhaseCommitSummary, buildWorkflowPlanScaffold, categoryFromGuardTag, classifyToolResult, cleanContextPacks, codingLedgerExportCommand, collaborationIdeStatusCommand, collectAgentReadinessLocalSignals, collectSyncDocuments, collectSyncDocumentsInput, compactHostedGuardResources, compareLocalSourceSnapshots, completeTeamSyncStateFromEvidence, completeTeamSyncWorkFromEvidence, contextPackCleanCommand, contextPackPackCommand, contextPackRetrieveCommand, contextPackStatsCommand, createClient, createEmptyCollaborationState, createEmptyTeamSyncState, createLocalQueryCache, deriveLocalCollaborationResourcesFromFiles, detectReleaseSurfacesFromFiles, detectRuntimeEnvironment, evalExportCommand, evalRunCommand, evaluateProjectPolicyGates, extractCommandFromToolInput, extractFilesFromToolInput, formatAgentReadinessAuditReport, formatCompanionEngineeringLeadPlanReport, formatOrchestratorRecommendationReason, formatPolicyGateDecision, formatProjectJudgmentCard, formatStuckGuardDecision, getAutomationManifestPath, getAutomationStatus, getCollaborationStatePath, getConfigPath, getContextPackStoragePaths, getLocalCodeOverlayCachePath, getLocalCodePromotionStatePath, getLocalSourceSnapshotPath, getOrchestratorRecommendation, getPlanStepDisplayTitle, getStagedFiles, getStuckGuardInjection, getTeamSyncStatePath, ingestReferences, installAutomationBundle, leadPlanCommand, listProjectsForApiKey, loadAutomationManifest, loadCollaborationState, loadConfig, loadTeamSyncState, memoryAuditCommand, memoryCleanCandidatesCommand, memoryCompactCommand, memoryHealthCommand, memoryLocalCommand, normalizeCollaborationFiles, normalizeGuardTag, normalizeWorkflowPlanInput, outcomeCapturePreviewCommand, packContext, parseCollaborationResources, projectIntelligenceBriefCommand, projectIntelligenceRunCommand, readLocalCodeOverlayCache, readLocalCodePromotionState, readLocalSourceSnapshot, readLocalWorkersConfig, realityCheckCommand, referencesIngestCommand, referencesScanCommand, resolveContextPackRecord, resolveFullWorkflowTokenBudget, resolveLocalWorkerRoutingDefaults, resolveQueryFromToolInput, retrieveContextPack, runMemoryGuardCheck, saveCollaborationState, saveConfig, saveTeamSyncState, scanReferences, shouldSuggestOrchestratorForWorkflow, shouldSuggestRuntimeForWorkflow, summarizeLocalCodeOverlay, teamSyncSweepCommand, validatePlanResult, verifyCommand, workersLocalAddCommand, workersLocalStatusCommand, writeLocalCodeOverlayCache, writeLocalCodePromotionState, writeLocalSourceSnapshot, writeOrchestratorHandoff };
package/dist/index.js CHANGED
@@ -85,6 +85,7 @@ __export(index_exports, {
85
85
  buildLocalImpactResult: () => buildLocalImpactResult,
86
86
  buildLocalImportsResult: () => buildLocalImportsResult,
87
87
  buildLocalNeighborsResult: () => buildLocalNeighborsResult,
88
+ buildLocalProjectRealityCheck: () => buildLocalProjectRealityCheck,
88
89
  buildLocalShortestPathResult: () => buildLocalShortestPathResult,
89
90
  buildLocalSourceSnapshot: () => buildLocalSourceSnapshot,
90
91
  buildLocalSourceStatus: () => buildLocalSourceStatus,
@@ -179,6 +180,7 @@ __export(index_exports, {
179
180
  readLocalCodePromotionState: () => readLocalCodePromotionState,
180
181
  readLocalSourceSnapshot: () => readLocalSourceSnapshot,
181
182
  readLocalWorkersConfig: () => readLocalWorkersConfig,
183
+ realityCheckCommand: () => realityCheckCommand,
182
184
  referencesIngestCommand: () => referencesIngestCommand,
183
185
  referencesScanCommand: () => referencesScanCommand,
184
186
  resolveContextPackRecord: () => resolveContextPackRecord,
@@ -1460,9 +1462,9 @@ var RLMClient = class {
1460
1462
  ...maxTokens ? { max_tokens: maxTokens } : {}
1461
1463
  });
1462
1464
  }
1463
- async uploadDocument(path27, content, options = {}) {
1465
+ async uploadDocument(path28, content, options = {}) {
1464
1466
  return this.mcpCall("snipara_upload_document", {
1465
- path: path27,
1467
+ path: path28,
1466
1468
  content,
1467
1469
  ...options.kind ? { kind: options.kind } : {},
1468
1470
  ...options.format ? { format: options.format } : {},
@@ -1549,9 +1551,9 @@ var RLMClient = class {
1549
1551
  ...maxTokens ? { max_tokens: maxTokens } : {}
1550
1552
  });
1551
1553
  }
1552
- async loadDocument(path27) {
1554
+ async loadDocument(path28) {
1553
1555
  return this.mcpCall("snipara_load_document", {
1554
- path: path27
1556
+ path: path28
1555
1557
  });
1556
1558
  }
1557
1559
  async getSessionMemories(maxCriticalTokens, maxDailyTokens, includeYesterday) {
@@ -13430,12 +13432,12 @@ function uniqueStringList(values) {
13430
13432
  if (!values) {
13431
13433
  return void 0;
13432
13434
  }
13433
- const unique5 = Array.from(
13435
+ const unique6 = Array.from(
13434
13436
  new Set(
13435
13437
  values.map((value) => stringValue4(value)).filter((value) => Boolean(value))
13436
13438
  )
13437
13439
  );
13438
- return unique5.length > 0 ? unique5 : void 0;
13440
+ return unique6.length > 0 ? unique6 : void 0;
13439
13441
  }
13440
13442
  function sanitizeWorkflowId(value, fallback) {
13441
13443
  const normalized = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
@@ -15680,8 +15682,8 @@ function enrichAdaptiveRoutingWithLocalOrchestrator(routing, options, cwd = proc
15680
15682
  };
15681
15683
  }
15682
15684
  }
15683
- function printUploadResult(path27, result) {
15684
- printKeyValue2("Uploaded:", path27);
15685
+ function printUploadResult(path28, result) {
15686
+ printKeyValue2("Uploaded:", path28);
15685
15687
  printCompactObject(result, ["message", "document_id", "documentId", "version", "status"]);
15686
15688
  console.log("");
15687
15689
  printJson2(result);
@@ -15989,9 +15991,9 @@ function printOrchestrateResult(result) {
15989
15991
  }
15990
15992
  printJson2(result);
15991
15993
  }
15992
- function printLoadDocumentResult(path27, result) {
15994
+ function printLoadDocumentResult(path28, result) {
15993
15995
  printKeyValue2("Tool:", "snipara_load_document");
15994
- printKeyValue2("Path:", path27);
15996
+ printKeyValue2("Path:", path28);
15995
15997
  console.log("");
15996
15998
  if (typeof result === "string") {
15997
15999
  console.log(result.trim());
@@ -19684,6 +19686,339 @@ var PROJECT_INTELLIGENCE_ENGINEERING_LEAD_PROOF_VERIFICATION_SOURCES = [
19684
19686
  "manual",
19685
19687
  "unknown"
19686
19688
  ];
19689
+ var PROJECT_REALITY_CHECK_VERSION = "project-reality-check-v0";
19690
+ var SENSITIVE_SURFACES = [
19691
+ {
19692
+ key: "billing_atomicity",
19693
+ label: "Billing or payment settlement",
19694
+ type: "intent_vs_code",
19695
+ patterns: [/billing/i, /payment/i, /settlement/i, /invoice/i, /stripe/i],
19696
+ verificationPatterns: [/test/i, /spec/i, /e2e/i, /vitest/i, /pytest/i],
19697
+ riskTerms: [/async/i, /queue/i, /retry/i, /eventual/i, /background/i, /worker/i],
19698
+ defaultSeverity: "review_required"
19699
+ },
19700
+ {
19701
+ key: "auth_security",
19702
+ label: "Authentication or authorization",
19703
+ type: "verification_vs_claim",
19704
+ patterns: [/auth/i, /session/i, /permission/i, /role/i, /oauth/i, /token/i],
19705
+ verificationPatterns: [/test/i, /spec/i, /e2e/i, /permission/i, /auth/i],
19706
+ riskTerms: [/bypass/i, /public/i, /admin/i, /token/i, /session/i],
19707
+ defaultSeverity: "review_required"
19708
+ },
19709
+ {
19710
+ key: "schema_migration",
19711
+ label: "Database schema or migration",
19712
+ type: "verification_vs_claim",
19713
+ patterns: [/schema\.prisma$/i, /prisma\/migrations/i, /migration/i, /sql$/i],
19714
+ verificationPatterns: [/migration/i, /schema/i, /prisma/i, /test/i],
19715
+ riskTerms: [/drop/i, /delete/i, /reset/i, /force/i, /accept-data-loss/i],
19716
+ defaultSeverity: "review_required"
19717
+ },
19718
+ {
19719
+ key: "package_surface",
19720
+ label: "Published package or agent surface",
19721
+ type: "verification_vs_claim",
19722
+ patterns: [/packages\//i, /package\.json$/i, /CHANGELOG\.md$/i, /README\.md$/i],
19723
+ verificationPatterns: [/pack/i, /smoke/i, /help/i, /test/i, /type-check/i],
19724
+ riskTerms: [/bin/i, /cli/i, /npx/i, /command/i, /public/i],
19725
+ defaultSeverity: "watch"
19726
+ },
19727
+ {
19728
+ key: "deployment_surface",
19729
+ label: "Deployment or production operations",
19730
+ type: "verification_vs_claim",
19731
+ patterns: [/deploy/i, /docker/i, /traefik/i, /infomaniak/i, /production/i],
19732
+ verificationPatterns: [/smoke/i, /health/i, /ready/i, /deploy/i, /test/i],
19733
+ riskTerms: [/production/i, /secret/i, /migrate/i, /zero-downtime/i],
19734
+ defaultSeverity: "review_required"
19735
+ }
19736
+ ];
19737
+ var ARCHITECTURE_RULES = [
19738
+ {
19739
+ key: "web_mcp_boundary",
19740
+ title: "Web/MCP runtime boundary needs review",
19741
+ files: [/apps\/web\//i, /apps\/mcp-server\//i]
19742
+ },
19743
+ {
19744
+ key: "database_runtime_boundary",
19745
+ title: "Database contract crosses runtime boundary",
19746
+ files: [/packages\/database\//i, /apps\/mcp-server\/prisma/i, /apps\/web\//i]
19747
+ }
19748
+ ];
19749
+ function uniqueStrings8(values) {
19750
+ return [
19751
+ ...new Set(
19752
+ values.map((value) => value?.trim()).filter((value) => Boolean(value))
19753
+ )
19754
+ ];
19755
+ }
19756
+ function normalizeText(value) {
19757
+ return value?.toLowerCase() ?? "";
19758
+ }
19759
+ function hasPattern(values, patterns) {
19760
+ return values.some((value) => patterns.some((pattern) => pattern.test(value)));
19761
+ }
19762
+ function matchesAnyText(text, patterns) {
19763
+ return patterns.some((pattern) => pattern.test(text));
19764
+ }
19765
+ function findingSeverityScore(severity) {
19766
+ if (severity === "blocking") return 0;
19767
+ if (severity === "review_required") return 30;
19768
+ if (severity === "watch") return 70;
19769
+ return 90;
19770
+ }
19771
+ function resultStatusFromFindings(findings) {
19772
+ if (findings.some((finding) => finding.severity === "blocking")) return "blocking";
19773
+ if (findings.some((finding) => finding.severity === "review_required")) return "review_required";
19774
+ if (findings.some((finding) => finding.severity === "watch")) return "advisory";
19775
+ return "pass";
19776
+ }
19777
+ function makeFindingId(type, key, files) {
19778
+ const compactFiles = files.slice(0, 3).map(
19779
+ (file) => file.replace(/[^a-z0-9]+/gi, "-").replace(/^-|-$/g, "").toLowerCase()
19780
+ ).filter(Boolean).join("-");
19781
+ return ["reality", type, key, compactFiles || "project"].join(":").slice(0, 180);
19782
+ }
19783
+ function decisionMatchesChangedFiles(decision, changedFiles) {
19784
+ const anchors = decision.affectedAnchors ?? [];
19785
+ if (anchors.length === 0) return false;
19786
+ return anchors.some(
19787
+ (anchor) => changedFiles.some((file) => file.includes(anchor) || anchor.includes(file))
19788
+ );
19789
+ }
19790
+ function decisionText(decision) {
19791
+ return [
19792
+ decision.title,
19793
+ decision.decision,
19794
+ decision.rationale,
19795
+ decision.scope,
19796
+ ...decision.constraints ?? []
19797
+ ].filter(Boolean).join(" ");
19798
+ }
19799
+ function surfaceFiles(surface, changedFiles) {
19800
+ return changedFiles.filter((file) => surface.patterns.some((pattern) => pattern.test(file)));
19801
+ }
19802
+ function testFiles(changedFiles) {
19803
+ return changedFiles.filter(
19804
+ (file) => /(^|\/)(__tests__|tests?|e2e)(\/|$)|(\.test|\.spec)\.[jt]sx?$/i.test(file)
19805
+ );
19806
+ }
19807
+ function docEvidence(input) {
19808
+ return (input.documents ?? []).slice(0, 5).map((doc) => ({
19809
+ kind: "document",
19810
+ label: doc.title ? `${doc.path}: ${doc.title}` : doc.path,
19811
+ sourceRef: doc.sourceRef ?? doc.path,
19812
+ strength: 0.6
19813
+ }));
19814
+ }
19815
+ function symbolEvidence(input) {
19816
+ return (input.symbols ?? []).slice(0, 5).map((symbol) => ({
19817
+ kind: "code",
19818
+ label: `${symbol.qualifiedName} (${symbol.modulePath})`,
19819
+ sourceRef: symbol.modulePath,
19820
+ strength: 0.7
19821
+ }));
19822
+ }
19823
+ function decisionEvidence(decisions) {
19824
+ return decisions.slice(0, 5).map((decision) => ({
19825
+ kind: "decision",
19826
+ label: `${decision.id}: ${decision.title}`,
19827
+ sourceRef: decision.id,
19828
+ strength: decision.confidenceScore ?? 0.8
19829
+ }));
19830
+ }
19831
+ function buildProjectRealityCheck(input) {
19832
+ const changedFiles = uniqueStrings8(input.changedFiles);
19833
+ const dirtyFiles = uniqueStrings8(input.dirtyFiles ?? []);
19834
+ const diffText = normalizeText(input.diffSummary);
19835
+ const tests = testFiles(changedFiles);
19836
+ const findings = [];
19837
+ const decisions = input.decisions ?? [];
19838
+ const contextEvidence2 = [...docEvidence(input), ...symbolEvidence(input)];
19839
+ for (const surface of SENSITIVE_SURFACES) {
19840
+ const files = surfaceFiles(surface, changedFiles);
19841
+ if (files.length === 0) continue;
19842
+ const relatedDecisions = decisions.filter(
19843
+ (decision) => decisionMatchesChangedFiles(decision, files) || matchesAnyText(normalizeText(decisionText(decision)), surface.patterns)
19844
+ );
19845
+ const hasVerification = tests.length > 0 || hasPattern(input.verificationChecklist ?? [], surface.verificationPatterns);
19846
+ const hasRiskTerm = matchesAnyText(diffText, surface.riskTerms);
19847
+ const severity = surface.defaultSeverity === "watch" ? relatedDecisions.length > 0 && !hasVerification ? "review_required" : "watch" : hasVerification && !hasRiskTerm ? "watch" : surface.defaultSeverity;
19848
+ const reasonCodes2 = uniqueStrings8([
19849
+ surface.key,
19850
+ relatedDecisions.length > 0 ? "linked_decision_touched" : "no_linked_decision",
19851
+ hasVerification ? "verification_present" : "verification_missing",
19852
+ hasRiskTerm ? "risk_term_in_diff" : void 0
19853
+ ]);
19854
+ const recommendedActions = [
19855
+ hasVerification ? `Verify the ${surface.label.toLowerCase()} tests cover the changed behavior.` : `Add or cite verification for the ${surface.label.toLowerCase()} change before merge.`,
19856
+ relatedDecisions.length > 0 ? "Review the linked decision intent and supersede it if the implementation intentionally changes the rule." : "Capture or link the governing intent if this surface has no reviewed decision."
19857
+ ];
19858
+ findings.push({
19859
+ id: makeFindingId(surface.type, surface.key, files),
19860
+ type: surface.type,
19861
+ severity,
19862
+ title: `${surface.label} needs a reality check`,
19863
+ summary: `${files.length} changed file(s) touch ${surface.label.toLowerCase()} with ${relatedDecisions.length > 0 ? `${relatedDecisions.length} linked decision(s)` : "no linked decision"} and ${hasVerification ? "some verification evidence" : "no obvious verification evidence"}.`,
19864
+ changedFiles: files.slice(0, 12),
19865
+ decisionIds: relatedDecisions.map((decision) => decision.id).slice(0, 8),
19866
+ evidence: [...decisionEvidence(relatedDecisions), ...contextEvidence2].slice(0, 8),
19867
+ reasonCodes: reasonCodes2,
19868
+ recommendedActions,
19869
+ caveats: [
19870
+ "V0 uses path, decision, document, and verification signals; it does not prove semantic causality."
19871
+ ]
19872
+ });
19873
+ }
19874
+ for (const rule of ARCHITECTURE_RULES) {
19875
+ const matchedGroups = rule.files.filter(
19876
+ (patterns) => changedFiles.some((file) => patterns.test(file))
19877
+ );
19878
+ if (matchedGroups.length < 2) continue;
19879
+ const files = changedFiles.filter((file) => rule.files.some((pattern) => pattern.test(file)));
19880
+ findings.push({
19881
+ id: makeFindingId("architecture_drift", rule.key, files),
19882
+ type: "architecture_drift",
19883
+ severity: "watch",
19884
+ title: rule.title,
19885
+ summary: "This change spans architectural boundaries. Verify that the dependency direction and runtime ownership still match the intended architecture.",
19886
+ changedFiles: files.slice(0, 12),
19887
+ decisionIds: [],
19888
+ evidence: contextEvidence2.slice(0, 6),
19889
+ reasonCodes: [rule.key, "cross_boundary_change"],
19890
+ recommendedActions: [
19891
+ "Check that the changed modules do not introduce a forbidden runtime dependency.",
19892
+ "Document the boundary intent if this cross-boundary change is intentional."
19893
+ ],
19894
+ caveats: [
19895
+ "Architecture drift V0 is boundary-based; import-level drift needs code graph confirmation."
19896
+ ]
19897
+ });
19898
+ }
19899
+ if (changedFiles.length > 0 && decisions.length === 0 && (input.source === "pull_request" || findings.length > 0)) {
19900
+ findings.push({
19901
+ id: makeFindingId("decision_vs_code", "missing_intent", changedFiles),
19902
+ type: "decision_vs_code",
19903
+ severity: findings.some((finding) => finding.severity === "review_required") ? "watch" : "info",
19904
+ title: "No governing intent was linked",
19905
+ summary: "No reviewed decision or intent was linked to this change. This is an unknown, not proof that no constraint exists.",
19906
+ changedFiles: changedFiles.slice(0, 12),
19907
+ decisionIds: [],
19908
+ evidence: contextEvidence2.slice(0, 6),
19909
+ reasonCodes: ["missing_intent", "unknown_governing_decision"],
19910
+ recommendedActions: [
19911
+ "Link an existing decision or capture a review-pending intent if this change establishes a durable rule."
19912
+ ],
19913
+ caveats: [
19914
+ "A missing linked decision can reflect retrieval/index freshness rather than missing project truth."
19915
+ ]
19916
+ });
19917
+ }
19918
+ if (dirtyFiles.length > 0 && input.source === "local") {
19919
+ findings.push({
19920
+ id: makeFindingId("verification_vs_claim", "dirty_worktree", dirtyFiles),
19921
+ type: "verification_vs_claim",
19922
+ severity: "watch",
19923
+ title: "Dirty local files are part of the reality check",
19924
+ summary: `${dirtyFiles.length} dirty file(s) were included in the local scan; verify they are intentional before push.`,
19925
+ changedFiles: dirtyFiles.slice(0, 12),
19926
+ decisionIds: [],
19927
+ evidence: dirtyFiles.slice(0, 6).map((file) => ({
19928
+ kind: "repository",
19929
+ label: file,
19930
+ sourceRef: file,
19931
+ strength: 0.5
19932
+ })),
19933
+ reasonCodes: ["dirty_working_tree"],
19934
+ recommendedActions: [
19935
+ "Review dirty files separately from committed PR or upstream diff evidence."
19936
+ ],
19937
+ caveats: [
19938
+ "Dirty working-tree evidence is local-only and will not exist in hosted PR checks until committed."
19939
+ ]
19940
+ });
19941
+ }
19942
+ const status = resultStatusFromFindings(findings);
19943
+ const score = findings.length === 0 ? 95 : Math.max(
19944
+ 0,
19945
+ Math.min(
19946
+ 100,
19947
+ Math.round(
19948
+ Math.min(...findings.map((finding) => findingSeverityScore(finding.severity))) - Math.max(0, findings.length - 1) * 4
19949
+ )
19950
+ )
19951
+ );
19952
+ const requiredActions = uniqueStrings8(
19953
+ findings.filter(
19954
+ (finding) => finding.severity === "review_required" || finding.severity === "blocking"
19955
+ ).flatMap((finding) => finding.recommendedActions)
19956
+ ).slice(0, 10);
19957
+ const watchItems = uniqueStrings8(
19958
+ findings.filter((finding) => finding.severity === "watch" || finding.severity === "info").map((finding) => finding.summary)
19959
+ ).slice(0, 10);
19960
+ const reasonCodes = uniqueStrings8(findings.flatMap((finding) => finding.reasonCodes)).slice(
19961
+ 0,
19962
+ 20
19963
+ );
19964
+ const caveats = uniqueStrings8([
19965
+ "Project Reality Check V0 is advisory and evidence-backed; it is not deterministic repository simulation.",
19966
+ input.source === "local" ? "Local results may include dirty files that hosted PR checks cannot see." : "PR results are scoped to GitHub-provided PR files and indexed Snipara context."
19967
+ ]);
19968
+ return {
19969
+ version: PROJECT_REALITY_CHECK_VERSION,
19970
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
19971
+ status,
19972
+ score,
19973
+ source: input.source,
19974
+ summary: findings.length === 0 ? "No contradiction-to-reality finding was detected for this scope." : `${findings.length} reality check finding(s): ${status.replace("_", " ")}.`,
19975
+ changedFileCount: changedFiles.length,
19976
+ findingCount: findings.length,
19977
+ findings,
19978
+ requiredActions,
19979
+ watchItems,
19980
+ reasonCodes,
19981
+ caveats
19982
+ };
19983
+ }
19984
+ function renderProjectRealityCheckMarkdown(result) {
19985
+ const lines = [
19986
+ `- Status: ${result.status}; score ${result.score}/100.`,
19987
+ `- Scope: ${result.changedFileCount} changed file(s), ${result.findingCount} finding(s).`,
19988
+ `- Summary: ${result.summary}`
19989
+ ];
19990
+ if (result.findings.length > 0) {
19991
+ lines.push("", "Findings:");
19992
+ for (const finding of result.findings.slice(0, 8)) {
19993
+ lines.push(
19994
+ `- ${finding.severity.toUpperCase()} ${finding.type}: ${finding.title}`,
19995
+ ` ${finding.summary}`
19996
+ );
19997
+ if (finding.changedFiles.length > 0) {
19998
+ lines.push(` Files: ${finding.changedFiles.map((file) => `\`${file}\``).join(", ")}`);
19999
+ }
20000
+ if (finding.decisionIds.length > 0) {
20001
+ lines.push(` Decisions: ${finding.decisionIds.join(", ")}`);
20002
+ }
20003
+ if (finding.recommendedActions.length > 0) {
20004
+ lines.push(` Action: ${finding.recommendedActions[0]}`);
20005
+ }
20006
+ }
20007
+ }
20008
+ if (result.requiredActions.length > 0) {
20009
+ lines.push("", "Required actions:");
20010
+ lines.push(...result.requiredActions.map((action) => `- ${action}`));
20011
+ }
20012
+ if (result.watchItems.length > 0) {
20013
+ lines.push("", "Watch items:");
20014
+ lines.push(...result.watchItems.map((item) => `- ${item}`));
20015
+ }
20016
+ if (result.caveats.length > 0) {
20017
+ lines.push("", "Caveats:");
20018
+ lines.push(...result.caveats.map((caveat) => `- ${caveat}`));
20019
+ }
20020
+ return lines.join("\n");
20021
+ }
19687
20022
 
19688
20023
  // src/commands/execution-receipts.ts
19689
20024
  var ENGINEERING_LEAD_PROOF_VERIFICATION_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1e3;
@@ -21378,7 +21713,7 @@ function normalizeCaptureEvent(event, now, index) {
21378
21713
  const reasons = normalizeStringList3(event.reason).map(redactText);
21379
21714
  const evidence = normalizeStringList3(event.evidence).map(redactText);
21380
21715
  const commands = normalizeStringList3(event.commands).map(redactText);
21381
- const redactionPatterns = uniqueStrings8([
21716
+ const redactionPatterns = uniqueStrings9([
21382
21717
  ...summary.patterns,
21383
21718
  ...outcome.patterns,
21384
21719
  ...status.patterns,
@@ -21411,7 +21746,7 @@ function normalizeEventKind(value) {
21411
21746
  return "feedback";
21412
21747
  }
21413
21748
  function reasonCodesForEvent(event, kind, status) {
21414
- return uniqueStrings8([
21749
+ return uniqueStrings9([
21415
21750
  "why_outcome_capture_v1",
21416
21751
  "review_pending_authority",
21417
21752
  `source_${event.kind}`,
@@ -21476,7 +21811,7 @@ function readEventsFromFile(filePath) {
21476
21811
  function stableHash(parts) {
21477
21812
  return (0, import_node_crypto3.createHash)("sha256").update(parts.join("\0")).digest("hex");
21478
21813
  }
21479
- function uniqueStrings8(values) {
21814
+ function uniqueStrings9(values) {
21480
21815
  return Array.from(new Set(values.filter(Boolean)));
21481
21816
  }
21482
21817
  function compactWhitespace2(value) {
@@ -21574,7 +21909,7 @@ function createRedactor(rootDir) {
21574
21909
  patterns.add(item.name);
21575
21910
  item.pattern.lastIndex = 0;
21576
21911
  }
21577
- const uniqueMatchedPatterns = uniqueStrings9(matchedPatterns);
21912
+ const uniqueMatchedPatterns = uniqueStrings10(matchedPatterns);
21578
21913
  if (uniqueMatchedPatterns.length > 0) {
21579
21914
  redactedValueCount += 1;
21580
21915
  }
@@ -21689,14 +22024,14 @@ function buildRepoState(input, options, rootDir, redactor) {
21689
22024
  const inputRepo = inputRecord(input, "repoState", "repo_state", "repo");
21690
22025
  const detected = detectGitState(rootDir);
21691
22026
  const statusCounts = countGitStatus(detected.statusLines);
21692
- const changedFiles = uniqueStrings9([
22027
+ const changedFiles = uniqueStrings10([
21693
22028
  ...normalizeUnknownStringList(inputRepo.changedFiles),
21694
22029
  ...normalizeUnknownStringList(inputRepo.changed_files),
21695
22030
  ...normalizeUnknownStringList(input.changedFiles),
21696
22031
  ...normalizeUnknownStringList(input.changed_files),
21697
22032
  ...options.changedFiles ?? []
21698
22033
  ]).map((item) => redactor.redact(item).value);
21699
- const recentFiles = uniqueStrings9([
22034
+ const recentFiles = uniqueStrings10([
21700
22035
  ...normalizeUnknownStringList(inputRepo.recentFiles),
21701
22036
  ...normalizeUnknownStringList(inputRepo.recent_files),
21702
22037
  ...normalizeUnknownStringList(input.recentFiles),
@@ -21764,18 +22099,18 @@ function normalizeEvidenceItem(value, section, index, redactor) {
21764
22099
  "command",
21765
22100
  "check"
21766
22101
  ]) ?? fallbackSummary(value, section, index);
21767
- const reasonCodes = uniqueStrings9([
22102
+ const reasonCodes = uniqueStrings10([
21768
22103
  `section_${section}`,
21769
22104
  ...normalizeUnknownStringList(value.reasonCodes),
21770
22105
  ...normalizeUnknownStringList(value.reason_codes)
21771
22106
  ]).map((item) => redactor.redact(item).value);
21772
- const files = uniqueStrings9([
22107
+ const files = uniqueStrings10([
21773
22108
  ...normalizeUnknownStringList(value.files),
21774
22109
  ...normalizeUnknownStringList(value.changedFiles),
21775
22110
  ...normalizeUnknownStringList(value.changed_files),
21776
22111
  ...normalizeUnknownStringList(value.file)
21777
22112
  ]).slice(0, MAX_LIST_ITEMS2).map((item) => redactor.redact(item).value);
21778
- const commands = uniqueStrings9([
22113
+ const commands = uniqueStrings10([
21779
22114
  ...normalizeUnknownStringList(value.commands),
21780
22115
  ...normalizeUnknownStringList(value.command),
21781
22116
  ...normalizeUnknownStringList(value.checks),
@@ -21799,7 +22134,7 @@ function normalizeEvidenceItem(value, section, index, redactor) {
21799
22134
  });
21800
22135
  }
21801
22136
  function collectReasonCodes(input, cliValues, items, redactor) {
21802
- return uniqueStrings9([
22137
+ return uniqueStrings10([
21803
22138
  "coding_intelligence_ledger_v0",
21804
22139
  ...normalizeUnknownStringList(input.reasonCodes),
21805
22140
  ...normalizeUnknownStringList(input.reason_codes),
@@ -21830,13 +22165,13 @@ function buildCalibrationMetadata(input, cliValues, redactor) {
21830
22165
  "calibration",
21831
22166
  "calibration_metadata"
21832
22167
  );
21833
- const notes = uniqueStrings9([
22168
+ const notes = uniqueStrings10([
21834
22169
  ...normalizeUnknownStringList(calibration.notes),
21835
22170
  ...normalizeUnknownStringList(calibration.note),
21836
22171
  ...normalizeUnknownStringList(input.calibrationNotes),
21837
22172
  ...cliValues ?? []
21838
22173
  ]).slice(0, MAX_LIST_ITEMS2).map((item) => redactor.redact(item).value);
21839
- const caveats = uniqueStrings9([
22174
+ const caveats = uniqueStrings10([
21840
22175
  ...normalizeUnknownStringList(calibration.caveats),
21841
22176
  ...normalizeUnknownStringList(calibration.caveat),
21842
22177
  ...normalizeUnknownStringList(input.calibrationCaveats)
@@ -22033,7 +22368,7 @@ function validIso(value) {
22033
22368
  const date = new Date(value);
22034
22369
  return Number.isNaN(date.getTime()) ? void 0 : date.toISOString();
22035
22370
  }
22036
- function uniqueStrings9(values) {
22371
+ function uniqueStrings10(values) {
22037
22372
  return Array.from(new Set(values.map((value) => value.trim()).filter(Boolean)));
22038
22373
  }
22039
22374
  function compactWhitespace3(value) {
@@ -23516,14 +23851,154 @@ async function projectIntelligenceBriefCommand(options) {
23516
23851
  }
23517
23852
  }
23518
23853
 
23854
+ // src/commands/reality-check.ts
23855
+ var import_node_child_process8 = require("child_process");
23856
+ var import_node_path = __toESM(require("path"));
23857
+ var import_chalk10 = __toESM(require("chalk"));
23858
+ function runGit2(args, cwd, options = {}) {
23859
+ try {
23860
+ const output = (0, import_node_child_process8.execFileSync)("git", args, {
23861
+ cwd,
23862
+ encoding: "utf8",
23863
+ stdio: ["ignore", "pipe", "ignore"],
23864
+ timeout: 5e3
23865
+ });
23866
+ return options.preserveLeadingWhitespace ? output.trimEnd() : output.trim();
23867
+ } catch {
23868
+ return void 0;
23869
+ }
23870
+ }
23871
+ function splitLines(value) {
23872
+ return value ? value.split(/\r?\n/g).map((line) => line.trim()).filter(Boolean) : [];
23873
+ }
23874
+ function unique5(values) {
23875
+ return [
23876
+ ...new Set(
23877
+ values.map((value) => value?.trim()).filter((value) => Boolean(value))
23878
+ )
23879
+ ];
23880
+ }
23881
+ function parseDirtyFile(line) {
23882
+ if (!line.trim()) return void 0;
23883
+ const withoutStatus = line.length >= 3 ? line.slice(3).trim() : line.trim();
23884
+ const renameParts = withoutStatus.split(" -> ");
23885
+ return renameParts[renameParts.length - 1]?.replace(/^"|"$/g, "");
23886
+ }
23887
+ function resolveGitRoot(cwd) {
23888
+ return runGit2(["rev-parse", "--show-toplevel"], cwd) ?? cwd;
23889
+ }
23890
+ function resolveBaseRef(root, explicitBase) {
23891
+ if (explicitBase) return explicitBase;
23892
+ return runGit2(["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"], root) ?? void 0;
23893
+ }
23894
+ function buildLocalGitScope(options) {
23895
+ const requestedRoot = import_node_path.default.resolve(options.dir ?? process.cwd());
23896
+ const workspaceRoot = findWorkspaceRoot(requestedRoot, true) ?? requestedRoot;
23897
+ const root = resolveGitRoot(workspaceRoot);
23898
+ const branch = options.branch ?? runGit2(["rev-parse", "--abbrev-ref", "HEAD"], root);
23899
+ const baseRef = resolveBaseRef(root, options.base);
23900
+ const headRef = runGit2(["rev-parse", "--verify", "HEAD"], root);
23901
+ const statusLines = runGit2(["status", "--short"], root, { preserveLeadingWhitespace: true })?.split(/\r?\n/g).filter((line) => line.trim()) ?? [];
23902
+ const dirtyFiles = unique5(statusLines.map(parseDirtyFile));
23903
+ const committedFiles = baseRef ? splitLines(runGit2(["diff", "--name-only", `${baseRef}...HEAD`], root)) : [];
23904
+ const cachedFiles = splitLines(runGit2(["diff", "--cached", "--name-only"], root));
23905
+ const unstagedFiles = splitLines(runGit2(["diff", "--name-only"], root));
23906
+ const changedFiles = unique5([
23907
+ ...options.changedFiles ?? [],
23908
+ ...committedFiles,
23909
+ ...cachedFiles,
23910
+ ...options.includeDirty === false ? [] : unstagedFiles
23911
+ ]);
23912
+ const diffSummary = options.diffSummary ?? [
23913
+ baseRef ? runGit2(["diff", "--stat", `${baseRef}...HEAD`], root) : void 0,
23914
+ options.includeDirty === false ? void 0 : runGit2(["diff", "--stat"], root)
23915
+ ].filter(Boolean).join("\n");
23916
+ const caveats = [
23917
+ baseRef ? void 0 : "No upstream/base ref was resolved; local reality check used dirty/cached files only.",
23918
+ dirtyFiles.length > 0 && options.includeDirty === false ? "Dirty files were detected but excluded by --no-include-dirty." : void 0
23919
+ ].filter((item) => Boolean(item));
23920
+ return {
23921
+ root,
23922
+ ...branch && branch !== "HEAD" ? { branch } : {},
23923
+ ...baseRef ? { baseRef } : {},
23924
+ ...headRef ? { headRef } : {},
23925
+ changedFiles,
23926
+ dirtyFiles: options.includeDirty === false ? [] : dirtyFiles,
23927
+ ...diffSummary ? { diffSummary } : {},
23928
+ caveats
23929
+ };
23930
+ }
23931
+ function parseDecision(value, index) {
23932
+ const [rawId, ...rest] = value.split(":");
23933
+ const hasExplicitId = rest.length > 0 && rawId.trim().length > 0;
23934
+ const id = hasExplicitId ? rawId.trim() : `local-decision-${index + 1}`;
23935
+ const title = hasExplicitId ? rest.join(":").trim() : value.trim();
23936
+ return {
23937
+ id,
23938
+ title: title || id,
23939
+ decision: title || value,
23940
+ confidenceScore: 0.75
23941
+ };
23942
+ }
23943
+ function parseDocument(value) {
23944
+ const [rawPath, ...rest] = value.split(":");
23945
+ return {
23946
+ path: rawPath.trim() || value,
23947
+ contentPreview: rest.join(":").trim() || null
23948
+ };
23949
+ }
23950
+ function buildLocalProjectRealityCheck(options) {
23951
+ const scope = buildLocalGitScope(options);
23952
+ const result = buildProjectRealityCheck({
23953
+ source: "local",
23954
+ task: options.task,
23955
+ branch: scope.branch,
23956
+ baseRef: scope.baseRef,
23957
+ headRef: scope.headRef,
23958
+ changedFiles: scope.changedFiles,
23959
+ dirtyFiles: scope.dirtyFiles,
23960
+ diffSummary: scope.diffSummary,
23961
+ decisions: (options.decision ?? []).map(parseDecision),
23962
+ documents: (options.document ?? []).map(parseDocument),
23963
+ verificationChecklist: options.verification ?? []
23964
+ });
23965
+ if (scope.caveats.length === 0) {
23966
+ return result;
23967
+ }
23968
+ return {
23969
+ ...result,
23970
+ caveats: [...result.caveats, ...scope.caveats]
23971
+ };
23972
+ }
23973
+ function printRealityCheck(result) {
23974
+ console.log(import_chalk10.default.bold("Project Reality Check"));
23975
+ console.log(`Status: ${result.status}`);
23976
+ console.log(`Score: ${result.score}/100`);
23977
+ console.log(`Changed files: ${result.changedFileCount}`);
23978
+ console.log(`Findings: ${result.findingCount}`);
23979
+ console.log("");
23980
+ console.log(renderProjectRealityCheckMarkdown(result));
23981
+ }
23982
+ async function realityCheckCommand(options) {
23983
+ const result = buildLocalProjectRealityCheck(options);
23984
+ if (options.json) {
23985
+ console.log(JSON.stringify(result, null, 2));
23986
+ } else {
23987
+ printRealityCheck(result);
23988
+ }
23989
+ if (options.enforce && (result.status === "review_required" || result.status === "blocking")) {
23990
+ process.exitCode = 1;
23991
+ }
23992
+ }
23993
+
23519
23994
  // src/commands/references.ts
23520
23995
  var crypto6 = __toESM(require("crypto"));
23521
23996
  var fs25 = __toESM(require("fs"));
23522
- var path24 = __toESM(require("path"));
23523
- var import_chalk10 = __toESM(require("chalk"));
23997
+ var path25 = __toESM(require("path"));
23998
+ var import_chalk11 = __toESM(require("chalk"));
23524
23999
  var MANIFEST_VERSION2 = "snipara.references.v1";
23525
- var DEFAULT_MANIFEST_PATH = path24.join(".snipara", "references", "manifest.json");
23526
- var DEFAULT_SNAPSHOT_DIR = path24.join(".snipara", "references", "snapshots");
24000
+ var DEFAULT_MANIFEST_PATH = path25.join(".snipara", "references", "manifest.json");
24001
+ var DEFAULT_SNAPSHOT_DIR = path25.join(".snipara", "references", "snapshots");
23527
24002
  var DEFAULT_DESTINATION_PREFIX = "external-references";
23528
24003
  var DEFAULT_SCAN_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".mdx", ".txt", ".rst"]);
23529
24004
  var DEFAULT_IGNORE_DIRS = /* @__PURE__ */ new Set([
@@ -23599,10 +24074,10 @@ function sanitizeSegment(value, fallback) {
23599
24074
  return sanitized || fallback;
23600
24075
  }
23601
24076
  function toRelative(root, file) {
23602
- return path24.relative(root, file).split(path24.sep).join("/");
24077
+ return path25.relative(root, file).split(path25.sep).join("/");
23603
24078
  }
23604
24079
  function ensureParentDir(file) {
23605
- fs25.mkdirSync(path24.dirname(file), { recursive: true });
24080
+ fs25.mkdirSync(path25.dirname(file), { recursive: true });
23606
24081
  }
23607
24082
  function walkFiles(root, extensions, maxFiles, files = []) {
23608
24083
  if (files.length >= maxFiles) {
@@ -23612,14 +24087,14 @@ function walkFiles(root, extensions, maxFiles, files = []) {
23612
24087
  if (files.length >= maxFiles) {
23613
24088
  break;
23614
24089
  }
23615
- const fullPath = path24.join(root, entry.name);
24090
+ const fullPath = path25.join(root, entry.name);
23616
24091
  if (entry.isDirectory()) {
23617
24092
  if (!DEFAULT_IGNORE_DIRS.has(entry.name)) {
23618
24093
  walkFiles(fullPath, extensions, maxFiles, files);
23619
24094
  }
23620
24095
  continue;
23621
24096
  }
23622
- if (entry.isFile() && extensions.has(path24.extname(entry.name).toLowerCase())) {
24097
+ if (entry.isFile() && extensions.has(path25.extname(entry.name).toLowerCase())) {
23623
24098
  files.push(fullPath);
23624
24099
  }
23625
24100
  }
@@ -23674,8 +24149,8 @@ function collectReferenceItems(root, files, allowDomains, denyDomains) {
23674
24149
  return Array.from(byUrl.values()).sort((a, b) => a.normalizedUrl.localeCompare(b.normalizedUrl));
23675
24150
  }
23676
24151
  function scanReferences(options = {}) {
23677
- const root = path24.resolve(options.root ?? process.cwd());
23678
- const outputPath = path24.resolve(root, options.output ?? DEFAULT_MANIFEST_PATH);
24152
+ const root = path25.resolve(options.root ?? process.cwd());
24153
+ const outputPath = path25.resolve(root, options.output ?? DEFAULT_MANIFEST_PATH);
23679
24154
  const allowDomains = normalizeList(options.allowDomain);
23680
24155
  const denyDomains = normalizeList(options.denyDomain);
23681
24156
  const extensions = new Set(
@@ -23777,8 +24252,8 @@ async function fetchReference(item, outputDir, destinationPrefix, timeoutMs, max
23777
24252
  slugSource,
23778
24253
  item.id
23779
24254
  )}-${item.id}.md`;
23780
- const snapshotPath = path24.resolve(outputDir, fileName);
23781
- const destinationPath = path24.posix.join(
24255
+ const snapshotPath = path25.resolve(outputDir, fileName);
24256
+ const destinationPath = path25.posix.join(
23782
24257
  destinationPrefix.replace(/^\/+|\/+$/g, "") || DEFAULT_DESTINATION_PREFIX,
23783
24258
  fileName
23784
24259
  );
@@ -23823,14 +24298,14 @@ function selectItems(manifest, options, allowDomains) {
23823
24298
  return typeof options.max === "number" && options.max > 0 ? selected.slice(0, options.max) : selected;
23824
24299
  }
23825
24300
  async function ingestReferences(options = {}) {
23826
- const manifestPath = path24.resolve(options.manifest ?? DEFAULT_MANIFEST_PATH);
24301
+ const manifestPath = path25.resolve(options.manifest ?? DEFAULT_MANIFEST_PATH);
23827
24302
  const manifest = readManifest2(manifestPath);
23828
- const root = manifest.root ? path24.resolve(manifest.root) : process.cwd();
24303
+ const root = manifest.root ? path25.resolve(manifest.root) : process.cwd();
23829
24304
  const allowDomains = normalizeList([
23830
24305
  ...manifest.allowDomains ?? [],
23831
24306
  ...options.allowDomain ?? []
23832
24307
  ]);
23833
- const outputDir = path24.resolve(root, options.outputDir ?? DEFAULT_SNAPSHOT_DIR);
24308
+ const outputDir = path25.resolve(root, options.outputDir ?? DEFAULT_SNAPSHOT_DIR);
23834
24309
  const destinationPrefix = options.destinationPrefix ?? DEFAULT_DESTINATION_PREFIX;
23835
24310
  const items = selectItems(manifest, options, allowDomains);
23836
24311
  const summary = {
@@ -23857,7 +24332,7 @@ async function ingestReferences(options = {}) {
23857
24332
  options.maxBytes ?? 512 * 1024
23858
24333
  );
23859
24334
  summary.fetched += 1;
23860
- item.latestSnapshotPath = path24.relative(root, snapshot.snapshotPath).split(path24.sep).join("/");
24335
+ item.latestSnapshotPath = path25.relative(root, snapshot.snapshotPath).split(path25.sep).join("/");
23861
24336
  item.latestFetchStatus = snapshot.status;
23862
24337
  item.latestFetchAt = snapshot.fetchedAt;
23863
24338
  item.latestContentHash = snapshot.contentHash;
@@ -23920,7 +24395,7 @@ async function referencesScanCommand(options) {
23920
24395
  printJson4(result);
23921
24396
  return;
23922
24397
  }
23923
- console.log(import_chalk10.default.bold("External References"));
24398
+ console.log(import_chalk11.default.bold("External References"));
23924
24399
  console.log(`Manifest: ${result.outputPath}`);
23925
24400
  console.log(`Files scanned: ${result.scannedFiles}`);
23926
24401
  console.log(`URLs found: ${result.foundUrls}`);
@@ -23929,7 +24404,7 @@ async function referencesScanCommand(options) {
23929
24404
  console.log(`Denied: ${result.denied}`);
23930
24405
  if (result.pending > 0) {
23931
24406
  console.log(
23932
- import_chalk10.default.gray("Re-run with --allow-domain <domain> or pass --allow-domain to ingest.")
24407
+ import_chalk11.default.gray("Re-run with --allow-domain <domain> or pass --allow-domain to ingest.")
23933
24408
  );
23934
24409
  }
23935
24410
  }
@@ -23939,7 +24414,7 @@ async function referencesIngestCommand(options) {
23939
24414
  printJson4(result);
23940
24415
  return;
23941
24416
  }
23942
- console.log(import_chalk10.default.bold("External Reference Ingest"));
24417
+ console.log(import_chalk11.default.bold("External Reference Ingest"));
23943
24418
  console.log(`Manifest: ${result.manifestPath}`);
23944
24419
  console.log(`Selected: ${result.selected}`);
23945
24420
  if (result.dryRun) {
@@ -23956,8 +24431,8 @@ async function referencesIngestCommand(options) {
23956
24431
  }
23957
24432
 
23958
24433
  // src/commands/run.ts
23959
- var import_node_child_process8 = require("child_process");
23960
- var import_chalk11 = __toESM(require("chalk"));
24434
+ var import_node_child_process9 = require("child_process");
24435
+ var import_chalk12 = __toESM(require("chalk"));
23961
24436
 
23962
24437
  // src/commands/policy-gates.ts
23963
24438
  var REGISTRY_VERSION = "project-intelligence.policy-gates.registry.v1";
@@ -24721,7 +25196,7 @@ function runGuard(options, changedFiles) {
24721
25196
  if (options.task) {
24722
25197
  args.push("--action", options.release ? "release" : "run");
24723
25198
  }
24724
- const result = (0, import_node_child_process8.spawnSync)(process.execPath, args, {
25199
+ const result = (0, import_node_child_process9.spawnSync)(process.execPath, args, {
24725
25200
  cwd: process.cwd(),
24726
25201
  encoding: "utf8",
24727
25202
  env: process.env,
@@ -24753,7 +25228,7 @@ function runPackageReview(options) {
24753
25228
  };
24754
25229
  }
24755
25230
  try {
24756
- const output = (0, import_node_child_process8.execFileSync)(
25231
+ const output = (0, import_node_child_process9.execFileSync)(
24757
25232
  "npm",
24758
25233
  ["view", "snipara-companion", "version", "bin", "dist-tags", "--json"],
24759
25234
  {
@@ -24866,19 +25341,19 @@ async function projectIntelligenceRunCommand(options) {
24866
25341
  if (options.json) {
24867
25342
  console.log(JSON.stringify(result, null, 2));
24868
25343
  } else {
24869
- console.log(import_chalk11.default.bold("Project Intelligence Run"));
25344
+ console.log(import_chalk12.default.bold("Project Intelligence Run"));
24870
25345
  if (result.brief.task) {
24871
25346
  console.log(`Task: ${result.brief.task}`);
24872
25347
  }
24873
25348
  console.log(`Release: ${result.release ? "yes" : "no"}`);
24874
25349
  console.log("");
24875
- console.log(import_chalk11.default.bold("Project Judgment"));
25350
+ console.log(import_chalk12.default.bold("Project Judgment"));
24876
25351
  for (const line of formatProjectJudgmentCard(result.judgmentCard)) {
24877
25352
  console.log(line);
24878
25353
  }
24879
25354
  console.log("");
24880
25355
  if (result.policyGates.gates.length > 0) {
24881
- console.log(import_chalk11.default.bold("Policy Gates"));
25356
+ console.log(import_chalk12.default.bold("Policy Gates"));
24882
25357
  console.log(
24883
25358
  `Strongest: ${result.policyGates.summary.strongestSeverity}; advisory ${result.policyGates.summary.advisory}, required ${result.policyGates.summary.requiredAction}, block ${result.policyGates.summary.block}`
24884
25359
  );
@@ -24890,7 +25365,7 @@ async function projectIntelligenceRunCommand(options) {
24890
25365
  console.log("");
24891
25366
  }
24892
25367
  if (result.guard) {
24893
- console.log(import_chalk11.default.bold("Guard"));
25368
+ console.log(import_chalk12.default.bold("Guard"));
24894
25369
  console.log(`Status: ${result.guard.status}`);
24895
25370
  const actionCards = isRecord15(result.guard.payload) ? result.guard.payload.actionCards : [];
24896
25371
  if (Array.isArray(actionCards) && actionCards.length > 0) {
@@ -24902,7 +25377,7 @@ async function projectIntelligenceRunCommand(options) {
24902
25377
  console.log("");
24903
25378
  }
24904
25379
  if (result.packageReview) {
24905
- console.log(import_chalk11.default.bold("Package Review"));
25380
+ console.log(import_chalk12.default.bold("Package Review"));
24906
25381
  console.log(`${result.packageReview.packageName}: ${result.packageReview.status}`);
24907
25382
  if (result.packageReview.error) {
24908
25383
  console.log(result.packageReview.error);
@@ -24910,7 +25385,7 @@ async function projectIntelligenceRunCommand(options) {
24910
25385
  console.log("");
24911
25386
  }
24912
25387
  if (result.advisorReceiptCapture) {
24913
- console.log(import_chalk11.default.bold("Advisor Receipts"));
25388
+ console.log(import_chalk12.default.bold("Advisor Receipts"));
24914
25389
  console.log(`Status: ${result.advisorReceiptCapture.status}`);
24915
25390
  if (result.advisorReceiptCapture.servedJudgmentId) {
24916
25391
  console.log(`Served judgment: ${result.advisorReceiptCapture.servedJudgmentId}`);
@@ -24931,7 +25406,7 @@ async function projectIntelligenceRunCommand(options) {
24931
25406
  }
24932
25407
  console.log("");
24933
25408
  }
24934
- console.log(import_chalk11.default.bold("Suggested Commands"));
25409
+ console.log(import_chalk12.default.bold("Suggested Commands"));
24935
25410
  for (const command of result.suggestedCommands.slice(0, 8)) {
24936
25411
  console.log(command);
24937
25412
  }
@@ -24942,12 +25417,12 @@ async function projectIntelligenceRunCommand(options) {
24942
25417
  }
24943
25418
 
24944
25419
  // src/commands/collaboration.ts
24945
- var import_node_child_process9 = require("child_process");
25420
+ var import_node_child_process10 = require("child_process");
24946
25421
  var import_node_crypto5 = require("crypto");
24947
25422
  var fs26 = __toESM(require("fs"));
24948
25423
  var os6 = __toESM(require("os"));
24949
- var path25 = __toESM(require("path"));
24950
- var COLLABORATION_STATE_RELATIVE_PATH = path25.join(
25424
+ var path26 = __toESM(require("path"));
25425
+ var COLLABORATION_STATE_RELATIVE_PATH = path26.join(
24951
25426
  ".snipara",
24952
25427
  "collaboration",
24953
25428
  "session.json"
@@ -25034,7 +25509,7 @@ function createEmptyCollaborationState(now = /* @__PURE__ */ new Date()) {
25034
25509
  };
25035
25510
  }
25036
25511
  function getCollaborationStatePath(rootDir = process.cwd()) {
25037
- return path25.join(rootDir, COLLABORATION_STATE_RELATIVE_PATH);
25512
+ return path26.join(rootDir, COLLABORATION_STATE_RELATIVE_PATH);
25038
25513
  }
25039
25514
  function loadCollaborationState(rootDir = process.cwd()) {
25040
25515
  const statePath = getCollaborationStatePath(rootDir);
@@ -25068,7 +25543,7 @@ function loadCollaborationState(rootDir = process.cwd()) {
25068
25543
  }
25069
25544
  function saveCollaborationState(state, rootDir = process.cwd()) {
25070
25545
  const statePath = getCollaborationStatePath(rootDir);
25071
- fs26.mkdirSync(path25.dirname(statePath), { recursive: true });
25546
+ fs26.mkdirSync(path26.dirname(statePath), { recursive: true });
25072
25547
  const tempPath = `${statePath}.${process.pid}.${Date.now()}.tmp`;
25073
25548
  try {
25074
25549
  fs26.writeFileSync(tempPath, `${JSON.stringify(state, null, 2)}
@@ -25487,7 +25962,7 @@ async function collaborationIdeStatusCommand(options) {
25487
25962
  console.log(`Active leases: ${payload.hosted.activeLeases.length}`);
25488
25963
  }
25489
25964
  function resolveCollaborationContext(options) {
25490
- const rootDir = path25.resolve(options.dir ?? process.cwd());
25965
+ const rootDir = path26.resolve(options.dir ?? process.cwd());
25491
25966
  const config = loadConfig({ cwd: rootDir });
25492
25967
  const actor = buildCollaborationActor(options, config);
25493
25968
  return {
@@ -25823,9 +26298,9 @@ function readGitChangedFiles(rootDir, args) {
25823
26298
  return output ? normalizeFiles2(output.split(/\r?\n/)) : [];
25824
26299
  }
25825
26300
  function resolveRepoRoot3(cwd) {
25826
- const resolved = path25.resolve(cwd);
26301
+ const resolved = path26.resolve(cwd);
25827
26302
  const gitRoot = readGitValue3(resolved, ["rev-parse", "--show-toplevel"]);
25828
- return gitRoot ? path25.resolve(gitRoot) : resolved;
26303
+ return gitRoot ? path26.resolve(gitRoot) : resolved;
25829
26304
  }
25830
26305
  function deriveGuardProfileResources(profile, files) {
25831
26306
  const resources = [];
@@ -26030,7 +26505,7 @@ function readGitRawValue(rootDir, args) {
26030
26505
  stdio: ["ignore", "pipe", "ignore"],
26031
26506
  timeout: 1e3
26032
26507
  };
26033
- const output = (0, import_node_child_process9.execFileSync)("git", args, execOptions);
26508
+ const output = (0, import_node_child_process10.execFileSync)("git", args, execOptions);
26034
26509
  return output || void 0;
26035
26510
  } catch {
26036
26511
  return void 0;
@@ -26076,16 +26551,16 @@ ${nextBlock}`);
26076
26551
  }
26077
26552
  function resolveGitHooksDir2(repoRoot) {
26078
26553
  const gitHooksPath = readGitValue3(repoRoot, ["rev-parse", "--git-path", "hooks"]);
26079
- const hooksDir = path25.resolve(repoRoot, gitHooksPath ?? path25.join(".git", "hooks"));
26080
- const huskyUserHooksDir = path25.dirname(hooksDir);
26081
- if (path25.basename(hooksDir) === "_" && path25.basename(huskyUserHooksDir) === ".husky" && fs26.existsSync(path25.join(hooksDir, "h"))) {
26554
+ const hooksDir = path26.resolve(repoRoot, gitHooksPath ?? path26.join(".git", "hooks"));
26555
+ const huskyUserHooksDir = path26.dirname(hooksDir);
26556
+ if (path26.basename(hooksDir) === "_" && path26.basename(huskyUserHooksDir) === ".husky" && fs26.existsSync(path26.join(hooksDir, "h"))) {
26082
26557
  return huskyUserHooksDir;
26083
26558
  }
26084
26559
  return hooksDir;
26085
26560
  }
26086
26561
  function installManagedCollaborationGitHook(repoRoot, hookName, options) {
26087
26562
  const hooksDir = resolveGitHooksDir2(repoRoot);
26088
- const hookPath = path25.join(hooksDir, hookName);
26563
+ const hookPath = path26.join(hooksDir, hookName);
26089
26564
  const currentContent = fs26.existsSync(hookPath) ? fs26.readFileSync(hookPath, "utf8") : null;
26090
26565
  const block = buildCollaborationGitHookBlock(hookName);
26091
26566
  const nextContent = mergeManagedCollaborationHookBlock(hookName, currentContent, block);
@@ -26566,7 +27041,7 @@ function normalizeResourceId(kind, id) {
26566
27041
  return normalized;
26567
27042
  }
26568
27043
  function normalizeRepoPath3(value) {
26569
- return value.trim().split(path25.sep).join("/").replace(/^\.?\//, "");
27044
+ return value.trim().split(path26.sep).join("/").replace(/^\.?\//, "");
26570
27045
  }
26571
27046
  function normalizeOptionalString2(value) {
26572
27047
  const normalized = typeof value === "string" ? value.trim() : "";
@@ -26807,6 +27282,24 @@ var program = new import_commander.Command();
26807
27282
  function collectOption(value, previous = []) {
26808
27283
  return [...previous, value];
26809
27284
  }
27285
+ function configureRealityCheckCommand(command) {
27286
+ return command.description("Run a Project Reality Check against local or supplied change scope").option("--task <task>", "Task or change summary").option("--branch <branch>", "Branch to scope the check").option("--base <ref>", "Base ref for committed local changes (default: upstream)").option("--changed-files <files...>", "Changed files to analyze").option("--diff-summary <summary>", "Natural-language diff summary").option("--decision <decision...>", "Decision or intent in ID: text form").option("--document <document...>", "Document/context hint in path: preview form").option("--verification <item...>", "Verification evidence or checklist item").option("--no-include-dirty", "Exclude dirty working-tree files from local scope").option("--enforce", "Exit non-zero for review-required or blocking findings").option("-d, --dir <directory>", "Project directory (default: current)").option("--json", "Print raw JSON").action(async (options) => {
27287
+ await realityCheckCommand({
27288
+ task: options.task,
27289
+ branch: options.branch,
27290
+ base: options.base,
27291
+ changedFiles: options.changedFiles,
27292
+ diffSummary: options.diffSummary,
27293
+ decision: options.decision,
27294
+ document: options.document,
27295
+ verification: options.verification,
27296
+ includeDirty: options.includeDirty,
27297
+ enforce: Boolean(options.enforce),
27298
+ dir: options.dir,
27299
+ json: Boolean(options.json)
27300
+ });
27301
+ });
27302
+ }
26810
27303
  program.name("snipara-companion").description("Snipara companion CLI for local hooks and automation workflows").version(readCliVersion());
26811
27304
  program.command("login").description("Authenticate this workspace through the Snipara project picker").option("--api-url <url>", "Override the API URL (default: https://api.snipara.com)").option("-c, --client <client>", "Client type for the project API key label").option("-p, --project <project>", "Project slug or ID to preselect in the browser").option("--project-id <id>", "Project slug or ID (deprecated alias)").option("-d, --dir <directory>", "Project directory (default: current)").option("--user-key", "Use the legacy project-agnostic user-key login flow").action(async (options) => {
26812
27305
  try {
@@ -27572,6 +28065,7 @@ program.command("brief").description("Build a Project Intelligence continuity br
27572
28065
  json: Boolean(options.json)
27573
28066
  });
27574
28067
  });
28068
+ configureRealityCheckCommand(program.command("reality-check"));
27575
28069
  var intelligence = program.command("intelligence").description(
27576
28070
  "Compose Project Intelligence briefs from continuity, memory health, and code impact"
27577
28071
  );
@@ -27588,6 +28082,7 @@ intelligence.command("brief").description("Build a Project Intelligence continui
27588
28082
  json: Boolean(options.json)
27589
28083
  });
27590
28084
  });
28085
+ configureRealityCheckCommand(intelligence.command("reality-check"));
27591
28086
  intelligence.command("ledger-export").description("Export a structured, redacted Coding Intelligence Ledger JSON artifact").option("--from-file <file>", "Read ledger inputs from a JSON object").option("--task <task>", "Task or work package summary").option("--prompt <prompt>", "Prompt or operator request summary").option("--source-ref <ref>", "Stable prompt or source reference").option("--branch <branch>", "Repository branch").option("--commit <commit>", "Repository commit or revision").option("--changed-files <files...>", "Changed files represented by the ledger").option("--recent-files <files...>", "Recently relevant files").option("--diff-summary <summary>", "Diff summary represented by the ledger").option("--served-context <context>", "Served context item; repeatable", collectOption, []).option("--plan <plan>", "Plan or decision item; repeatable", collectOption, []).option("--diff <diff>", "Diff item; repeatable", collectOption, []).option("--test <test>", "Test or verification item; repeatable", collectOption, []).option("--ci <ci>", "CI or build item; repeatable", collectOption, []).option("--review <review>", "Review item; repeatable", collectOption, []).option("--outcome <outcome>", "Outcome item; repeatable", collectOption, []).option(
27592
28087
  "--influence-receipt <receipt>",
27593
28088
  "Advisor influence or receipt item; repeatable",
@@ -28659,6 +29154,7 @@ if (require.main === module) {
28659
29154
  buildLocalImpactResult,
28660
29155
  buildLocalImportsResult,
28661
29156
  buildLocalNeighborsResult,
29157
+ buildLocalProjectRealityCheck,
28662
29158
  buildLocalShortestPathResult,
28663
29159
  buildLocalSourceSnapshot,
28664
29160
  buildLocalSourceStatus,
@@ -28753,6 +29249,7 @@ if (require.main === module) {
28753
29249
  readLocalCodePromotionState,
28754
29250
  readLocalSourceSnapshot,
28755
29251
  readLocalWorkersConfig,
29252
+ realityCheckCommand,
28756
29253
  referencesIngestCommand,
28757
29254
  referencesScanCommand,
28758
29255
  resolveContextPackRecord,
@@ -174,6 +174,7 @@ snipara-companion status
174
174
  snipara-companion source init .
175
175
  snipara-companion source sync --json
176
176
  snipara-companion brief --task "ship auth hardening" --changed-files src/auth.ts
177
+ snipara-companion reality-check --task "ship auth hardening" --changed-files src/auth.ts --enforce
177
178
  snipara-companion timeline
178
179
  snipara-companion workflow phase-commit build --summary "tests green"
179
180
  snipara-companion workflow impact-gate
@@ -192,6 +193,10 @@ snipara-companion workflow resume --include-session-context
192
193
  it writes a source snapshot, previews supported document sync, and refreshes
193
194
  the local code overlay cache without requiring GitHub.
194
195
  - `brief` is the short alias for `intelligence brief`.
196
+ - `reality-check` compares changed files, linked intent, context docs, symbols,
197
+ and verification hints to flag contradiction-to-reality risks before commit or
198
+ merge. Use `--enforce` in local hooks when review-required findings should
199
+ fail the hook.
195
200
  - `timeline` is the Git-style log for workflow starts, phase starts, phase
196
201
  commits, final commits, and Team Sync handoffs.
197
202
  - `workflow impact-gate` audits committed local workflow phases that are ahead
@@ -741,6 +746,7 @@ snipara-companion query --query "auth middleware"
741
746
  snipara-companion query --query "who calls src.mcp_transport.handle_call_tool" --follow-recommendation
742
747
  snipara-companion status
743
748
  snipara-companion brief --task "ship auth hardening" --changed-files apps/web/src/lib/auth.ts tests/auth.test.ts --diff-summary "auth hardening"
749
+ snipara-companion reality-check --task "ship auth hardening" --changed-files apps/web/src/lib/auth.ts --verification "pnpm test auth" --enforce
744
750
  snipara-companion handoff --summary "auth hardening implemented" --next "run permissions tests" --files apps/web/src/lib/auth.ts --output handoff.md
745
751
  snipara-companion intelligence brief --task "ship auth hardening" --changed-files apps/web/src/lib/auth.ts tests/auth.test.ts --diff-summary "auth hardening"
746
752
  snipara-companion workflow scaffold --preset project-intelligence-continuity-layer --output .snipara/workflow/plans/project-intelligence-plan.json
@@ -930,6 +936,23 @@ checkouts use hosted graph impact. It prints continuity signals, memory health,
930
936
  risk and verification hints, degraded surfaces, and the Judgment Card's
931
937
  weighted readiness, evidence, and required actions.
932
938
 
939
+ Use `reality-check` or `intelligence reality-check` when a local hook, agent, or
940
+ CI adapter needs the contradiction-to-reality gate without a full hosted brief:
941
+
942
+ ```bash
943
+ snipara-companion reality-check \
944
+ --task "refactor auth middleware" \
945
+ --changed-files src/auth/middleware.ts \
946
+ --decision "DEC-001: auth middleware must keep side effects explicit" \
947
+ --verification "pnpm test auth" \
948
+ --enforce
949
+ ```
950
+
951
+ The command reads the local Git scope by default, includes dirty files unless
952
+ `--no-include-dirty` is set, and also accepts explicit `--changed-files` for
953
+ hooks or CI collectors. `--enforce` exits non-zero for `review_required` or
954
+ `blocking` findings; JSON output is available with `--json`.
955
+
933
956
  Use `intelligence ledger-export` when an agent run, review, or replay benchmark
934
957
  needs a portable Coding Intelligence Ledger instead of a raw transcript:
935
958
 
@@ -1005,9 +1028,11 @@ Semantics:
1005
1028
  - `snipara-companion status` = top-level agentic work status across local workflow state, git dirtiness, and Team Sync carryover
1006
1029
  - `snipara-companion source init|sync|status|snapshot|watch` = automatic local source activation for folders with or without Git metadata; writes `.snipara/source/latest.json`, previews document sync, and refreshes the local code overlay cache
1007
1030
  - `snipara-companion brief` = short alias for `snipara-companion intelligence brief`
1031
+ - `snipara-companion reality-check` = local Project Reality Check for supplied or Git-derived changed files; `--enforce` makes review-required contradiction-to-reality findings fail hooks
1008
1032
  - `snipara-companion timeline` = local timeline of workflow starts, phase starts, phase commits, final commits, and Team Sync handoffs
1009
1033
  - `snipara-companion handoff` = top-level agent-ready Markdown/JSON handoff artifact plus the same local/hosted Team Sync handoff persistence
1010
1034
  - `snipara-companion intelligence brief` = one local Project Intelligence brief that combines resume context, memory health, and code impact for a task
1035
+ - `snipara-companion intelligence reality-check` = Project Intelligence namespace alias for the same local Reality Check gate
1011
1036
  - `snipara-companion intelligence ledger-export` = structured redacted Coding Intelligence Ledger JSON for replay, review, and commercial proof assets without dumping raw transcripts
1012
1037
  - `snipara-companion run` = production Project Intelligence flow that combines the brief, guard action cards, package review, verification hints, and a final weighted Judgment Card
1013
1038
  - `snipara-companion workflow start --plan-file` = records the visible LLM plan locally so phase state survives agent compaction; prefer JSON plans with explicit ids for stable machine phase state
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snipara-companion",
3
- "version": "3.0.6",
3
+ "version": "3.0.7",
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": {