snipara-companion 3.5.0 → 3.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  Release notes for `snipara-companion`, newest first.
4
4
 
5
+ ## New In 3.5.1
6
+
7
+ - Adds Context Control V1 hosted diff/apply commands for declarative
8
+ `snipara.project-context.json` sources.
9
+ - Binds hosted mutations to tenant-scoped server plans, remote compare-and-set
10
+ hashes, explicit resolved Decision Requests, EDITOR API-key access, and
11
+ detailed apply/reindex receipts.
12
+ - Keeps reconciliation add/update-only: unmanaged hosted documents are reported
13
+ but never deleted, managed authority promotions are blocked, and stale plans
14
+ fail before writes.
15
+ - Makes local V0 `context-control apply` enforce its review flag through an
16
+ explicit `--approve` acknowledgement.
17
+
5
18
  ## New In 3.5.0
6
19
 
7
20
  - Adds an explicit `workflow run --strong-repair` handoff contract for one
package/README.md CHANGED
@@ -100,7 +100,7 @@ These commands are useful without hosted Snipara:
100
100
  | `workflow producer-triage` | Ask for human review of unreviewed Producer Loop samples |
101
101
  | `workflow producer-report` | Local Producer Loop adoption and calibration report |
102
102
  | `workflow producer-review` | Mark local Producer Loop samples reviewed or rejected |
103
- | `context-control plan` / `apply` / `drift` / `validate` | Preview/apply local context mutations, report drift, and validate manifests |
103
+ | `context-control plan` / `apply` / `drift` / `validate` / `hosted-*` | Review local state and reconcile Context as Code with hosted project context |
104
104
  | `context-pack` | Reversible local packs for long logs, diffs, and tool output |
105
105
  | `judgment-card`, `verify`, `lead-plan`, `agent-readiness` | Local review artifacts and delegation contracts |
106
106
  | `intelligence ledger-export` | Structured redacted ledger JSON for replay and review |
@@ -111,8 +111,9 @@ These commands are useful without hosted Snipara:
111
111
  `context-control` is the local trust layer for Project Intelligence state. It
112
112
  borrows Terraform's useful product grammar without copying Terraform: preview a
113
113
  bounded context mutation, inspect drift, then apply only the exact reviewed
114
- plan. V0 is intentionally local-only: it creates trust artifacts for review, not
115
- hosted context mutations.
114
+ plan. V0 remains the local trust-artifact layer. Context Control V1 adds an
115
+ authenticated hosted diff/apply path with tenant scoping, compare-and-set hashes,
116
+ explicit Decision Request approval, detailed receipts, and add/update-only writes.
116
117
 
117
118
  ```bash
118
119
  npx -y snipara-companion context-control plan \
@@ -120,7 +121,8 @@ npx -y snipara-companion context-control plan \
120
121
  --output .snipara/context-control/plans/demo.json
121
122
 
122
123
  npx -y snipara-companion context-control apply \
123
- --plan .snipara/context-control/plans/demo.json
124
+ --plan .snipara/context-control/plans/demo.json \
125
+ --approve
124
126
 
125
127
  npx -y snipara-companion context-control drift
126
128
  ```
@@ -151,6 +153,21 @@ locally:
151
153
  }
152
154
  ```
153
155
 
156
+ To reconcile that manifest with hosted project context, first write a reviewed
157
+ plan and Decision Request, resolve the request, then apply the exact plan:
158
+
159
+ ```text
160
+ snipara-companion context-control hosted-diff --manifest snipara.project-context.json --output .snipara/context-control/plans/hosted.json --emit-decision-request
161
+ snipara-companion workflow decide <request-id> --choose approve_hosted_apply --reviewer <name>
162
+ snipara-companion context-control hosted-apply --plan .snipara/context-control/plans/hosted.json --approval .snipara/decisions/resolved/<request-id>.json --output .snipara/context-control/applied/hosted.json
163
+ ```
164
+
165
+ V1 never deletes remote documents. It reports hosted paths outside the manifest,
166
+ blocks authority promotions on existing managed sources, rejects stale remote
167
+ hashes, and requires an EDITOR-authorized API key for mutation. The local
168
+ approval artifact records declared human review; the API key remains the actual
169
+ hosted mutation authority.
170
+
154
171
  ```bash
