snipara-companion 3.5.2 → 3.5.4

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/CHANGELOG.md CHANGED
@@ -2,6 +2,26 @@
2
2
 
3
3
  Release notes for `snipara-companion`, newest first.
4
4
 
5
+ ## New In 3.5.4
6
+
7
+ - Makes `reality-check` auto-link bounded reviewed Team Sync decisions, keyword
8
+ document context, managed workflow receipts, and current verification
9
+ evidence while preserving explicit CLI inputs and failing open when hosted
10
+ context is unavailable.
11
+ - Keeps the evidence used by Reality Check inspectable in JSON and Markdown
12
+ findings instead of using verification only as a hidden severity signal.
13
+ - Gives `query` a 30-second default timeout plus explicit search-mode,
14
+ Answer Pack, decomposition, and shared-context controls for fast recovery.
15
+
16
+ ## New In 3.5.3
17
+
18
+ - Propagates the configured Companion `sessionId` as
19
+ `X-Snipara-Session-Id` on Hosted MCP calls.
20
+ - Labels supported retrieval calls as `snipara-companion` while preserving an
21
+ explicit caller-provided client label and correlation context.
22
+ - Keeps correlation telemetry-only and project-scoped; authentication and
23
+ ranking promotion remain separate contracts.
24
+
5
25
  ## New In 3.5.2
6
26
 
7
27
  - Replaces the retired Windsurf preset with Kimi Code CLI across setup,
package/README.md CHANGED
@@ -60,6 +60,10 @@ same value as `correlation_context.session_id` on retrieval tools.
60
60
 
61
61
  The identifier is opaque, project-scoped telemetry. It does not grant access or
62
62
  change authorization, and explicit per-call correlation remains authoritative.
63
+ Companion also forwards its configured `sessionId` automatically on every
64
+ Hosted MCP call and labels supported retrieval traffic as
65
+ `snipara-companion`, unless the caller supplied an explicit client label. This
66
+ improves join coverage without inventing a second server-side identity.
63
67
 
64
68
  Example output excerpt:
65
69
 
@@ -90,7 +94,7 @@ These commands are useful without hosted Snipara:
90
94
  | ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
91
95
  | `source init` / `source sync` / `source status` | Local source snapshot, document preview, and code overlay |
92
96
  | `impact` / `code impact` | File-level blast-radius from the local code overlay |
93
- | `reality-check` | Intent Ledger, Unknown Registry, and verification checks |
97
+ | `reality-check` | Intent Ledger, Unknown Registry, auto-linked context, and inspectable proof |
94
98
  | `code callers` / `imports` / `neighbors` / `shortest-path` | Structural repo questions from local files |
95
99
  | `workflow start` / `phase-start` / `phase-commit` / `resume` | Agent continuity that survives compaction |
96
100
  | `workflow timeline` / `workflow session` | Append-only local activity log and Session Snapshot V0 |
package/dist/index.d.ts CHANGED
@@ -269,6 +269,19 @@ interface ContextQueryResult {
269
269
  graph_hybrid_used?: boolean;
270
270
  graph_context_tool?: string;
271
271
  graph_context_summary?: string;
272
+ search_mode?: ContextQuerySearchMode;
273
+ timing?: Record<string, number>;
274
+ retrieval_diagnostics?: Record<string, unknown>;
275
+ }
276
+ type ContextQuerySearchMode = "keyword" | "semantic" | "hybrid";
277
+ interface ContextQueryOptions {
278
+ searchMode?: ContextQuerySearchMode;
279
+ includeMetadata?: boolean;
280
+ includeAnswerPack?: boolean;
281
+ autoDecompose?: boolean;
282
+ includeSharedContext?: boolean;
283
+ includeAllTiers?: boolean;
284
+ returnReferences?: boolean;
272
285
  }
273
286
  interface AnswerPackSource {
274
287
  title?: string;
@@ -1222,7 +1235,7 @@ declare class RLMClient {
1222
1235
  /**
1223
1236
  * Query for optimized context using snipara_context_query
1224
1237
  */
1225
- queryContext(query: string, maxTokens?: number): Promise<ContextQueryResult>;
1238
+ queryContext(query: string, maxTokens?: number, options?: ContextQueryOptions): Promise<ContextQueryResult>;
1226
1239
  sharedContext(options?: {
1227
1240
  maxTokens?: number;
1228
1241
  categories?: string[];
@@ -2183,12 +2196,24 @@ interface RealityCheckCommandOptions {
2183
2196
  decision?: string[];
2184
2197
  document?: string[];
2185
2198
  verification?: string[];
2199
+ autoContext?: boolean;
2200
+ autoContextTimeoutMs?: number;
2186
2201
  includeDirty?: boolean;
2187
2202
  enforce?: boolean;
2188
2203
  dir?: string;
2189
2204
  json?: boolean;
2190
2205
  }
2206
+ interface RealityCheckAutoContextClient {
2207
+ queryContext(query: string, maxTokens?: number, options?: ContextQueryOptions): Promise<ContextQueryResult>;
2208
+ getTeamSyncWhatChanged(args: {
2209
+ limit?: number;
2210
+ branch?: string;
2211
+ paths?: string[];
2212
+ recentFiles?: string[];
2213
+ }): Promise<TeamSyncChangesResponse>;
2214
+ }
2191
2215
  declare function buildLocalProjectRealityCheck(options: RealityCheckCommandOptions): ProjectRealityCheckResult;
2216
+ declare function buildLocalProjectRealityCheckWithAutoContext(options: RealityCheckCommandOptions, clientOverride?: RealityCheckAutoContextClient): Promise<ProjectRealityCheckResult>;
2192
2217
  declare function realityCheckCommand(options: RealityCheckCommandOptions): Promise<void>;
2193
2218
 
2194
2219
  interface DecisionRequestWriteResult {
@@ -4906,4 +4931,4 @@ declare function installAutomationBundle(args: {
4906
4931
  }): Promise<AutomationInstallResult>;
4907
4932
  declare function getAutomationStatus(projectDir?: string): AutomationStatusResult;
4908
4933
 
4909
- 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, FINAL_COMMIT_REPORT_RELATIVE_PATH, FINAL_COMMIT_REPORT_VERSION, ORCHESTRATOR_HANDOFF_RELATIVE_PATH, POLICY_LEDGER_SYNC_REPORT_VERSION, PRODUCER_LOOP_ARTIFACT_VERSION, PRODUCER_LOOP_RELATIVE_DIR, PRODUCER_LOOP_REPORT_VERSION, TEAM_SYNC_STATE_RELATIVE_PATH, WHY_OUTCOME_CAPTURE_VERSION, WORKFLOW_PLANS_RELATIVE_DIR, WORKFLOW_STATE_RELATIVE_PATH, addLocalWorker, agentReadinessAuditCommand, appendActivityEvent, applyLocalContextMutationPlan, archiveInactiveTeamSyncWork, attachLocalContextPackReceipts, autoArchiveTeamSyncState, buildAdaptiveWorkRoutingRecommendation, buildAgentReadinessAuditReport, buildAgenticHandoffMarkdown, buildAgenticTimeline, buildAgenticWorkStatus, buildAutomationInstallPlan, buildCanonicalEvent, buildCodeHooksInstallPlan, buildCodePromotionResult, buildCodeStatusResult, buildCodeSyncResult, buildCodingIntelligenceLedger, buildCollaborationActor, buildCollaborationGuardActionCards, buildCollaborationHooksInstallPlan, buildCommitResultMetadata, buildCompanionEngineeringLeadPlanReport, buildContextPackStats, buildEvalCaseArtifact, buildFinalCommitReport, buildGeneratedWorkflowPlanDocument, buildHostedCodeOverlayUploadPayload, buildHostedGuardPayload, buildJournalCheckpointEntry, buildLocalCallersResult, buildLocalCodeOverlay, buildLocalContextMutationPlan, buildLocalContextPackReceipt, buildLocalContextPackReceipts, buildLocalImpactResult, buildLocalImportsResult, buildLocalNeighborsResult, buildLocalProjectContextValidationReport, buildLocalProjectDriftReport, buildLocalProjectRealityCheck, buildLocalShortestPathResult, buildLocalSourceSnapshot, buildLocalSourceStatus, buildLocalSourceSyncResult, buildMemoryAudit, buildOnboardFolderManifest, buildOrchestratorHandoff, buildPolicyLedgerSyncReport, buildProducerLoopReport, buildProjectIntelligenceBrief, buildProjectIntelligenceRun, buildProjectJudgmentCard, buildSessionBootstrapBrief, buildSessionBootstrapQuality, buildSessionSnapshot, buildSyncDocumentsDryRun, buildTeamSyncHandoffRecord, buildTeamSyncStartWorkRecord, buildTeamSyncSummary, buildToolCallPayload, buildToolResultPayload, buildVerificationPlan, buildWhyOutcomeCaptureReport, buildWorkerTrustCandidates, buildWorkflowImpactGate, buildWorkflowPhaseCommitReceipt, buildWorkflowPhaseCommitSummary, buildWorkflowPlanScaffold, categoryFromGuardTag, classifyToolResult, cleanContextPacks, codingLedgerExportCommand, collaborationIdeStatusCommand, collectAgentReadinessLocalSignals, collectPolicyLedgerSyncArtifacts, collectSyncDocuments, collectSyncDocumentsInput, compactHostedGuardResources, compareLocalSourceSnapshots, completeTeamSyncStateFromEvidence, completeTeamSyncWorkFromEvidence, contextControlApplyCommand, contextControlDriftCommand, contextControlHostedApplyCommand, contextControlHostedDiffCommand, contextControlPlanCommand, contextControlValidateCommand, contextPackCleanCommand, contextPackPackCommand, contextPackRetrieveCommand, contextPackStatsCommand, controlledWorkerExecuteCommand, createClient, createEmptyCollaborationState, createEmptyTeamSyncState, createLocalQueryCache, deriveLocalCollaborationResourcesFromFiles, detectReleaseSurfacesFromFiles, detectRuntimeEnvironment, evalExportCommand, evalRunCommand, evaluateProjectPolicyGates, extractCommandFromToolInput, extractFilesFromToolInput, formatAgentReadinessAuditReport, formatCompanionEngineeringLeadPlanReport, formatFinalCommitReport, formatOrchestratorRecommendationReason, formatPolicyGateDecision, formatProjectJudgmentCard, formatStuckGuardDecision, getAutomationManifestPath, getAutomationStatus, getCollaborationStatePath, getConfigPath, getContextPackStoragePaths, getLocalCodeOverlayCachePath, getLocalCodePromotionStatePath, getLocalSourceSnapshotPath, getOrchestratorRecommendation, getPlanStepDisplayTitle, getStagedFiles, getStuckGuardInjection, getTeamSyncStatePath, hashWorkerProfile, ingestReferences, installAutomationBundle, leadPlanCommand, listProjectsForApiKey, loadAutomationManifest, loadCollaborationState, loadConfig, loadTeamSyncState, memoryAuditCommand, memoryCleanCandidatesCommand, memoryCompactCommand, memoryHealthCommand, memoryLocalCommand, memoryReviewsCommand, normalizeCollaborationFiles, normalizeGuardTag, normalizeWorkflowPlanInput, outcomeCapturePreviewCommand, packContext, parseCollaborationResources, projectIntelligenceBriefCommand, projectIntelligenceRunCommand, readActivityTimeline, readLocalCodeOverlayCache, readLocalCodePromotionState, readLocalSourceSnapshot, readLocalWorkersConfig, readSessionSnapshot, readWorkerTrustEvent, realityCheckCommand, referencesIngestCommand, referencesScanCommand, resolveAutoWorkflowMode, resolveContextPackRecord, resolveFullWorkflowTokenBudget, resolveLocalWorkerRoutingDefaults, resolveQueryFromToolInput, retrieveContextPack, runMemoryGuardCheck, saveCollaborationState, saveConfig, saveTeamSyncState, scanReferences, shouldFailCollaborationGuard, shouldSuggestOrchestratorForWorkflow, shouldSuggestRuntimeForWorkflow, summarizeLocalCodeOverlay, teamSyncSweepCommand, validatePlanResult, verifyCommand, workerTrustCandidateCommand, workerTrustReviewCommand, workerTrustStatusCommand, workersLocalAddCommand, workersLocalListCommand, workersLocalProbePrintCommand, workersLocalRemoveCommand, workersLocalStatusCommand, workflowSyncPolicyLedgerCommand, writeFinalCommitReport, writeLocalCodeOverlayCache, writeLocalCodePromotionState, writeLocalSourceSnapshot, writeOrchestratorHandoff, writeProducerLoopArtifact, writeSessionSnapshot };
4934
+ 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, FINAL_COMMIT_REPORT_RELATIVE_PATH, FINAL_COMMIT_REPORT_VERSION, ORCHESTRATOR_HANDOFF_RELATIVE_PATH, POLICY_LEDGER_SYNC_REPORT_VERSION, PRODUCER_LOOP_ARTIFACT_VERSION, PRODUCER_LOOP_RELATIVE_DIR, PRODUCER_LOOP_REPORT_VERSION, TEAM_SYNC_STATE_RELATIVE_PATH, WHY_OUTCOME_CAPTURE_VERSION, WORKFLOW_PLANS_RELATIVE_DIR, WORKFLOW_STATE_RELATIVE_PATH, addLocalWorker, agentReadinessAuditCommand, appendActivityEvent, applyLocalContextMutationPlan, archiveInactiveTeamSyncWork, attachLocalContextPackReceipts, autoArchiveTeamSyncState, buildAdaptiveWorkRoutingRecommendation, buildAgentReadinessAuditReport, buildAgenticHandoffMarkdown, buildAgenticTimeline, buildAgenticWorkStatus, buildAutomationInstallPlan, buildCanonicalEvent, buildCodeHooksInstallPlan, buildCodePromotionResult, buildCodeStatusResult, buildCodeSyncResult, buildCodingIntelligenceLedger, buildCollaborationActor, buildCollaborationGuardActionCards, buildCollaborationHooksInstallPlan, buildCommitResultMetadata, buildCompanionEngineeringLeadPlanReport, buildContextPackStats, buildEvalCaseArtifact, buildFinalCommitReport, buildGeneratedWorkflowPlanDocument, buildHostedCodeOverlayUploadPayload, buildHostedGuardPayload, buildJournalCheckpointEntry, buildLocalCallersResult, buildLocalCodeOverlay, buildLocalContextMutationPlan, buildLocalContextPackReceipt, buildLocalContextPackReceipts, buildLocalImpactResult, buildLocalImportsResult, buildLocalNeighborsResult, buildLocalProjectContextValidationReport, buildLocalProjectDriftReport, buildLocalProjectRealityCheck, buildLocalProjectRealityCheckWithAutoContext, buildLocalShortestPathResult, buildLocalSourceSnapshot, buildLocalSourceStatus, buildLocalSourceSyncResult, buildMemoryAudit, buildOnboardFolderManifest, buildOrchestratorHandoff, buildPolicyLedgerSyncReport, buildProducerLoopReport, buildProjectIntelligenceBrief, buildProjectIntelligenceRun, buildProjectJudgmentCard, buildSessionBootstrapBrief, buildSessionBootstrapQuality, buildSessionSnapshot, buildSyncDocumentsDryRun, buildTeamSyncHandoffRecord, buildTeamSyncStartWorkRecord, buildTeamSyncSummary, buildToolCallPayload, buildToolResultPayload, buildVerificationPlan, buildWhyOutcomeCaptureReport, buildWorkerTrustCandidates, buildWorkflowImpactGate, buildWorkflowPhaseCommitReceipt, buildWorkflowPhaseCommitSummary, buildWorkflowPlanScaffold, categoryFromGuardTag, classifyToolResult, cleanContextPacks, codingLedgerExportCommand, collaborationIdeStatusCommand, collectAgentReadinessLocalSignals, collectPolicyLedgerSyncArtifacts, collectSyncDocuments, collectSyncDocumentsInput, compactHostedGuardResources, compareLocalSourceSnapshots, completeTeamSyncStateFromEvidence, completeTeamSyncWorkFromEvidence, contextControlApplyCommand, contextControlDriftCommand, contextControlHostedApplyCommand, contextControlHostedDiffCommand, contextControlPlanCommand, contextControlValidateCommand, contextPackCleanCommand, contextPackPackCommand, contextPackRetrieveCommand, contextPackStatsCommand, controlledWorkerExecuteCommand, createClient, createEmptyCollaborationState, createEmptyTeamSyncState, createLocalQueryCache, deriveLocalCollaborationResourcesFromFiles, detectReleaseSurfacesFromFiles, detectRuntimeEnvironment, evalExportCommand, evalRunCommand, evaluateProjectPolicyGates, extractCommandFromToolInput, extractFilesFromToolInput, formatAgentReadinessAuditReport, formatCompanionEngineeringLeadPlanReport, formatFinalCommitReport, formatOrchestratorRecommendationReason, formatPolicyGateDecision, formatProjectJudgmentCard, formatStuckGuardDecision, getAutomationManifestPath, getAutomationStatus, getCollaborationStatePath, getConfigPath, getContextPackStoragePaths, getLocalCodeOverlayCachePath, getLocalCodePromotionStatePath, getLocalSourceSnapshotPath, getOrchestratorRecommendation, getPlanStepDisplayTitle, getStagedFiles, getStuckGuardInjection, getTeamSyncStatePath, hashWorkerProfile, ingestReferences, installAutomationBundle, leadPlanCommand, listProjectsForApiKey, loadAutomationManifest, loadCollaborationState, loadConfig, loadTeamSyncState, memoryAuditCommand, memoryCleanCandidatesCommand, memoryCompactCommand, memoryHealthCommand, memoryLocalCommand, memoryReviewsCommand, normalizeCollaborationFiles, normalizeGuardTag, normalizeWorkflowPlanInput, outcomeCapturePreviewCommand, packContext, parseCollaborationResources, projectIntelligenceBriefCommand, projectIntelligenceRunCommand, readActivityTimeline, readLocalCodeOverlayCache, readLocalCodePromotionState, readLocalSourceSnapshot, readLocalWorkersConfig, readSessionSnapshot, readWorkerTrustEvent, realityCheckCommand, referencesIngestCommand, referencesScanCommand, resolveAutoWorkflowMode, resolveContextPackRecord, resolveFullWorkflowTokenBudget, resolveLocalWorkerRoutingDefaults, resolveQueryFromToolInput, retrieveContextPack, runMemoryGuardCheck, saveCollaborationState, saveConfig, saveTeamSyncState, scanReferences, shouldFailCollaborationGuard, shouldSuggestOrchestratorForWorkflow, shouldSuggestRuntimeForWorkflow, summarizeLocalCodeOverlay, teamSyncSweepCommand, validatePlanResult, verifyCommand, workerTrustCandidateCommand, workerTrustReviewCommand, workerTrustStatusCommand, workersLocalAddCommand, workersLocalListCommand, workersLocalProbePrintCommand, workersLocalRemoveCommand, workersLocalStatusCommand, workflowSyncPolicyLedgerCommand, writeFinalCommitReport, writeLocalCodeOverlayCache, writeLocalCodePromotionState, writeLocalSourceSnapshot, writeOrchestratorHandoff, writeProducerLoopArtifact, writeSessionSnapshot };
package/dist/index.js CHANGED
@@ -99,6 +99,7 @@ __export(index_exports, {
99
99
  buildLocalProjectContextValidationReport: () => buildLocalProjectContextValidationReport,
100
100
  buildLocalProjectDriftReport: () => buildLocalProjectDriftReport,
101
101
  buildLocalProjectRealityCheck: () => buildLocalProjectRealityCheck,
102
+ buildLocalProjectRealityCheckWithAutoContext: () => buildLocalProjectRealityCheckWithAutoContext,
102
103
  buildLocalShortestPathResult: () => buildLocalShortestPathResult,
103
104
  buildLocalSourceSnapshot: () => buildLocalSourceSnapshot,
104
105
  buildLocalSourceStatus: () => buildLocalSourceStatus,
@@ -522,6 +523,27 @@ function readGitRemote(cwd) {
522
523
  }
523
524
 
524
525
  // src/api/client.ts
526
+ var CORRELATED_RETRIEVAL_TOOL_NAMES = /* @__PURE__ */ new Set([
527
+ "snipara_context_query",
528
+ "snipara_ask",
529
+ "snipara_search",
530
+ "snipara_recall",
531
+ "snipara_get_chunk",
532
+ "rlm_context_query",
533
+ "rlm_ask",
534
+ "rlm_search",
535
+ "rlm_recall",
536
+ "rlm_get_chunk"
537
+ ]);
538
+ function withCompanionRetrievalClient(toolName, args) {
539
+ if (!CORRELATED_RETRIEVAL_TOOL_NAMES.has(toolName) || args.client !== void 0) {
540
+ return args;
541
+ }
542
+ return {
543
+ ...args,
544
+ client: "snipara-companion"
545
+ };
546
+ }
525
547
  function getSniparaTokenStorePath() {
526
548
  return path3.join(os2.homedir(), ".snipara", "tokens.json");
527
549
  }
@@ -743,7 +765,7 @@ var RLMClient = class {
743
765
  method: "tools/call",
744
766
  params: {
745
767
  name: toolName,
746
- arguments: args
768
+ arguments: withCompanionRetrievalClient(toolName, args)
747
769
  }
748
770
  };
749
771
  const controller = new AbortController();
@@ -754,7 +776,8 @@ var RLMClient = class {
754
776
  {
755
777
  method: "POST",
756
778
  headers: {
757
- "Content-Type": "application/json"
779
+ "Content-Type": "application/json",
780
+ ...this.config.sessionId ? { "X-Snipara-Session-Id": this.config.sessionId } : {}
758
781
  },
759
782
  body: JSON.stringify(payload),
760
783
  signal: controller.signal
@@ -783,13 +806,17 @@ var RLMClient = class {
783
806
  /**
784
807
  * Query for optimized context using snipara_context_query
785
808
  */
786
- async queryContext(query, maxTokens = 8e3) {
809
+ async queryContext(query, maxTokens = 8e3, options = {}) {
787
810
  const result = await this.mcpCall("snipara_context_query", {
788
811
  query,
789
812
  max_tokens: maxTokens,
790
- search_mode: "hybrid",
791
- include_metadata: true,
792
- include_answer_pack: true
813
+ search_mode: options.searchMode ?? "hybrid",
814
+ include_metadata: options.includeMetadata ?? true,
815
+ include_answer_pack: options.includeAnswerPack ?? true,
816
+ auto_decompose: options.autoDecompose,
817
+ include_shared_context: options.includeSharedContext,
818
+ include_all_tiers: options.includeAllTiers,
819
+ return_references: options.returnReferences
793
820
  });
794
821
  return {
795
822
  sections: (result.sections || []).map((s) => ({
@@ -818,7 +845,10 @@ var RLMClient = class {
818
845
  recommended_tool_arguments: result.recommended_tool_arguments || {},
819
846
  graph_hybrid_used: result.graph_hybrid_used,
820
847
  graph_context_tool: result.graph_context_tool,
821
- graph_context_summary: result.graph_context_summary
848
+ graph_context_summary: result.graph_context_summary,
849
+ search_mode: result.search_mode,
850
+ timing: result.timing,
851
+ retrieval_diagnostics: result.retrieval_diagnostics
822
852
  };
823
853
  }
824
854
  async sharedContext(options = {}) {
@@ -9519,6 +9549,9 @@ function buildDocumentIntentEntry(doc, policy) {
9519
9549
  doc.intent?.freshnessHorizonDays ?? doc.freshnessHorizonDays ?? sectionIntent.freshnessHorizonDays,
9520
9550
  policy
9521
9551
  );
9552
+ const affectedAnchors = uniqueStrings3(
9553
+ doc.affectedAnchors && doc.affectedAnchors.length > 0 ? doc.affectedAnchors : [doc.path]
9554
+ );
9522
9555
  return {
9523
9556
  id: `intent:doc:${doc.path}`,
9524
9557
  title: doc.title || doc.path,
@@ -9546,7 +9579,7 @@ function buildDocumentIntentEntry(doc, policy) {
9546
9579
  structuredSections: sectionIntent,
9547
9580
  fallbackUsed: goal === doc.path || goal === doc.title
9548
9581
  }),
9549
- affectedAnchors: [doc.path],
9582
+ affectedAnchors,
9550
9583
  owner: doc.intent?.owner ?? sectionIntent.owner ?? doc.owner ?? null,
9551
9584
  evidence: [
9552
9585
  {
@@ -10174,6 +10207,23 @@ function decisionEvidence(decisions) {
10174
10207
  strength: decision.confidenceScore ?? 0.8
10175
10208
  }));
10176
10209
  }
10210
+ function verificationEvidence(input) {
10211
+ return (input.verificationChecklist ?? []).slice(0, 8).map((item, index) => ({
10212
+ kind: /test|spec|vitest|pytest|e2e|smoke|lint|type.?check|build|health|ready|migration|schema|pack/i.test(
10213
+ item
10214
+ ) ? "test" : "manual",
10215
+ label: item,
10216
+ sourceRef: `verification:${index + 1}`,
10217
+ strength: 0.75
10218
+ }));
10219
+ }
10220
+ function uniqueEvidence(evidence) {
10221
+ return [
10222
+ ...new Map(
10223
+ evidence.map((item) => [`${item.kind}:${item.sourceRef ?? item.label}`, item])
10224
+ ).values()
10225
+ ];
10226
+ }
10177
10227
  function buildProjectRealityCheck(input) {
10178
10228
  const changedFiles = uniqueStrings3(input.changedFiles);
10179
10229
  const dirtyFiles = uniqueStrings3(input.dirtyFiles ?? []);
@@ -10181,7 +10231,17 @@ function buildProjectRealityCheck(input) {
10181
10231
  const tests = testFiles(changedFiles);
10182
10232
  const findings = [];
10183
10233
  const decisions = input.decisions ?? [];
10184
- const contextEvidence2 = [...docEvidence(input), ...symbolEvidence(input)];
10234
+ const verificationRefs = verificationEvidence(input);
10235
+ const contextEvidence2 = uniqueEvidence([
10236
+ ...docEvidence(input),
10237
+ ...symbolEvidence(input),
10238
+ ...input.evidence ?? []
10239
+ ]);
10240
+ const allEvidence = uniqueEvidence([
10241
+ ...decisionEvidence(decisions),
10242
+ ...verificationRefs,
10243
+ ...contextEvidence2
10244
+ ]).slice(0, 20);
10185
10245
  const intentLedger = buildProjectIntentLedger(input, changedFiles);
10186
10246
  for (const surface of SENSITIVE_SURFACES) {
10187
10247
  const files = surfaceFiles(surface, changedFiles);
@@ -10210,7 +10270,11 @@ function buildProjectRealityCheck(input) {
10210
10270
  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"}.`,
10211
10271
  changedFiles: files.slice(0, 12),
10212
10272
  decisionIds: relatedDecisions.map((decision) => decision.id).slice(0, 8),
10213
- evidence: [...decisionEvidence(relatedDecisions), ...contextEvidence2].slice(0, 8),
10273
+ evidence: uniqueEvidence([
10274
+ ...decisionEvidence(relatedDecisions),
10275
+ ...verificationRefs,
10276
+ ...contextEvidence2
10277
+ ]).slice(0, 8),
10214
10278
  reasonCodes: reasonCodes2,
10215
10279
  recommendedActions,
10216
10280
  caveats: [
@@ -10232,7 +10296,7 @@ function buildProjectRealityCheck(input) {
10232
10296
  summary: "This change spans architectural boundaries. Verify that the dependency direction and runtime ownership still match the intended architecture.",
10233
10297
  changedFiles: files.slice(0, 12),
10234
10298
  decisionIds: [],
10235
- evidence: contextEvidence2.slice(0, 6),
10299
+ evidence: uniqueEvidence([...verificationRefs, ...contextEvidence2]).slice(0, 8),
10236
10300
  reasonCodes: [rule.key, "cross_boundary_change"],
10237
10301
  recommendedActions: [
10238
10302
  "Check that the changed modules do not introduce a forbidden runtime dependency.",
@@ -10331,6 +10395,7 @@ function buildProjectRealityCheck(input) {
10331
10395
  findings,
10332
10396
  intentLedger,
10333
10397
  unknownRegistry,
10398
+ evidence: allEvidence,
10334
10399
  requiredActions,
10335
10400
  watchItems,
10336
10401
  reasonCodes: uniqueStrings3([
@@ -10399,11 +10464,24 @@ function renderProjectRealityCheckMarkdown(result) {
10399
10464
  if (finding.decisionIds.length > 0) {
10400
10465
  lines.push(` Decisions: ${finding.decisionIds.join(", ")}`);
10401
10466
  }
10467
+ if (finding.evidence.length > 0) {
10468
+ lines.push(
10469
+ ` Evidence: ${finding.evidence.slice(0, 4).map((item) => `${item.kind}:${item.label}`).join("; ")}`
10470
+ );
10471
+ }
10402
10472
  if (finding.recommendedActions.length > 0) {
10403
10473
  lines.push(` Action: ${finding.recommendedActions[0]}`);
10404
10474
  }
10405
10475
  }
10406
10476
  }
10477
+ if (result.evidence.length > 0) {
10478
+ lines.push("", "Evidence:");
10479
+ lines.push(
10480
+ ...result.evidence.slice(0, 10).map(
10481
+ (item) => `- ${item.kind}: ${item.label}${item.sourceRef ? ` (${item.sourceRef})` : ""}`
10482
+ )
10483
+ );
10484
+ }
10407
10485
  if (result.requiredActions.length > 0) {
10408
10486
  lines.push("", "Required actions:");
10409
10487
  lines.push(...result.requiredActions.map((action) => `- ${action}`));
@@ -26096,8 +26174,18 @@ function printRecallResult(result) {
26096
26174
  }
26097
26175
  async function queryCommand(options) {
26098
26176
  ensureConfigured();
26099
- const client = createClient(15e3);
26100
- const result = await client.queryContext(options.query, options.maxTokens || 8e3);
26177
+ const searchMode = options.searchMode ?? "hybrid";
26178
+ if (!["keyword", "semantic", "hybrid"].includes(searchMode)) {
26179
+ throw new Error("--search-mode must be keyword, semantic, or hybrid");
26180
+ }
26181
+ const timeoutMs = Math.max(1e3, Math.min(options.timeoutMs ?? 3e4, 12e4));
26182
+ const client = createClient(timeoutMs);
26183
+ const result = await client.queryContext(options.query, options.maxTokens || 8e3, {
26184
+ searchMode,
26185
+ includeAnswerPack: options.includeAnswerPack,
26186
+ autoDecompose: options.autoDecompose,
26187
+ includeSharedContext: options.includeSharedContext
26188
+ });
26101
26189
  const recommendedExecution = options.followRecommendation && result.recommended_tool ? await runRecommendedTool(result) : null;
26102
26190
  if (options.json) {
26103
26191
  printJson2(
@@ -34828,6 +34916,7 @@ async function projectIntelligenceBriefCommand(options) {
34828
34916
 
34829
34917
  // src/commands/reality-check.ts
34830
34918
  var import_node_child_process14 = require("child_process");
34919
+ var import_node_fs2 = __toESM(require("fs"));
34831
34920
  var import_node_path2 = __toESM(require("path"));
34832
34921
  var import_chalk12 = __toESM(require("chalk"));
34833
34922
  function runGit2(args, cwd, options = {}) {
@@ -34922,8 +35011,263 @@ function parseDocument(value) {
34922
35011
  contentPreview: rest.join(":").trim() || null
34923
35012
  };
34924
35013
  }
34925
- function buildLocalProjectRealityCheck(options) {
34926
- const scope = buildLocalGitScope(options);
35014
+ function emptyAutoContext() {
35015
+ return {
35016
+ decisions: [],
35017
+ documents: [],
35018
+ evidence: [],
35019
+ verification: [],
35020
+ caveats: []
35021
+ };
35022
+ }
35023
+ function isRecord19(value) {
35024
+ return typeof value === "object" && value !== null && !Array.isArray(value);
35025
+ }
35026
+ function stringValue14(value) {
35027
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
35028
+ }
35029
+ function stringList3(value) {
35030
+ return Array.isArray(value) ? unique5(value.map((item) => typeof item === "string" ? item : void 0)) : [];
35031
+ }
35032
+ function readJsonRecord3(filePath) {
35033
+ try {
35034
+ const parsed = JSON.parse(import_node_fs2.default.readFileSync(filePath, "utf8"));
35035
+ return isRecord19(parsed) ? parsed : void 0;
35036
+ } catch {
35037
+ return void 0;
35038
+ }
35039
+ }
35040
+ var GENERIC_SCOPE_TOKENS = /* @__PURE__ */ new Set([
35041
+ "apps",
35042
+ "packages",
35043
+ "src",
35044
+ "test",
35045
+ "tests",
35046
+ "index",
35047
+ "server",
35048
+ "project",
35049
+ "snipara",
35050
+ "file",
35051
+ "files",
35052
+ "change",
35053
+ "changed"
35054
+ ]);
35055
+ function scopeTokens(value) {
35056
+ const tokens = new Set(
35057
+ (value.toLowerCase().match(/[a-z0-9][a-z0-9_-]{2,}/g) ?? []).flatMap((token) => token.split(/[-_]/g)).filter((token) => token.length >= 3 && !GENERIC_SCOPE_TOKENS.has(token))
35058
+ );
35059
+ if (/packages\/cli\//i.test(value)) {
35060
+ tokens.add("cli");
35061
+ tokens.add("companion");
35062
+ }
35063
+ if (/project-intelligence-contracts/i.test(value)) {
35064
+ tokens.add("intelligence");
35065
+ tokens.add("intent");
35066
+ tokens.add("reality");
35067
+ }
35068
+ if (/mcp-server/i.test(value)) {
35069
+ tokens.add("mcp");
35070
+ tokens.add("context");
35071
+ tokens.add("retrieval");
35072
+ }
35073
+ if (/prisma|migration|document_chunks/i.test(value)) {
35074
+ tokens.add("database");
35075
+ tokens.add("schema");
35076
+ tokens.add("pgvector");
35077
+ }
35078
+ return tokens;
35079
+ }
35080
+ function matchingAnchors(text, changedFiles) {
35081
+ const textTokens = scopeTokens(text);
35082
+ return changedFiles.filter((file) => {
35083
+ const fileTokens = scopeTokens(file);
35084
+ return [...fileTokens].some((token) => textTokens.has(token));
35085
+ });
35086
+ }
35087
+ function hasFileOverlap(left, right) {
35088
+ const rightSet = new Set(right);
35089
+ return left.some((item) => rightSet.has(item));
35090
+ }
35091
+ function collectLocalReceiptContext(scope) {
35092
+ const context = emptyAutoContext();
35093
+ const workflowRef = ".snipara/workflow/current.json";
35094
+ const workflow2 = readJsonRecord3(import_node_path2.default.join(scope.root, workflowRef));
35095
+ if (workflow2) {
35096
+ const workflowId = stringValue14(workflow2.workflowId) ?? "managed workflow";
35097
+ const phases = Array.isArray(workflow2.phases) ? workflow2.phases.filter(isRecord19) : [];
35098
+ for (const phase of phases) {
35099
+ const phaseFiles = stringList3(phase.files);
35100
+ if (!hasFileOverlap(phaseFiles, scope.changedFiles)) continue;
35101
+ const title = stringValue14(phase.title) ?? stringValue14(phase.id) ?? "workflow phase";
35102
+ const status = stringValue14(phase.status) ?? "unknown";
35103
+ context.evidence.push({
35104
+ kind: "workflow",
35105
+ label: `${workflowId}: ${title} (${status})`,
35106
+ sourceRef: workflowRef,
35107
+ strength: status === "completed" ? 0.78 : 0.62
35108
+ });
35109
+ }
35110
+ }
35111
+ const finalReportRef = ".snipara/workflow/final-report.json";
35112
+ const finalReport = readJsonRecord3(import_node_path2.default.join(scope.root, finalReportRef));
35113
+ const changed = isRecord19(finalReport?.changed) ? finalReport.changed : void 0;
35114
+ const reportFiles = stringList3(changed?.files);
35115
+ const overlappingFiles = reportFiles.filter((file) => scope.changedFiles.includes(file));
35116
+ if (finalReport && overlappingFiles.length > 0) {
35117
+ const workflowId = stringValue14(finalReport.workflowId) ?? "completed workflow";
35118
+ const outcome = stringValue14(finalReport.outcome) ?? "unknown";
35119
+ context.evidence.push({
35120
+ kind: "workflow",
35121
+ label: `${workflowId}: final report (${outcome})`,
35122
+ sourceRef: finalReportRef,
35123
+ strength: outcome === "completed" ? 0.82 : 0.6
35124
+ });
35125
+ const repository = isRecord19(changed?.repository) ? changed.repository : void 0;
35126
+ const reportHead = stringValue14(repository?.head);
35127
+ const dirtyOverlap = hasFileOverlap(scope.dirtyFiles, overlappingFiles);
35128
+ const receiptMatchesCurrentHead = Boolean(reportHead && reportHead === scope.headRef);
35129
+ const evidence = isRecord19(finalReport.evidence) ? finalReport.evidence : void 0;
35130
+ const items = Array.isArray(evidence?.items) ? evidence.items.filter(isRecord19) : [];
35131
+ if (receiptMatchesCurrentHead && !dirtyOverlap) {
35132
+ for (const [index, item] of items.entries()) {
35133
+ if (stringValue14(item.status)?.toLowerCase() !== "passed") continue;
35134
+ const label = stringValue14(item.text);
35135
+ if (!label) continue;
35136
+ context.verification.push(label);
35137
+ context.evidence.push({
35138
+ kind: "test",
35139
+ label,
35140
+ sourceRef: `${finalReportRef}#evidence-${index + 1}`,
35141
+ strength: 0.88
35142
+ });
35143
+ }
35144
+ } else if (items.length > 0) {
35145
+ context.caveats.push(
35146
+ "A prior workflow report overlaps this scope, but its passed checks were not counted as current verification because the receipt does not cover the current dirty/HEAD state."
35147
+ );
35148
+ }
35149
+ }
35150
+ return context;
35151
+ }
35152
+ function isReviewedDecisionSignal(signal) {
35153
+ const status = signal.status.toUpperCase();
35154
+ if (!["ACTIVE", "APPROVED", "ACCEPTED", "CONFIRMED"].includes(status)) return false;
35155
+ const tags = signal.tags.map((tag) => tag.toLowerCase());
35156
+ if (tags.some(
35157
+ (tag) => tag === "workflow-phase" || tag === "release" || tag === "auto-captured" || tag === "review-pending" || tag.startsWith("journal:")
35158
+ )) {
35159
+ return false;
35160
+ }
35161
+ return /decision/i.test(signal.recommendedAction);
35162
+ }
35163
+ function decisionsFromTeamSync(response, changedFiles) {
35164
+ const decisions = [];
35165
+ for (const signal of response.whatChanged.decisions.filter(isReviewedDecisionSignal)) {
35166
+ const affectedAnchors = matchingAnchors(
35167
+ [signal.title, signal.summary, ...signal.tags].join(" "),
35168
+ changedFiles
35169
+ );
35170
+ if (affectedAnchors.length === 0) continue;
35171
+ decisions.push({
35172
+ id: signal.id,
35173
+ title: signal.title,
35174
+ decision: signal.summary,
35175
+ status: "approved",
35176
+ confidenceScore: signal.impact?.toUpperCase() === "HIGH" ? 0.9 : 0.84,
35177
+ affectedAnchors,
35178
+ evidence: [
35179
+ {
35180
+ kind: "decision",
35181
+ label: `${signal.id}: ${signal.title}`,
35182
+ sourceRef: signal.id,
35183
+ strength: signal.impact?.toUpperCase() === "HIGH" ? 0.9 : 0.84
35184
+ }
35185
+ ]
35186
+ });
35187
+ }
35188
+ return decisions.slice(0, 8);
35189
+ }
35190
+ function contextQueryText(options, scope) {
35191
+ const task = options.task?.trim() || "Project Reality Check governing intent";
35192
+ const tokens = unique5([
35193
+ ...scopeTokens(task),
35194
+ ...scope.changedFiles.slice(0, 12).flatMap((file) => [...scopeTokens(file)]),
35195
+ "decision",
35196
+ "constraint"
35197
+ ]).slice(0, 8);
35198
+ return tokens.join(" ");
35199
+ }
35200
+ function documentsFromContext(result, changedFiles) {
35201
+ return result.sections.filter((section) => section.file && section.file !== "(unknown)").map((section) => ({
35202
+ path: section.file,
35203
+ title: section.title,
35204
+ contentPreview: section.content.slice(0, 1600),
35205
+ kind: /adr|decision/i.test(`${section.file} ${section.title}`) ? "ADR" : "DOC",
35206
+ sourceRef: `${section.file}#L${section.lines[0]}-L${section.lines[1]}`,
35207
+ affectedAnchors: matchingAnchors(
35208
+ `${section.file} ${section.title} ${section.content.slice(0, 800)}`,
35209
+ changedFiles
35210
+ )
35211
+ })).slice(0, 8);
35212
+ }
35213
+ async function collectHostedAutoContext(client, options, scope) {
35214
+ const context = emptyAutoContext();
35215
+ const [teamSync2, documents] = await Promise.allSettled([
35216
+ client.getTeamSyncWhatChanged({
35217
+ limit: 50,
35218
+ branch: scope.branch,
35219
+ paths: scope.changedFiles.slice(0, 20),
35220
+ recentFiles: scope.changedFiles.slice(0, 10)
35221
+ }),
35222
+ client.queryContext(contextQueryText(options, scope), 1200, {
35223
+ searchMode: "keyword",
35224
+ includeMetadata: true,
35225
+ includeAnswerPack: false,
35226
+ autoDecompose: false,
35227
+ includeSharedContext: false,
35228
+ includeAllTiers: false
35229
+ })
35230
+ ]);
35231
+ if (teamSync2.status === "fulfilled") {
35232
+ context.decisions = decisionsFromTeamSync(teamSync2.value, scope.changedFiles);
35233
+ } else {
35234
+ context.caveats.push(
35235
+ "Hosted reviewed-decision auto-linking was unavailable; explicit --decision inputs remain authoritative."
35236
+ );
35237
+ }
35238
+ if (documents.status === "fulfilled") {
35239
+ context.documents = documentsFromContext(documents.value, scope.changedFiles);
35240
+ } else {
35241
+ context.caveats.push(
35242
+ "Hosted document auto-context was unavailable; Reality Check continued with local and explicit evidence."
35243
+ );
35244
+ }
35245
+ return context;
35246
+ }
35247
+ function mergeAutoContext(local, hosted) {
35248
+ return {
35249
+ decisions: [...local.decisions, ...hosted.decisions],
35250
+ documents: [...local.documents, ...hosted.documents],
35251
+ evidence: [...local.evidence, ...hosted.evidence],
35252
+ verification: unique5([...local.verification, ...hosted.verification]),
35253
+ caveats: unique5([...local.caveats, ...hosted.caveats])
35254
+ };
35255
+ }
35256
+ function buildProjectRealityCheckForScope(options, scope, autoContext = emptyAutoContext()) {
35257
+ const decisionsById = new Map(
35258
+ autoContext.decisions.map((decision) => [decision.id, decision])
35259
+ );
35260
+ for (const [index, value] of (options.decision ?? []).entries()) {
35261
+ const decision = parseDecision(value, index);
35262
+ decisionsById.set(decision.id, decision);
35263
+ }
35264
+ const documentsByPath = new Map(
35265
+ autoContext.documents.map((document) => [document.path, document])
35266
+ );
35267
+ for (const value of options.document ?? []) {
35268
+ const document = parseDocument(value);
35269
+ documentsByPath.set(document.path, document);
35270
+ }
34927
35271
  const result = buildProjectRealityCheck({
34928
35272
  source: "local",
34929
35273
  task: options.task,
@@ -34933,17 +35277,35 @@ function buildLocalProjectRealityCheck(options) {
34933
35277
  changedFiles: scope.changedFiles,
34934
35278
  dirtyFiles: scope.dirtyFiles,
34935
35279
  diffSummary: scope.diffSummary,
34936
- decisions: (options.decision ?? []).map(parseDecision),
34937
- documents: (options.document ?? []).map(parseDocument),
34938
- verificationChecklist: options.verification ?? []
35280
+ decisions: [...decisionsById.values()],
35281
+ documents: [...documentsByPath.values()],
35282
+ evidence: autoContext.evidence,
35283
+ verificationChecklist: unique5([...autoContext.verification, ...options.verification ?? []])
34939
35284
  });
34940
- if (scope.caveats.length === 0) {
34941
- return result;
35285
+ const caveats = unique5([...result.caveats, ...scope.caveats, ...autoContext.caveats]);
35286
+ return { ...result, caveats };
35287
+ }
35288
+ function buildLocalProjectRealityCheck(options) {
35289
+ const scope = buildLocalGitScope(options);
35290
+ return buildProjectRealityCheckForScope(options, scope);
35291
+ }
35292
+ async function buildLocalProjectRealityCheckWithAutoContext(options, clientOverride) {
35293
+ const scope = buildLocalGitScope(options);
35294
+ let autoContext = collectLocalReceiptContext(scope);
35295
+ const configured = Boolean(clientOverride) || isConfigured({ cwd: scope.root });
35296
+ if (configured) {
35297
+ const timeoutMs = Math.max(1e3, Math.min(options.autoContextTimeoutMs ?? 12e3, 3e4));
35298
+ const client = clientOverride ?? createClient(timeoutMs, { cwd: scope.root });
35299
+ autoContext = mergeAutoContext(
35300
+ autoContext,
35301
+ await collectHostedAutoContext(client, options, scope)
35302
+ );
35303
+ } else {
35304
+ autoContext.caveats.push(
35305
+ "Hosted auto-context was skipped because this workspace is not configured; use --decision, --document, and --verification for explicit evidence."
35306
+ );
34942
35307
  }
34943
- return {
34944
- ...result,
34945
- caveats: [...result.caveats, ...scope.caveats]
34946
- };
35308
+ return buildProjectRealityCheckForScope(options, scope, autoContext);
34947
35309
  }
34948
35310
  function printRealityCheck(result) {
34949
35311
  console.log(import_chalk12.default.bold("Project Reality Check"));
@@ -34955,7 +35317,7 @@ function printRealityCheck(result) {
34955
35317
  console.log(renderProjectRealityCheckMarkdown(result));
34956
35318
  }
34957
35319
  async function realityCheckCommand(options) {
34958
- const result = buildLocalProjectRealityCheck(options);
35320
+ const result = options.autoContext === false ? buildLocalProjectRealityCheck(options) : await buildLocalProjectRealityCheckWithAutoContext(options);
34959
35321
  if (options.json) {
34960
35322
  console.log(JSON.stringify(result, null, 2));
34961
35323
  } else {
@@ -34967,7 +35329,7 @@ async function realityCheckCommand(options) {
34967
35329
  }
34968
35330
 
34969
35331
  // src/commands/context-control.ts
34970
- var fs33 = __toESM(require("fs"));
35332
+ var fs34 = __toESM(require("fs"));
34971
35333
  var path33 = __toESM(require("path"));
34972
35334
  var import_node_child_process15 = require("child_process");
34973
35335
  var import_chalk13 = __toESM(require("chalk"));
@@ -35018,7 +35380,7 @@ function resolveGitDriftScopePaths(cwd) {
35018
35380
  path33.join(".snipara", "decisions")
35019
35381
  ];
35020
35382
  const manifestPath = resolveManifestPath(cwd);
35021
- if (!fs33.existsSync(manifestPath)) {
35383
+ if (!fs34.existsSync(manifestPath)) {
35022
35384
  return normalizeScopePaths(scopePaths, cwd);
35023
35385
  }
35024
35386
  const manifestRead = readJsonFileSafe(manifestPath);
@@ -35068,12 +35430,12 @@ function receiptPathFor(receipt, cwd) {
35068
35430
  return path33.resolve(cwd, CONTEXT_CONTROL_APPLIED_RELATIVE_DIR, `${receipt.receiptId}.json`);
35069
35431
  }
35070
35432
  function writeStableJsonFile(filePath, value) {
35071
- fs33.mkdirSync(path33.dirname(filePath), { recursive: true });
35072
- fs33.writeFileSync(filePath, `${stableDecisionJsonStringify(value)}
35433
+ fs34.mkdirSync(path33.dirname(filePath), { recursive: true });
35434
+ fs34.writeFileSync(filePath, `${stableDecisionJsonStringify(value)}
35073
35435
  `, "utf8");
35074
35436
  }
35075
35437
  function readJsonFile4(filePath) {
35076
- return JSON.parse(fs33.readFileSync(filePath, "utf8"));
35438
+ return JSON.parse(fs34.readFileSync(filePath, "utf8"));
35077
35439
  }
35078
35440
  function buildStateOperation(options) {
35079
35441
  const target = assertContextControlTarget(
@@ -35265,7 +35627,7 @@ function applyLocalContextMutationPlan(options) {
35265
35627
  baseRevisionAtApply: currentRevision
35266
35628
  });
35267
35629
  const receiptPath = receiptPathFor(pendingReceipt, cwd);
35268
- if (fs33.existsSync(receiptPath)) {
35630
+ if (fs34.existsSync(receiptPath)) {
35269
35631
  const receipt2 = buildContextMutationApplyReceipt({
35270
35632
  plan,
35271
35633
  appliedAt: options.now,
@@ -35303,7 +35665,7 @@ function applyLocalContextMutationPlan(options) {
35303
35665
  continue;
35304
35666
  }
35305
35667
  const absoluteTarget = path33.resolve(cwd, target);
35306
- if (operation.mode === "create" && fs33.existsSync(absoluteTarget)) {
35668
+ if (operation.mode === "create" && fs34.existsSync(absoluteTarget)) {
35307
35669
  throw new Error(`Refusing to overwrite existing context-control file: ${target}`);
35308
35670
  }
35309
35671
  writeStableJsonFile(absoluteTarget, operation.content ?? {});
@@ -35337,8 +35699,8 @@ function applyLocalContextMutationPlan(options) {
35337
35699
  };
35338
35700
  }
35339
35701
  function listJsonFiles2(dir) {
35340
- if (!fs33.existsSync(dir)) return [];
35341
- return fs33.readdirSync(dir).filter((name) => name.endsWith(".json")).map((name) => path33.join(dir, name)).sort((left, right) => left.localeCompare(right));
35702
+ if (!fs34.existsSync(dir)) return [];
35703
+ return fs34.readdirSync(dir).filter((name) => name.endsWith(".json")).map((name) => path33.join(dir, name)).sort((left, right) => left.localeCompare(right));
35342
35704
  }
35343
35705
  function readJsonFileSafe(filePath) {
35344
35706
  try {
@@ -35417,7 +35779,7 @@ function collectGitDriftSignals(cwd) {
35417
35779
  }
35418
35780
  function collectWorkflowDriftSignals(cwd) {
35419
35781
  const workflowPath = path33.join(cwd, ".snipara", "workflow", "current.json");
35420
- if (!fs33.existsSync(workflowPath)) {
35782
+ if (!fs34.existsSync(workflowPath)) {
35421
35783
  return [
35422
35784
  {
35423
35785
  id: "workflow-state-missing",
@@ -35560,7 +35922,7 @@ function collectContextControlDriftSignals(cwd) {
35560
35922
  function collectProjectContextManifestDriftSignals(cwd) {
35561
35923
  const manifestPath = resolveManifestPath(cwd);
35562
35924
  const relative11 = toProjectRelativePath4(manifestPath, cwd);
35563
- if (!fs33.existsSync(manifestPath)) {
35925
+ if (!fs34.existsSync(manifestPath)) {
35564
35926
  return [
35565
35927
  {
35566
35928
  id: "project-context-manifest-missing",
@@ -35763,23 +36125,23 @@ function resolveHostedContextSources(cwd, manifestPath, report) {
35763
36125
  if (!report.manifest || report.status === "invalid") {
35764
36126
  throw new Error("ProjectContext manifest is invalid; run context-control validate first.");
35765
36127
  }
35766
- const workspaceRoot2 = fs33.realpathSync(cwd);
36128
+ const workspaceRoot2 = fs34.realpathSync(cwd);
35767
36129
  return report.manifest.sources.map((source2) => {
35768
36130
  const candidate = path33.resolve(cwd, source2.path);
35769
- if (!fs33.existsSync(candidate)) {
36131
+ if (!fs34.existsSync(candidate)) {
35770
36132
  throw new Error(`ProjectContext source is missing: ${source2.path}`);
35771
36133
  }
35772
- if (fs33.lstatSync(candidate).isSymbolicLink()) {
36134
+ if (fs34.lstatSync(candidate).isSymbolicLink()) {
35773
36135
  throw new Error(`ProjectContext source symlinks are not allowed: ${source2.path}`);
35774
36136
  }
35775
- const canonical = fs33.realpathSync(candidate);
36137
+ const canonical = fs34.realpathSync(candidate);
35776
36138
  if (canonical !== workspaceRoot2 && !canonical.startsWith(`${workspaceRoot2}${path33.sep}`)) {
35777
36139
  throw new Error(`ProjectContext source escapes the workspace: ${source2.path}`);
35778
36140
  }
35779
- if (!fs33.statSync(canonical).isFile()) {
36141
+ if (!fs34.statSync(canonical).isFile()) {
35780
36142
  throw new Error(`ProjectContext source must be a file: ${source2.path}`);
35781
36143
  }
35782
- const content = fs33.readFileSync(canonical, "utf8");
36144
+ const content = fs34.readFileSync(canonical, "utf8");
35783
36145
  if (Buffer.byteLength(content, "utf8") > 1e6) {
35784
36146
  throw new Error(`ProjectContext source exceeds 1 MB: ${source2.path}`);
35785
36147
  }
@@ -35914,7 +36276,7 @@ function uniqueStrings22(values) {
35914
36276
 
35915
36277
  // src/commands/references.ts
35916
36278
  var crypto6 = __toESM(require("crypto"));
35917
- var fs34 = __toESM(require("fs"));
36279
+ var fs35 = __toESM(require("fs"));
35918
36280
  var path34 = __toESM(require("path"));
35919
36281
  var import_chalk14 = __toESM(require("chalk"));
35920
36282
  var MANIFEST_VERSION2 = "snipara.references.v1";
@@ -35998,13 +36360,13 @@ function toRelative(root, file) {
35998
36360
  return path34.relative(root, file).split(path34.sep).join("/");
35999
36361
  }
36000
36362
  function ensureParentDir(file) {
36001
- fs34.mkdirSync(path34.dirname(file), { recursive: true });
36363
+ fs35.mkdirSync(path34.dirname(file), { recursive: true });
36002
36364
  }
36003
36365
  function walkFiles(root, extensions, maxFiles, files = []) {
36004
36366
  if (files.length >= maxFiles) {
36005
36367
  return files;
36006
36368
  }
36007
- for (const entry of fs34.readdirSync(root, { withFileTypes: true })) {
36369
+ for (const entry of fs35.readdirSync(root, { withFileTypes: true })) {
36008
36370
  if (files.length >= maxFiles) {
36009
36371
  break;
36010
36372
  }
@@ -36025,7 +36387,7 @@ function collectReferenceItems(root, files, allowDomains, denyDomains) {
36025
36387
  const byUrl = /* @__PURE__ */ new Map();
36026
36388
  const discoveredAt = (/* @__PURE__ */ new Date()).toISOString();
36027
36389
  for (const file of files) {
36028
- const content = fs34.readFileSync(file, "utf-8");
36390
+ const content = fs35.readFileSync(file, "utf-8");
36029
36391
  const lines = content.split(/\r?\n/);
36030
36392
  const markdownLink = /\[([^\]]+)\]\((https?:\/\/[^)\s]+)\)/g;
36031
36393
  const bareUrl = /https?:\/\/[^\s<>"'`]+/g;
@@ -36091,7 +36453,7 @@ function scanReferences(options = {}) {
36091
36453
  items
36092
36454
  };
36093
36455
  ensureParentDir(outputPath);
36094
- fs34.writeFileSync(outputPath, `${JSON.stringify(manifest, null, 2)}
36456
+ fs35.writeFileSync(outputPath, `${JSON.stringify(manifest, null, 2)}
36095
36457
  `, "utf-8");
36096
36458
  return {
36097
36459
  manifest,
@@ -36105,7 +36467,7 @@ function scanReferences(options = {}) {
36105
36467
  };
36106
36468
  }
36107
36469
  function readManifest2(file) {
36108
- const manifest = JSON.parse(fs34.readFileSync(file, "utf-8"));
36470
+ const manifest = JSON.parse(fs35.readFileSync(file, "utf-8"));
36109
36471
  if (manifest.version !== MANIFEST_VERSION2 || !Array.isArray(manifest.items)) {
36110
36472
  throw new Error(`${file} is not a ${MANIFEST_VERSION2} manifest`);
36111
36473
  }
@@ -36190,7 +36552,7 @@ async function fetchReference(item, outputDir, destinationPrefix, timeoutMs, max
36190
36552
  bodyHash: hash
36191
36553
  });
36192
36554
  ensureParentDir(snapshotPath);
36193
- fs34.writeFileSync(snapshotPath, markdown, "utf-8");
36555
+ fs35.writeFileSync(snapshotPath, markdown, "utf-8");
36194
36556
  return {
36195
36557
  item,
36196
36558
  fetchedAt,
@@ -36300,7 +36662,7 @@ async function ingestReferences(options = {}) {
36300
36662
  });
36301
36663
  }
36302
36664
  }
36303
- fs34.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}
36665
+ fs35.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}
36304
36666
  `, "utf-8");
36305
36667
  if (options.reindex && client) {
36306
36668
  await client.reindex({ kind: "doc", mode: "incremental" });
@@ -36354,7 +36716,7 @@ async function referencesIngestCommand(options) {
36354
36716
  // src/commands/run.ts
36355
36717
  var import_node_child_process16 = require("child_process");
36356
36718
  var import_node_crypto12 = require("crypto");
36357
- var fs35 = __toESM(require("fs"));
36719
+ var fs36 = __toESM(require("fs"));
36358
36720
  var path35 = __toESM(require("path"));
36359
36721
  var import_chalk15 = __toESM(require("chalk"));
36360
36722
 
@@ -36363,21 +36725,21 @@ var REGISTRY_VERSION = "project-intelligence.policy-gates.registry.v1";
36363
36725
  function normalizeChangedFiles(changedFiles) {
36364
36726
  return [...new Set((changedFiles ?? []).map((file) => file.trim()).filter(Boolean))];
36365
36727
  }
36366
- function isRecord19(value) {
36728
+ function isRecord20(value) {
36367
36729
  return typeof value === "object" && value !== null && !Array.isArray(value);
36368
36730
  }
36369
- function stringValue14(value) {
36731
+ function stringValue15(value) {
36370
36732
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
36371
36733
  }
36372
36734
  function nestedRecord3(root, keys) {
36373
36735
  let current = root;
36374
36736
  for (const key of keys) {
36375
- if (!isRecord19(current) || !isRecord19(current[key])) {
36737
+ if (!isRecord20(current) || !isRecord20(current[key])) {
36376
36738
  return {};
36377
36739
  }
36378
36740
  current = current[key];
36379
36741
  }
36380
- return isRecord19(current) ? current : {};
36742
+ return isRecord20(current) ? current : {};
36381
36743
  }
36382
36744
  function combinedText(input) {
36383
36745
  return [input.task, input.diffSummary, ...input.changedFiles ?? []].filter(Boolean).join("\n").toLowerCase();
@@ -36547,7 +36909,7 @@ function evaluateProjectPolicyGates(input) {
36547
36909
  );
36548
36910
  }
36549
36911
  const guardEval = guardEvaluation2(input.guard?.payload);
36550
- const guardDecision = stringValue14(guardEval.decision)?.toUpperCase();
36912
+ const guardDecision = stringValue15(guardEval.decision)?.toUpperCase();
36551
36913
  if (guardDecision === "BLOCKED" || input.release && input.guard?.status !== void 0 && input.guard.status !== 0) {
36552
36914
  gates.push(
36553
36915
  gate({
@@ -36785,8 +37147,8 @@ var GUARD_MAX_BUFFER_BYTES = 16 * 1024 * 1024;
36785
37147
  var RAW_OUTPUT_PREVIEW_BYTES = 64e3;
36786
37148
  var ADVISOR_RECEIPT_WRITE_LIMIT = 6;
36787
37149
  function buildProjectIntelligenceRunEnvelope(startedAt = /* @__PURE__ */ new Date()) {
36788
- const sniparaSessionId = stringValue15(process.env.SNIPARA_SESSION_ID)?.slice(0, 200);
36789
- const codexSessionId = stringValue15(process.env.CODEX_SESSION_ID)?.slice(0, 200);
37150
+ const sniparaSessionId = stringValue16(process.env.SNIPARA_SESSION_ID)?.slice(0, 200);
37151
+ const codexSessionId = stringValue16(process.env.CODEX_SESSION_ID)?.slice(0, 200);
36790
37152
  return {
36791
37153
  version: "project-intelligence.judgment-run-envelope.v1",
36792
37154
  runId: sniparaSessionId ?? codexSessionId ?? `judgment-run:${(0, import_node_crypto12.randomUUID)()}`,
@@ -36800,7 +37162,7 @@ function normalizeStringList6(values) {
36800
37162
  function uniqueStrings23(values) {
36801
37163
  return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
36802
37164
  }
36803
- function isRecord20(value) {
37165
+ function isRecord21(value) {
36804
37166
  return typeof value === "object" && value !== null && !Array.isArray(value);
36805
37167
  }
36806
37168
  function guardPayload(guard) {
@@ -36813,7 +37175,7 @@ function readOutcomeReceipts(files) {
36813
37175
  const receipts = [];
36814
37176
  for (const file of normalizeStringList6(files)) {
36815
37177
  const resolved = path35.resolve(process.cwd(), file);
36816
- const parsed = JSON.parse(fs35.readFileSync(resolved, "utf8"));
37178
+ const parsed = JSON.parse(fs36.readFileSync(resolved, "utf8"));
36817
37179
  receipts.push(...outcomeReceiptsFromUnknown(parsed));
36818
37180
  }
36819
37181
  return receipts;
@@ -36822,13 +37184,13 @@ function outcomeReceiptsFromUnknown(value) {
36822
37184
  if (Array.isArray(value)) {
36823
37185
  return value.flatMap(outcomeReceiptsFromUnknown);
36824
37186
  }
36825
- if (!isRecord20(value)) {
37187
+ if (!isRecord21(value)) {
36826
37188
  return [];
36827
37189
  }
36828
37190
  if (value.version === "snipara.outcome_intelligence.receipt.v0") {
36829
37191
  return [value];
36830
37192
  }
36831
- if (isRecord20(value.outcomeReceipt)) {
37193
+ if (isRecord21(value.outcomeReceipt)) {
36832
37194
  return outcomeReceiptsFromUnknown(value.outcomeReceipt);
36833
37195
  }
36834
37196
  if (Array.isArray(value.outcomeReceipts)) {
@@ -36846,11 +37208,11 @@ function outputPreview(value) {
36846
37208
  return `${value.slice(0, RAW_OUTPUT_PREVIEW_BYTES)}
36847
37209
  ...[truncated]`;
36848
37210
  }
36849
- function stringValue15(value) {
37211
+ function stringValue16(value) {
36850
37212
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
36851
37213
  }
36852
37214
  function servedJudgmentIdForRun(options, brief) {
36853
- return stringValue15(options.servedJudgmentId) ?? stringValue15(brief.servedJudgmentId) ?? servedJudgmentIdFromContext(brief.resumeContext) ?? servedJudgmentIdFromContext(brief.verificationPlan);
37215
+ return stringValue16(options.servedJudgmentId) ?? stringValue16(brief.servedJudgmentId) ?? servedJudgmentIdFromContext(brief.resumeContext) ?? servedJudgmentIdFromContext(brief.verificationPlan);
36854
37216
  }
36855
37217
  function advisorMeasurementState(args) {
36856
37218
  if (args.agentDecision === "blocked") return "blocked";
@@ -36927,7 +37289,7 @@ function boundedLifecycleText(value, maxChars) {
36927
37289
  return value.trim().replace(/\s+/g, " ").slice(0, maxChars);
36928
37290
  }
36929
37291
  function advisorRecommendationPlanScope(args) {
36930
- const requestedRecommendationId = stringValue15(args.options.advisorRecommendationId) ?? null;
37292
+ const requestedRecommendationId = stringValue16(args.options.advisorRecommendationId) ?? null;
36931
37293
  if (requestedRecommendationId) {
36932
37294
  const targeted = requestedRecommendationId === args.recommendationId;
36933
37295
  return {
@@ -37235,7 +37597,7 @@ async function recordFirstPartyAdvisorReceipts(args) {
37235
37597
  };
37236
37598
  }
37237
37599
  const client = createClient(1e4);
37238
- const verificationEvidence = args.verificationEvidence ?? [];
37600
+ const verificationEvidence2 = args.verificationEvidence ?? [];
37239
37601
  const outcomeReceipts = args.outcomeReceipts ?? [];
37240
37602
  const selectedRecommendations = allRecommendations.slice(0, ADVISOR_RECEIPT_WRITE_LIMIT);
37241
37603
  const overflowWrites = allRecommendations.slice(ADVISOR_RECEIPT_WRITE_LIMIT).map((recommendation) => skippedAdvisorReceiptWrite(recommendation, "write_limit_exceeded"));
@@ -37293,7 +37655,7 @@ async function recordFirstPartyAdvisorReceipts(args) {
37293
37655
  recommendation,
37294
37656
  recommendationIndex,
37295
37657
  totalRecommendations: allRecommendations.length,
37296
- verificationEvidence,
37658
+ verificationEvidence: verificationEvidence2,
37297
37659
  lifecycle,
37298
37660
  planScope,
37299
37661
  measurementState,
@@ -37379,7 +37741,7 @@ function runGuard(options, changedFiles) {
37379
37741
  let payload;
37380
37742
  try {
37381
37743
  const parsed = JSON.parse(result.stdout);
37382
- if (isRecord20(parsed)) {
37744
+ if (isRecord21(parsed)) {
37383
37745
  payload = parsed;
37384
37746
  }
37385
37747
  } catch {
@@ -37500,7 +37862,7 @@ async function buildProjectIntelligenceRun(options) {
37500
37862
  decision: brief.projectPolicyDecision
37501
37863
  } : void 0
37502
37864
  });
37503
- const verificationEvidence = verificationEvidenceFromRun({
37865
+ const verificationEvidence2 = verificationEvidenceFromRun({
37504
37866
  guard,
37505
37867
  packageReview,
37506
37868
  policyGates
@@ -37509,7 +37871,7 @@ async function buildProjectIntelligenceRun(options) {
37509
37871
  options,
37510
37872
  brief,
37511
37873
  judgmentCard,
37512
- verificationEvidence,
37874
+ verificationEvidence: verificationEvidence2,
37513
37875
  outcomeReceipts,
37514
37876
  runEnvelope
37515
37877
  });
@@ -37572,10 +37934,10 @@ async function projectIntelligenceRunCommand(options) {
37572
37934
  if (result.guard) {
37573
37935
  console.log(import_chalk15.default.bold("Guard"));
37574
37936
  console.log(`Status: ${result.guard.status}`);
37575
- const actionCards = isRecord20(result.guard.payload) ? result.guard.payload.actionCards : [];
37937
+ const actionCards = isRecord21(result.guard.payload) ? result.guard.payload.actionCards : [];
37576
37938
  if (Array.isArray(actionCards) && actionCards.length > 0) {
37577
37939
  for (const card of actionCards.slice(0, 6)) {
37578
- if (!isRecord20(card)) continue;
37940
+ if (!isRecord21(card)) continue;
37579
37941
  console.log(`- ${card.kind}: ${card.title ?? card.reason ?? "guard action"}`);
37580
37942
  }
37581
37943
  }
@@ -37640,7 +38002,7 @@ async function projectIntelligenceRunCommand(options) {
37640
38002
  }
37641
38003
 
37642
38004
  // src/commands/policy-ledger-sync.ts
37643
- var fs36 = __toESM(require("fs"));
38005
+ var fs37 = __toESM(require("fs"));
37644
38006
  var path36 = __toESM(require("path"));
37645
38007
  var POLICY_LEDGER_SYNC_REPORT_VERSION = "snipara.workflow_policy_ledger_sync.v0";
37646
38008
  function buildPolicyLedgerSyncReport(options = {}) {
@@ -37788,12 +38150,12 @@ function statusForChoiceClass(choiceClass) {
37788
38150
  return "modified";
37789
38151
  }
37790
38152
  function readJsonFiles(directory, cwd) {
37791
- if (!fs36.existsSync(directory)) {
38153
+ if (!fs37.existsSync(directory)) {
37792
38154
  return [];
37793
38155
  }
37794
- return fs36.readdirSync(directory).filter((fileName) => fileName.endsWith(".json")).sort().map((fileName) => {
38156
+ return fs37.readdirSync(directory).filter((fileName) => fileName.endsWith(".json")).sort().map((fileName) => {
37795
38157
  const filePath = path36.join(directory, fileName);
37796
- const parsed = JSON.parse(fs36.readFileSync(filePath, "utf8"));
38158
+ const parsed = JSON.parse(fs37.readFileSync(filePath, "utf8"));
37797
38159
  return { parsed, relativePath: toProjectRelativePath5(filePath, cwd) };
37798
38160
  });
37799
38161
  }
@@ -37998,7 +38360,11 @@ function collectOption(value, previous = []) {
37998
38360
  return [...previous, value];
37999
38361
  }
38000
38362
  function configureRealityCheckCommand(command) {
38001
- 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) => {
38363
+ 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-auto-context", "Disable bounded hosted/local context auto-linking").option(
38364
+ "--auto-context-timeout-ms <number>",
38365
+ "Timeout for each hosted auto-context source",
38366
+ "12000"
38367
+ ).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) => {
38002
38368
  await realityCheckCommand({
38003
38369
  task: options.task,
38004
38370
  branch: options.branch,
@@ -38008,6 +38374,8 @@ function configureRealityCheckCommand(command) {
38008
38374
  decision: options.decision,
38009
38375
  document: options.document,
38010
38376
  verification: options.verification,
38377
+ autoContext: options.autoContext !== false,
38378
+ autoContextTimeoutMs: Number.parseInt(options.autoContextTimeoutMs, 10),
38011
38379
  includeDirty: options.includeDirty,
38012
38380
  enforce: Boolean(options.enforce),
38013
38381
  dir: options.dir,
@@ -38487,13 +38855,18 @@ program.command("memory-guard").description(
38487
38855
  );
38488
38856
  program.command("query").description(
38489
38857
  "Search project documents, parsed files, and current truth through hosted Snipara context"
38490
- ).requiredOption("-q, --query <query>", "Search query").option("-m, --max-tokens <number>", "Maximum tokens", "8000").option(
38858
+ ).requiredOption("-q, --query <query>", "Search query").option("-m, --max-tokens <number>", "Maximum tokens", "8000").option("--search-mode <mode>", "Search mode: keyword|semantic|hybrid", "hybrid").option("--timeout-ms <number>", "Hosted context query timeout in milliseconds", "30000").option("--no-answer-pack", "Skip Answer Pack generation").option("--no-auto-decompose", "Disable automatic query decomposition").option("--no-shared-context", "Exclude linked shared context").option(
38491
38859
  "--follow-recommendation",
38492
38860
  "Automatically execute the recommended structural tool when Snipara returns one"
38493
38861
  ).option("--json", "Print raw JSON").action(async (options) => {
38494
38862
  await queryCommand({
38495
38863
  query: options.query,
38496
38864
  maxTokens: parseInt(options.maxTokens, 10),
38865
+ searchMode: options.searchMode,
38866
+ timeoutMs: parseInt(options.timeoutMs, 10),
38867
+ includeAnswerPack: options.answerPack !== false,
38868
+ autoDecompose: options.autoDecompose !== false,
38869
+ includeSharedContext: options.sharedContext !== false,
38497
38870
  followRecommendation: Boolean(options.followRecommendation),
38498
38871
  json: options.json
38499
38872
  });
@@ -40262,6 +40635,7 @@ if (require.main === module) {
40262
40635
  buildLocalProjectContextValidationReport,
40263
40636
  buildLocalProjectDriftReport,
40264
40637
  buildLocalProjectRealityCheck,
40638
+ buildLocalProjectRealityCheckWithAutoContext,
40265
40639
  buildLocalShortestPathResult,
40266
40640
  buildLocalSourceSnapshot,
40267
40641
  buildLocalSourceStatus,
@@ -913,6 +913,12 @@ headers, pass the same value as `correlation_context.session_id` on
913
913
  `snipara_context_query`, `snipara_recall`, `snipara_search`, `snipara_ask`, and
914
914
  `snipara_get_chunk`.
915
915
 
916
+ Companion's own Hosted MCP client always forwards the configured workspace
917
+ `sessionId` as `X-Snipara-Session-Id`. For the five correlated retrieval tools,
918
+ it also supplies `client: "snipara-companion"` when the caller did not provide a
919
+ client label. The session value is telemetry-only: it never authenticates the
920
+ request, changes project scope, or overrides explicit per-call correlation.
921
+
916
922
  OpenClaw hooks remain separate:
917
923
 
918
924
  ```bash
@@ -1044,6 +1050,7 @@ npx -y snipara-companion@latest plan --query "plan the auth refactor" --write-pl
1044
1050
  npx -y snipara-companion@latest task-commit --summary "Shipped auth refactor" --files apps/web/src/lib/auth.ts
1045
1051
 
1046
1052
  snipara-companion query --query "auth middleware"
1053
+ snipara-companion query --query "auth middleware" --search-mode keyword --no-answer-pack --timeout-ms 30000
1047
1054
  snipara-companion query --query "who calls src.mcp_transport.handle_call_tool" --follow-recommendation
1048
1055
  snipara-companion status
1049
1056
  snipara-companion brief --task "ship auth hardening" --changed-files apps/web/src/lib/auth.ts tests/auth.test.ts --diff-summary "auth hardening"
@@ -1266,7 +1273,13 @@ snipara-companion reality-check \
1266
1273
 
1267
1274
  The command reads the local Git scope by default, includes dirty files unless
1268
1275
  `--no-include-dirty` is set, and also accepts explicit `--changed-files` for
1269
- hooks or CI collectors. `--enforce` exits non-zero for `review_required` or
1276
+ hooks or CI collectors. When the workspace is configured, bounded auto-context
1277
+ loads reviewed Team Sync decisions, a narrow keyword document query, and local
1278
+ workflow receipts in parallel. Explicit `--decision`, `--document`, and
1279
+ `--verification` values take precedence. Use `--no-auto-context` for a purely
1280
+ local/explicit run or `--auto-context-timeout-ms` to tighten the hosted budget.
1281
+ Verification and workflow sources are retained in each finding's `evidence`
1282
+ array and in the top-level evidence summary. `--enforce` exits non-zero for `review_required` or
1270
1283
  `blocking` findings, but should stay opt-in until the matched surfaces,
1271
1284
  verification signals, and project-specific thresholds have been calibrated.
1272
1285
  Intent can be supplied as structured sections inside `--decision` or
@@ -1455,7 +1468,7 @@ snipara-companion workflow scaffold \
1455
1468
 
1456
1469
  Semantics:
1457
1470
 
1458
- - `snipara-companion query --follow-recommendation` = execute the hosted recommended structural tool instead of only printing it
1471
+ - `snipara-companion query --follow-recommendation` = execute the hosted recommended structural tool instead of only printing it; context retrieval defaults to a 30-second timeout and supports `--search-mode keyword|semantic|hybrid`, `--no-answer-pack`, `--no-auto-decompose`, and `--no-shared-context`
1459
1472
  - `snipara-companion workflow run --mode lite` = zero mandatory hosted calls for small known-file work
1460
1473
  - `snipara-companion workflow run --mode standard` = context query plus automatic `snipara_code_*` follow-up when Snipara recommends one
1461
1474
  - `snipara-companion workflow run --mode auto` = routes to lite, standard, full, or orchestrate from task intent
@@ -1467,7 +1480,7 @@ Semantics:
1467
1480
  - `snipara-companion status` = top-level agentic work status across local workflow state, git dirtiness, and Team Sync carryover
1468
1481
  - `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
1469
1482
  - `snipara-companion brief` = short alias for `snipara-companion intelligence brief`
1470
- - `snipara-companion reality-check` = local Project Reality Check plus Intent Ledger and Unknown Registry coverage for supplied or Git-derived changed files; `--enforce` is an opt-in strict mode for calibrated hooks
1483
+ - `snipara-companion reality-check` = Project Reality Check plus Intent Ledger, Unknown Registry, bounded auto-context, and inspectable evidence for supplied or Git-derived changed files; `--no-auto-context` keeps it local/explicit and `--enforce` is an opt-in strict mode for calibrated hooks
1471
1484
  - `snipara-companion timeline` = local timeline of workflow starts, phase starts, phase commits, final commits, and Team Sync handoffs
1472
1485
  - `snipara-companion workflow timeline` = append-only activity timeline from `.snipara/activity/timeline.jsonl`, including workflow, Producer Loop, Decision Request, and Team Sync events emitted by Companion commands; add `--export md` for a redacted Markdown artifact
1473
1486
  - `snipara-companion workflow session` = writes and prints Session Snapshot V0 at `.snipara/activity/session.json` with latest activity, risk, touched files, next action, advisory Intent Detection V0 intent/confidence/signals/suggested mode, workflow/session counts, Producer Loop calibration, decision counts, Team Sync counts, and `hardRoutingAllowed=false`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snipara-companion",
3
- "version": "3.5.2",
3
+ "version": "3.5.4",
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": {