155
172
  npx -y snipara-companion context-control validate --manifest snipara.project-context.json
156
173
  npx -y snipara-companion context-control plan --manifest snipara.project-context.json
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { AdvisorInfluenceLifecycle, ProjectIntentDetectionResult, ProjectPolicyDecision, ProjectRealityCheckResult, ContextMutationPlan, ContextMutationApplyReceipt, ProjectContextValidationReport, ProjectDriftReport, ProjectIntelligenceEngineeringLeadPlanSummary, ProjectPolicyRule, DecisionRequest, AdvisorInfluenceLifecycleState, OutcomeIntelligenceCalibration, ControlledWorkerExecutionMode, WorkerTrustCategory, ControlledWorkerExecutionReceipt, UnifiedReceiptEnvelope, WorkerTrustCandidate, WorkerProfile, WorkerTrustEvent } from '@snipara/project-intelligence-contracts';
2
+ import { AdvisorInfluenceLifecycle, HostedContextControlSource, HostedContextControlPlan, HostedContextControlApplyReceipt, ProjectIntentDetectionResult, ProjectPolicyDecision, ProjectRealityCheckResult, ContextMutationPlan, ContextMutationApplyReceipt, ProjectContextValidationReport, ProjectDriftReport, ProjectIntelligenceEngineeringLeadPlanSummary, ProjectPolicyRule, DecisionRequest, AdvisorInfluenceLifecycleState, OutcomeIntelligenceCalibration, ControlledWorkerExecutionMode, WorkerTrustCategory, ControlledWorkerExecutionReceipt, UnifiedReceiptEnvelope, WorkerTrustCandidate, WorkerProfile, WorkerTrustEvent } from '@snipara/project-intelligence-contracts';
3
3
 
4
4
  declare function resolveQueryFromToolInput(toolInput?: string, tool?: string): string | null;
5
5
 
@@ -299,6 +299,22 @@ interface AnswerPack {
299
299
  };
300
300
  token_count?: number;
301
301
  }
302
+ interface HostedContextControlDiffResponse {
303
+ project: {
304
+ id: string;
305
+ name: string;
306
+ slug: string;
307
+ };
308
+ plan: HostedContextControlPlan;
309
+ }
310
+ interface HostedContextControlApplyResponse {
311
+ project: {
312
+ id: string;
313
+ name: string;
314
+ slug: string;
315
+ };
316
+ receipt: HostedContextControlApplyReceipt;
317
+ }
302
318
  interface CodeGraphNodeResult {
303
319
  symbol_key: string;
304
320
  qualified_name: string;
@@ -1439,6 +1455,14 @@ declare class RLMClient {
1439
1455
  createClientProject(options: CreateClientProjectOptions): Promise<Record<string, unknown>>;
1440
1456
  syncDocuments(documents: SyncDocumentInput[], deleteMissing?: boolean): Promise<Record<string, unknown>>;
1441
1457
  syncProjectPolicyLedger(artifacts: ProjectPolicyLedgerSyncArtifactInput[]): Promise<Record<string, unknown>>;
1458
+ diffHostedContextControl(input: {
1459
+ manifestHash: string;
1460
+ sources: HostedContextControlSource[];
1461
+ }): Promise<HostedContextControlDiffResponse>;
1462
+ applyHostedContextControl(input: {
1463
+ plan: HostedContextControlPlan;
1464
+ approval?: unknown;
1465
+ }): Promise<HostedContextControlApplyResponse>;
1442
1466
  reindex(options: {
1443
1467
  kind?: "doc" | "code";
1444
1468
  mode?: "incremental" | "full";
@@ -2167,6 +2191,14 @@ interface RealityCheckCommandOptions {
2167
2191
  declare function buildLocalProjectRealityCheck(options: RealityCheckCommandOptions): ProjectRealityCheckResult;
2168
2192
  declare function realityCheckCommand(options: RealityCheckCommandOptions): Promise<void>;
2169
2193
 
2194
+ interface DecisionRequestWriteResult {
2195
+ status: "written" | "duplicate_pending" | "duplicate_resolved";
2196
+ requestId: string;
2197
+ fingerprint: string;
2198
+ path?: string;
2199
+ relativePath?: string;
2200
+ }
2201
+
2170
2202
  interface ContextControlPlanCommandOptions {
2171
2203
  summary?: string;
2172
2204
  target?: string;
@@ -2180,6 +2212,19 @@ interface ContextControlPlanCommandOptions {
2180
2212
  interface ContextControlApplyCommandOptions {
2181
2213
  plan: string;
2182
2214
  allowStaleBase?: boolean;
2215
+ approved?: boolean;
2216
+ json?: boolean;
2217
+ }
2218
+ interface ContextControlHostedDiffCommandOptions {
2219
+ manifest?: string;
2220
+ output?: string;
2221
+ emitDecisionRequest?: boolean;
2222
+ json?: boolean;
2223
+ }
2224
+ interface ContextControlHostedApplyCommandOptions {
2225
+ plan: string;
2226
+ approval?: string;
2227
+ output?: string;
2183
2228
  json?: boolean;
2184
2229
  }
2185
2230
  interface ContextControlDriftCommandOptions {
@@ -2219,14 +2264,8 @@ declare function contextControlPlanCommand(options: ContextControlPlanCommandOpt
2219
2264
  declare function contextControlApplyCommand(options: ContextControlApplyCommandOptions): Promise<void>;
2220
2265
  declare function contextControlDriftCommand(options: ContextControlDriftCommandOptions): Promise<void>;
2221
2266
  declare function contextControlValidateCommand(options: ContextControlValidateCommandOptions): Promise<void>;
2222
-
2223
- interface DecisionRequestWriteResult {
2224
- status: "written" | "duplicate_pending" | "duplicate_resolved";
2225
- requestId: string;
2226
- fingerprint: string;
2227
- path?: string;
2228
- relativePath?: string;
2229
- }
2267
+ declare function contextControlHostedDiffCommand(options: ContextControlHostedDiffCommandOptions): Promise<void>;
2268
+ declare function contextControlHostedApplyCommand(options: ContextControlHostedApplyCommandOptions): Promise<void>;
2230
2269
 
2231
2270
  interface MemoryHealthCommandOptions {
2232
2271
  scope?: MemoryScope;
@@ -4867,4 +4906,4 @@ declare function installAutomationBundle(args: {
4867
4906
  }): Promise<AutomationInstallResult>;
4868
4907
  declare function getAutomationStatus(projectDir?: string): AutomationStatusResult;
4869
4908
 
4870
- 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, 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 };
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 };
package/dist/index.js CHANGED
@@ -142,6 +142,8 @@ __export(index_exports, {
142
142
  completeTeamSyncWorkFromEvidence: () => completeTeamSyncWorkFromEvidence,
143
143
  contextControlApplyCommand: () => contextControlApplyCommand,
144
144
  contextControlDriftCommand: () => contextControlDriftCommand,
145
+ contextControlHostedApplyCommand: () => contextControlHostedApplyCommand,
146
+ contextControlHostedDiffCommand: () => contextControlHostedDiffCommand,
145
147
  contextControlPlanCommand: () => contextControlPlanCommand,
146
148
  contextControlValidateCommand: () => contextControlValidateCommand,
147
149
  contextPackCleanCommand: () => contextPackCleanCommand,
@@ -1609,6 +1611,26 @@ var RLMClient = class {
1609
1611
  }
1610
1612
  );
1611
1613
  }
1614
+ async diffHostedContextControl(input) {
1615
+ return this.dashboardProjectRequest(
1616
+ "/context-control",
1617
+ { method: "POST", body: { action: "diff", ...input } },
1618
+ {
1619
+ invalidMessage: "Invalid hosted Context Control diff response",
1620
+ validate: (data) => Boolean(data.project?.id && data.plan?.planHash)
1621
+ }
1622
+ );
1623
+ }
1624
+ async applyHostedContextControl(input) {
1625
+ return this.dashboardProjectRequest(
1626
+ "/context-control",
1627
+ { method: "POST", body: { action: "apply", ...input } },
1628
+ {
1629
+ invalidMessage: "Invalid hosted Context Control apply response",
1630
+ validate: (data) => Boolean(data.project?.id && data.receipt?.receiptId)
1631
+ }
1632
+ );
1633
+ }
1612
1634
  async reindex(options) {
1613
1635
  return this.mcpCall("snipara_reindex", {
1614
1636
  ...options.kind ? { kind: options.kind } : {},
@@ -11519,6 +11541,8 @@ var CONTEXT_MUTATION_APPLY_RECEIPT_VERSION = "snipara.context_mutation_apply_rec
11519
11541
  var PROJECT_DRIFT_REPORT_VERSION = "snipara.project_drift_report.v0";
11520
11542
  var PROJECT_CONTEXT_MANIFEST_VERSION = "snipara.project_context_manifest.v0";
11521
11543
  var PROJECT_CONTEXT_VALIDATION_VERSION = "snipara.project_context_validation.v0";
11544
+ var HOSTED_CONTEXT_CONTROL_PLAN_VERSION = "snipara.hosted_context_control_plan.v1";
11545
+ var HOSTED_CONTEXT_CONTROL_APPLY_RECEIPT_VERSION = "snipara.hosted_context_control_apply_receipt.v1";
11522
11546
  function buildContextMutationPlan(input) {
11523
11547
  const operations = normalizeOperations(input.operations);
11524
11548
  if (operations.length === 0) {
@@ -11637,6 +11661,14 @@ function validateProjectContextManifest(input) {
11637
11661
  ]
11638
11662
  };
11639
11663
  }
11664
+ function isHostedContextControlPlan(value) {
11665
+ if (!isRecord4(value)) return false;
11666
+ return value.schemaVersion === HOSTED_CONTEXT_CONTROL_PLAN_VERSION && typeof value.planId === "string" && typeof value.planHash === "string" && typeof value.createdAt === "string" && typeof value.projectId === "string" && typeof value.manifestHash === "string" && typeof value.approvalRequired === "boolean" && Array.isArray(value.sources) && Array.isArray(value.operations) && Array.isArray(value.unmanagedRemotePaths) && Array.isArray(value.warnings) && Array.isArray(value.caveats);
11667
+ }
11668
+ function isHostedContextControlApplyReceipt(value) {
11669
+ if (!isRecord4(value)) return false;
11670
+ return value.schemaVersion === HOSTED_CONTEXT_CONTROL_APPLY_RECEIPT_VERSION && typeof value.receiptId === "string" && typeof value.planId === "string" && typeof value.planHash === "string" && typeof value.projectId === "string" && typeof value.appliedAt === "string" && typeof value.status === "string" && Array.isArray(value.sources) && isRecord4(value.reindex) && Array.isArray(value.caveats);
11671
+ }
11640
11672
  function hashContextMutationPlanContent(value) {
11641
11673
  return hashDecisionJsonValue(value);
11642
11674
  }
@@ -35237,6 +35269,24 @@ function applyLocalContextMutationPlan(options) {
35237
35269
  });
35238
35270
  return { plan, receipt: receipt2, writtenFiles: [] };
35239
35271
  }
35272
+ if (plan.approvalRequired && !options.approved) {
35273
+ const receipt2 = buildContextMutationApplyReceipt({
35274
+ plan,
35275
+ appliedAt: options.now,
35276
+ status: "blocked",
35277
+ baseRevisionAtApply: resolveGitBaseRevision(cwd),
35278
+ skippedOperations: plan.operations.map((operation) => ({
35279
+ opId: operation.opId,
35280
+ kind: operation.kind,
35281
+ target: operation.target,
35282
+ status: "skipped",
35283
+ contentHash: operation.contentHash,
35284
+ message: "Explicit --approve acknowledgement was not provided."
35285
+ })),
35286
+ caveats: ["Re-run context-control apply with --approve after reviewing the plan."]
35287
+ });
35288
+ return { plan, receipt: receipt2, writtenFiles: [] };
35289
+ }
35240
35290
  const currentRevision = resolveGitBaseRevision(cwd);
35241
35291
  const staleBase = Boolean(plan.baseRevision.headSha && currentRevision.headSha) && plan.baseRevision.headSha !== currentRevision.headSha;
35242
35292
  if (staleBase && !options.allowStaleBase) {
@@ -35758,6 +35808,155 @@ async function contextControlValidateCommand(options) {
35758
35808
  process.exitCode = 1;
35759
35809
  }
35760
35810
  }
35811
+ function resolveHostedContextSources(cwd, manifestPath, report) {
35812
+ if (!report.manifest || report.status === "invalid") {
35813
+ throw new Error("ProjectContext manifest is invalid; run context-control validate first.");
35814
+ }
35815
+ const workspaceRoot2 = fs33.realpathSync(cwd);
35816
+ return report.manifest.sources.map((source2) => {
35817
+ const candidate = path33.resolve(cwd, source2.path);
35818
+ if (!fs33.existsSync(candidate)) {
35819
+ throw new Error(`ProjectContext source is missing: ${source2.path}`);
35820
+ }
35821
+ if (fs33.lstatSync(candidate).isSymbolicLink()) {
35822
+ throw new Error(`ProjectContext source symlinks are not allowed: ${source2.path}`);
35823
+ }
35824
+ const canonical = fs33.realpathSync(candidate);
35825
+ if (canonical !== workspaceRoot2 && !canonical.startsWith(`${workspaceRoot2}${path33.sep}`)) {
35826
+ throw new Error(`ProjectContext source escapes the workspace: ${source2.path}`);
35827
+ }
35828
+ if (!fs33.statSync(canonical).isFile()) {
35829
+ throw new Error(`ProjectContext source must be a file: ${source2.path}`);
35830
+ }
35831
+ const content = fs33.readFileSync(canonical, "utf8");
35832
+ if (Buffer.byteLength(content, "utf8") > 1e6) {
35833
+ throw new Error(`ProjectContext source exceeds 1 MB: ${source2.path}`);
35834
+ }
35835
+ return { ...source2, content };
35836
+ });
35837
+ }
35838
+ async function contextControlHostedDiffCommand(options) {
35839
+ const cwd = process.cwd();
35840
+ const manifestPath = resolveManifestPath(cwd, options.manifest);
35841
+ const report = buildLocalProjectContextValidationReport({ cwd, manifest: manifestPath });
35842
+ const sources = resolveHostedContextSources(cwd, manifestPath, report);
35843
+ const response = await createClient(6e4, { cwd }).diffHostedContextControl({
35844
+ manifestHash: report.manifestHash,
35845
+ sources
35846
+ });
35847
+ const result = {
35848
+ project: response.project,
35849
+ plan: response.plan
35850
+ };
35851
+ if (options.output) {
35852
+ const planPath = path33.resolve(cwd, options.output);
35853
+ writeStableJsonFile(planPath, response.plan);
35854
+ result.planPath = toProjectRelativePath4(planPath, cwd);
35855
+ }
35856
+ if (options.emitDecisionRequest && response.plan.approvalRequired) {
35857
+ if (response.plan.operations.some((operation) => operation.action === "blocked")) {
35858
+ throw new Error("Blocked hosted operations must be removed before requesting approval.");
35859
+ }
35860
+ const request = buildDecisionRequest({
35861
+ producer: {
35862
+ kind: "hosted_context_control",
35863
+ command: "context-control hosted-diff --emit-decision-request",
35864
+ sourceRef: response.plan.planId
35865
+ },
35866
+ decision: "Apply reviewed ProjectContext sources to hosted context",
35867
+ question: `Approve hosted Context Control plan ${response.plan.planId}?`,
35868
+ evidence: {
35869
+ summary: `${response.plan.operations.filter((operation) => operation.action === "create").length} create, ${response.plan.operations.filter((operation) => operation.action === "update").length} update, zero deletes.`,
35870
+ refs: [response.plan.planHash, toProjectRelativePath4(manifestPath, cwd)],
35871
+ items: [
35872
+ {
35873
+ ref: response.plan.planId,
35874
+ title: "Hosted Context Control plan",
35875
+ kind: "hosted_context_control_plan",
35876
+ metadata: {
35877
+ planHash: response.plan.planHash,
35878
+ projectId: response.plan.projectId
35879
+ }
35880
+ }
35881
+ ],
35882
+ reasonCodes: ["hosted_context_control_apply", "human_approval_required", "no_delete"],
35883
+ files: response.plan.sources.map((source2) => source2.path),
35884
+ applyPath: "context-control hosted-apply",
35885
+ applyCommand: `snipara-companion context-control hosted-apply --plan ${options.output ?? "<plan.json>"} --approval <resolved-decision.json>`
35886
+ },
35887
+ options: ["approve_hosted_apply", "reject_hosted_apply"],
35888
+ recommendation: "approve_hosted_apply",
35889
+ rationale: "The plan is bounded to reviewed add/update operations and contains no deletes.",
35890
+ blocking: true,
35891
+ expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1e3),
35892
+ fingerprintParts: [
35893
+ "hosted_context_control",
35894
+ response.plan.projectId,
35895
+ response.plan.planHash,
35896
+ response.plan.operations.map((operation) => ({
35897
+ path: operation.path,
35898
+ action: operation.action,
35899
+ contentHash: operation.contentHash,
35900
+ previousHash: operation.previousHash ?? null
35901
+ }))
35902
+ ]
35903
+ });
35904
+ result.decisionRequest = writeDecisionRequest(request, cwd);
35905
+ }
35906
+ if (options.json) {
35907
+ console.log(JSON.stringify(result, null, 2));
35908
+ return;
35909
+ }
35910
+ console.log(import_chalk13.default.bold("Hosted Context Control Diff"));
35911
+ console.log(`Project: ${response.project.name} (${response.project.id})`);
35912
+ console.log(`Plan: ${response.plan.planId}`);
35913
+ console.log(`Hash: ${response.plan.planHash}`);
35914
+ for (const operation of response.plan.operations) {
35915
+ console.log(`- ${operation.action} ${operation.path}`);
35916
+ }
35917
+ if (result.planPath) console.log(`Plan written: ${result.planPath}`);
35918
+ if (result.decisionRequest?.relativePath) {
35919
+ console.log(`Decision Request: ${result.decisionRequest.relativePath}`);
35920
+ }
35921
+ }
35922
+ async function contextControlHostedApplyCommand(options) {
35923
+ const cwd = process.cwd();
35924
+ const rawPlan = readJsonFile4(path33.resolve(cwd, options.plan));
35925
+ if (!isHostedContextControlPlan(rawPlan)) {
35926
+ throw new Error(`Invalid hosted Context Control plan: ${options.plan}`);
35927
+ }
35928
+ const approval = options.approval ? readJsonFile4(path33.resolve(cwd, options.approval)) : void 0;
35929
+ const response = await createClient(12e4, { cwd }).applyHostedContextControl({
35930
+ plan: rawPlan,
35931
+ approval
35932
+ });
35933
+ if (!isHostedContextControlApplyReceipt(response.receipt)) {
35934
+ throw new Error("Hosted Context Control apply returned an invalid receipt.");
35935
+ }
35936
+ const result = {
35937
+ project: response.project,
35938
+ receipt: response.receipt
35939
+ };
35940
+ if (options.output) {
35941
+ const receiptPath = path33.resolve(cwd, options.output);
35942
+ writeStableJsonFile(receiptPath, response.receipt);
35943
+ result.receiptPath = toProjectRelativePath4(receiptPath, cwd);
35944
+ }
35945
+ if (options.json) {
35946
+ console.log(JSON.stringify(result, null, 2));
35947
+ return;
35948
+ }
35949
+ console.log(import_chalk13.default.bold("Hosted Context Control Apply"));
35950
+ console.log(`Status: ${response.receipt.status}`);
35951
+ console.log(`Receipt: ${response.receipt.receiptId}`);
35952
+ for (const source2 of response.receipt.sources) {
35953
+ console.log(`- ${source2.action} ${source2.path}`);
35954
+ }
35955
+ if (result.receiptPath) console.log(`Receipt written: ${result.receiptPath}`);
35956
+ if (response.receipt.reindex.warning) {
35957
+ console.log(import_chalk13.default.yellow(`Reindex warning: ${response.receipt.reindex.warning}`));
35958
+ }
35959
+ }
35761
35960
  function uniqueStrings22(values) {
35762
35961
  return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
35763
35962
  }
@@ -38674,13 +38873,33 @@ contextControl.command("plan").description("Create a previewable local context m
38674
38873
  json: Boolean(options.json)
38675
38874
  });
38676
38875
  });
38677
- contextControl.command("apply").description("Apply a saved local context mutation plan idempotently").requiredOption("--plan <file>", "Plan JSON produced by context-control plan").option("--allow-stale-base", "Apply even when Git HEAD changed since planning").option("--json", "Print raw JSON").action(async (options) => {
38876
+ contextControl.command("apply").description("Apply a saved local context mutation plan idempotently").requiredOption("--plan <file>", "Plan JSON produced by context-control plan").option("--approve", "Acknowledge manual review when the local plan requires approval").option("--allow-stale-base", "Apply even when Git HEAD changed since planning").option("--json", "Print raw JSON").action(async (options) => {
38678
38877
  await contextControlApplyCommand({
38679
38878
  plan: options.plan,
38879
+ approved: Boolean(options.approve),
38680
38880
  allowStaleBase: Boolean(options.allowStaleBase),
38681
38881
  json: Boolean(options.json)
38682
38882
  });
38683
38883
  });
38884
+ contextControl.command("hosted-diff").description("Compare a local ProjectContext manifest with tenant-scoped hosted context").option("--manifest <file>", "ProjectContext manifest path", "snipara.project-context.json").option("-o, --output <file>", "Write the immutable hosted plan JSON").option(
38885
+ "--emit-decision-request",
38886
+ "Write a pending Decision Request bound to the hosted plan hash"
38887
+ ).option("--json", "Print raw JSON").action(async (options) => {
38888
+ await contextControlHostedDiffCommand({
38889
+ manifest: options.manifest,
38890
+ output: options.output,
38891
+ emitDecisionRequest: Boolean(options.emitDecisionRequest),
38892
+ json: Boolean(options.json)
38893
+ });
38894
+ });
38895
+ contextControl.command("hosted-apply").description("Apply an approved add/update-only hosted Context Control plan").requiredOption("--plan <file>", "Plan JSON produced by context-control hosted-diff").option("--approval <file>", "Resolved Decision Request artifact for mutating plans").option("-o, --output <file>", "Write the hosted apply receipt JSON").option("--json", "Print raw JSON").action(async (options) => {
38896
+ await contextControlHostedApplyCommand({
38897
+ plan: options.plan,
38898
+ approval: options.approval,
38899
+ output: options.output,
38900
+ json: Boolean(options.json)
38901
+ });
38902
+ });
38684
38903
  contextControl.command("drift").description("Report local project drift across git, workflow, decisions, and context plans").option("--json", "Print raw JSON").action(async (options) => {
38685
38904
  await contextControlDriftCommand({ json: Boolean(options.json) });
38686
38905
  });
@@ -40138,6 +40357,8 @@ if (require.main === module) {
40138
40357
  completeTeamSyncWorkFromEvidence,
40139
40358
  contextControlApplyCommand,
40140
40359
  contextControlDriftCommand,
40360
+ contextControlHostedApplyCommand,
40361
+ contextControlHostedDiffCommand,
40141
40362
  contextControlPlanCommand,
40142
40363
  contextControlValidateCommand,
40143
40364
  contextPackCleanCommand,
@@ -233,7 +233,7 @@ snipara-companion workflow producer-report
233
233
  snipara-companion workflow producer-review --latest --outcome useful --reviewer alice
234
234
  snipara-companion workflow run --adaptive-routing-dry-run --route-local-workers "document a scoped change"
235
235
  snipara-companion context-control plan --summary "record reviewed context state" --output .snipara/context-control/plans/demo.json
236
- snipara-companion context-control apply --plan .snipara/context-control/plans/demo.json
236
+ snipara-companion context-control apply --plan .snipara/context-control/plans/demo.json --approve
237
237
  snipara-companion context-control drift
238
238
  snipara-companion context-control validate --manifest snipara.project-context.json
239
239
  snipara-companion lead-plan --task "ship auth hardening" --changed-files src/auth.ts --proof "pnpm test auth" --acceptance "auth tests pass"
@@ -339,8 +339,9 @@ snipara-companion workflow resume --include-session-context
339
339
  - `context-control plan` writes a content-hashed local Context Mutation Plan V0
340
340
  for a bounded operation. The plan records the Git base and remains a preview
341
341
  until `context-control apply` writes the exact planned state.
342
- - `context-control apply --plan <file>` verifies the plan hash, rejects stale
343
- Git bases by default, writes only under `.snipara/context-control/`, and emits
342
+ - `context-control apply --plan <file> --approve` verifies the plan hash, records
343
+ explicit review, rejects stale Git bases by default, writes only under
344
+ `.snipara/context-control/`, and emits
344
345
  an apply receipt linked to the plan hash.
345
346
  - `context-control drift` is a read-only Project Drift V0 report. It checks Git
346
347
  upstream state, scoped Git dirty files, managed workflow state, pending
@@ -352,9 +353,21 @@ snipara-companion workflow resume --include-session-context
352
353
  `IN_SYNC`.
353
354
  - `context-control validate --manifest snipara.project-context.json` validates
354
355
  Context as Code V0. The manifest is JSON metadata declaring context sources,
355
- tiers, authority, freshness, and review policies. It does not upload content,
356
- refresh hosted context, reconcile manifest-vs-hosted state, or mutate hosted
357
- Snipara state; hosted refresh/apply belongs to the future V1 surface.
356
+ tiers, authority, freshness, and review policies. Validation itself does not
357
+ upload content or mutate hosted state.
358
+ - Context Control V1 uses `context-control hosted-diff` to produce a
359
+ tenant-scoped immutable plan and optional Decision Request, then
360
+ `context-control hosted-apply` to apply the resolved plan. The server rechecks
361
+ remote hashes atomically, allows only create/update, never deletes unmanaged
362
+ remote paths, blocks managed authority promotions, requires EDITOR API-key
363
+ access, and returns a per-source receipt plus reindex status.
364
+
365
+ ```text
366
+ $ snipara-companion context-control hosted-diff --manifest snipara.project-context.json --output .snipara/context-control/plans/hosted.json --emit-decision-request
367
+ $ snipara-companion workflow decide <request-id> --choose approve_hosted_apply --reviewer <name>
368
+ $ snipara-companion context-control hosted-apply --plan .snipara/context-control/plans/hosted.json --approval .snipara/decisions/resolved/<request-id>.json
369
+ ```
370
+
358
371
  - `lead-plan` turns local workflow state, Team Sync, file scope, context refs,
359
372
  proof gates, and acceptance criteria into an advisory Engineering Lead Plan.
360
373
  It emits worker recommendations and handoff contracts, keeps
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snipara-companion",
3
- "version": "3.5.0",
3
+ "version": "3.5.1",
4
4
  "description": "Local-first CLI that asks your repo what breaks before an AI coding agent edits it.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {