snipara-companion 2.2.0 → 2.3.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/README.md CHANGED
@@ -56,6 +56,7 @@ npx -y snipara-companion workflow start --goal "ship auth hardening"
56
56
  npx -y snipara-companion workflow phase-start audit
57
57
  npx -y snipara-companion lead-plan --task "ship auth hardening" --changed-files src/auth/session.ts --proof "pnpm test auth" --acceptance "auth tests pass"
58
58
  npx -y snipara-companion lead-plan --from-plan ./project-health-lead-plan.json --reconcile --changed-files src/auth/session.ts
59
+ npx -y snipara-companion lead-plan --from-plan ./project-health-lead-plan.json --json | jq '.engineeringLeadPlan.executionReceipts'
59
60
  npx -y snipara-companion workflow phase-commit audit --summary "mapped auth impact"
60
61
  npx -y snipara-companion handoff --summary "auth impact mapped" --next "run auth tests"
61
62
  ```
package/dist/index.d.ts CHANGED
@@ -2159,6 +2159,8 @@ declare const ENGINEERING_LEAD_WORKER_ROLES: readonly ["main_agent", "coding_wor
2159
2159
  declare const ENGINEERING_LEAD_ROUTING_MODES: readonly ["hold", "main_agent_execute", "explicit_handoff_ready", "needs_contract"];
2160
2160
  declare const ENGINEERING_LEAD_WORK_PACKAGE_STATUSES: readonly ["contracting", "ready_for_handoff", "executing", "verifying", "blocked", "closed", "unknown"];
2161
2161
  declare const ENGINEERING_LEAD_SUPERVISION_STATUSES: readonly ["on_track", "needs_review", "needs_replan", "blocked", "cold_start", "unknown"];
2162
+ declare const ENGINEERING_LEAD_EXECUTION_RECEIPT_STATUSES: readonly ["pending_handoff", "handoff_ready", "executing", "verification_required", "blocked", "closed", "unknown"];
2163
+ declare const ENGINEERING_LEAD_EXECUTION_RECEIPT_STAGES: readonly ["handoff", "claim", "approval", "proof", "outcome", "brain_update"];
2162
2164
  type EngineeringLeadPlanSummary = ProjectIntelligenceEngineeringLeadPlanSummary;
2163
2165
  interface CompanionEngineeringLeadReconciliation {
2164
2166
  status: "on_track" | "needs_review" | "needs_replan" | "blocked";
@@ -3363,6 +3365,7 @@ interface AdaptiveWorkProfile {
3363
3365
  contextBudget: string;
3364
3366
  reasoningDepth: string;
3365
3367
  evidenceRequirements?: string[];
3368
+ preferredProfileStrengths?: string[];
3366
3369
  notes?: string[];
3367
3370
  }
3368
3371
  interface AdaptiveModelRequirements {
@@ -3375,6 +3378,7 @@ interface AdaptiveModelRequirements {
3375
3378
  capabilities: string[];
3376
3379
  forbiddenCapabilities: string[];
3377
3380
  writeScope: string[];
3381
+ structuredOutputRequired?: boolean;
3378
3382
  preferredEndpointTypes?: string[];
3379
3383
  allowedEndpointTypes?: string[];
3380
3384
  catalogLimit?: number;
@@ -3392,13 +3396,13 @@ interface AdaptiveRoutingCard {
3392
3396
  requirements: AdaptiveModelRequirements;
3393
3397
  recommendedWorkerClass: string;
3394
3398
  costEstimate: AdaptiveRoutingCostEstimate;
3395
- humanApprovalRequired: true;
3399
+ humanApprovalRequired: boolean;
3396
3400
  fallback: "main_agent";
3397
3401
  reasons: string[];
3398
3402
  warnings: string[];
3399
3403
  }
3400
3404
  interface AdaptiveRoutingGatewayStatus {
3401
- source: "hosted_mcp";
3405
+ source: "hosted_mcp" | "local_orchestrator";
3402
3406
  success: boolean;
3403
3407
  resolutionStatus?: string;
3404
3408
  candidateCount: number;
@@ -3407,14 +3411,32 @@ interface AdaptiveRoutingGatewayStatus {
3407
3411
  }
3408
3412
  interface AdaptiveRoutingRuntimeCatalog {
3409
3413
  version?: string;
3414
+ source?: string;
3415
+ provider?: string;
3416
+ baseUrl?: string;
3417
+ models?: string[];
3418
+ apiPaths?: Record<string, unknown>;
3419
+ workerEndpoints?: Record<string, Record<string, unknown>>;
3420
+ workerProfiles?: Record<string, Record<string, unknown>>;
3410
3421
  candidates: Array<Record<string, unknown>>;
3411
3422
  }
3423
+ interface AdaptiveRoutingResolution {
3424
+ status?: string;
3425
+ selected?: Record<string, unknown>;
3426
+ policyDecision?: Record<string, unknown>;
3427
+ evaluatedCount?: number;
3428
+ rejectedCount?: number;
3429
+ fallback?: string;
3430
+ reasons?: string[];
3431
+ warnings?: string[];
3432
+ }
3412
3433
  interface AdaptiveWorkRoutingRecommendation {
3413
3434
  workProfile: AdaptiveWorkProfile;
3414
3435
  requirements: AdaptiveModelRequirements;
3415
3436
  routingCard: AdaptiveRoutingCard;
3416
3437
  gateway?: AdaptiveRoutingGatewayStatus;
3417
3438
  runtimeCatalog?: AdaptiveRoutingRuntimeCatalog;
3439
+ resolution?: AdaptiveRoutingResolution;
3418
3440
  }
3419
3441
  interface AdaptiveWorkRoutingOptions {
3420
3442
  query: string;
@@ -3424,6 +3446,8 @@ interface AdaptiveWorkRoutingOptions {
3424
3446
  allowedEndpointTypes?: string[];
3425
3447
  workerRole?: string;
3426
3448
  plannerRetainsReasoning?: boolean;
3449
+ preferredProfileStrengths?: string[];
3450
+ structuredOutputRequired?: boolean;
3427
3451
  catalogLimit?: number;
3428
3452
  dailyBudgetCents?: number;
3429
3453
  monthlyBudgetCents?: number;
@@ -3456,6 +3480,7 @@ interface OrchestratorHandoffArtifact {
3456
3480
  routingCard?: AdaptiveRoutingCard;
3457
3481
  gateway?: AdaptiveRoutingGatewayStatus;
3458
3482
  runtimeCatalog?: AdaptiveRoutingRuntimeCatalog;
3483
+ resolution?: AdaptiveRoutingResolution;
3459
3484
  };
3460
3485
  task: {
3461
3486
  title: string;
@@ -3519,4 +3544,4 @@ declare function buildOrchestratorHandoff(options: OrchestratorHandoffOptions):
3519
3544
  declare function buildAdaptiveWorkRoutingRecommendation(options: AdaptiveWorkRoutingOptions): AdaptiveWorkRoutingRecommendation;
3520
3545
  declare function writeOrchestratorHandoff(options: OrchestratorHandoffOptions): WrittenOrchestratorHandoff;
3521
3546
 
3522
- export { AUTOMATION_MANIFEST_RELATIVE_PATH, AutomationInstallConflictError, AutomationUnsupportedHookBundleError, COLLABORATION_STATE_RELATIVE_PATH, ENGINEERING_LEAD_POSTURES, ENGINEERING_LEAD_ROUTING_MODES, ENGINEERING_LEAD_STATUSES, ENGINEERING_LEAD_SUPERVISION_STATUSES, ENGINEERING_LEAD_WORKER_ROLES, ENGINEERING_LEAD_WORK_PACKAGE_STATUSES, ORCHESTRATOR_HANDOFF_RELATIVE_PATH, TEAM_SYNC_STATE_RELATIVE_PATH, WORKFLOW_PLANS_RELATIVE_DIR, WORKFLOW_STATE_RELATIVE_PATH, agentReadinessAuditCommand, archiveInactiveTeamSyncWork, attachLocalContextPackReceipts, autoArchiveTeamSyncState, buildAdaptiveWorkRoutingRecommendation, buildAgentReadinessAuditReport, buildAgenticHandoffMarkdown, buildAgenticTimeline, buildAgenticWorkStatus, buildAutomationInstallPlan, buildCanonicalEvent, buildCodeHooksInstallPlan, buildCodePromotionResult, buildCodeStatusResult, buildCodeSyncResult, buildCollaborationActor, buildCollaborationGuardActionCards, buildCollaborationHooksInstallPlan, buildCompanionEngineeringLeadPlanReport, buildContextPackStats, buildEvalCaseArtifact, buildGeneratedWorkflowPlanDocument, buildHostedCodeOverlayUploadPayload, buildHostedGuardPayload, buildJournalCheckpointEntry, buildLocalCallersResult, buildLocalCodeOverlay, buildLocalContextPackReceipt, buildLocalContextPackReceipts, buildLocalImpactResult, buildLocalImportsResult, buildLocalNeighborsResult, buildLocalShortestPathResult, buildMemoryAudit, buildOnboardFolderManifest, buildOrchestratorHandoff, buildProjectIntelligenceBrief, buildProjectIntelligenceRun, buildProjectJudgmentCard, buildSessionBootstrapQuality, buildSyncDocumentsDryRun, buildTeamSyncHandoffRecord, buildTeamSyncStartWorkRecord, buildTeamSyncSummary, buildToolCallPayload, buildToolResultPayload, buildVerificationPlan, buildWorkflowImpactGate, buildWorkflowPhaseCommitSummary, buildWorkflowPlanScaffold, categoryFromGuardTag, classifyToolResult, cleanContextPacks, collaborationIdeStatusCommand, collectAgentReadinessLocalSignals, collectSyncDocuments, collectSyncDocumentsInput, compactHostedGuardResources, completeTeamSyncStateFromEvidence, completeTeamSyncWorkFromEvidence, contextPackCleanCommand, contextPackPackCommand, contextPackRetrieveCommand, contextPackStatsCommand, createClient, createEmptyCollaborationState, createEmptyTeamSyncState, createLocalQueryCache, deriveLocalCollaborationResourcesFromFiles, detectReleaseSurfacesFromFiles, detectRuntimeEnvironment, evalExportCommand, evalRunCommand, evaluateProjectPolicyGates, extractCommandFromToolInput, extractFilesFromToolInput, formatAgentReadinessAuditReport, formatCompanionEngineeringLeadPlanReport, formatOrchestratorRecommendationReason, formatPolicyGateDecision, formatProjectJudgmentCard, formatStuckGuardDecision, getAutomationManifestPath, getAutomationStatus, getCollaborationStatePath, getConfigPath, getContextPackStoragePaths, getLocalCodeOverlayCachePath, getLocalCodePromotionStatePath, getOrchestratorRecommendation, getPlanStepDisplayTitle, getStagedFiles, getStuckGuardInjection, getTeamSyncStatePath, ingestReferences, installAutomationBundle, leadPlanCommand, listProjectsForApiKey, loadAutomationManifest, loadCollaborationState, loadConfig, loadTeamSyncState, memoryAuditCommand, memoryCleanCandidatesCommand, memoryCompactCommand, memoryHealthCommand, memoryLocalCommand, normalizeCollaborationFiles, normalizeGuardTag, normalizeWorkflowPlanInput, packContext, parseCollaborationResources, projectIntelligenceBriefCommand, projectIntelligenceRunCommand, readLocalCodeOverlayCache, readLocalCodePromotionState, referencesIngestCommand, referencesScanCommand, resolveContextPackRecord, resolveFullWorkflowTokenBudget, resolveQueryFromToolInput, retrieveContextPack, runMemoryGuardCheck, saveCollaborationState, saveConfig, saveTeamSyncState, scanReferences, shouldSuggestOrchestratorForWorkflow, shouldSuggestRuntimeForWorkflow, summarizeLocalCodeOverlay, teamSyncSweepCommand, validatePlanResult, verifyCommand, writeLocalCodeOverlayCache, writeLocalCodePromotionState, writeOrchestratorHandoff };
3547
+ export { AUTOMATION_MANIFEST_RELATIVE_PATH, AutomationInstallConflictError, AutomationUnsupportedHookBundleError, COLLABORATION_STATE_RELATIVE_PATH, ENGINEERING_LEAD_EXECUTION_RECEIPT_STAGES, ENGINEERING_LEAD_EXECUTION_RECEIPT_STATUSES, ENGINEERING_LEAD_POSTURES, ENGINEERING_LEAD_ROUTING_MODES, ENGINEERING_LEAD_STATUSES, ENGINEERING_LEAD_SUPERVISION_STATUSES, ENGINEERING_LEAD_WORKER_ROLES, ENGINEERING_LEAD_WORK_PACKAGE_STATUSES, ORCHESTRATOR_HANDOFF_RELATIVE_PATH, TEAM_SYNC_STATE_RELATIVE_PATH, WORKFLOW_PLANS_RELATIVE_DIR, WORKFLOW_STATE_RELATIVE_PATH, agentReadinessAuditCommand, archiveInactiveTeamSyncWork, attachLocalContextPackReceipts, autoArchiveTeamSyncState, buildAdaptiveWorkRoutingRecommendation, buildAgentReadinessAuditReport, buildAgenticHandoffMarkdown, buildAgenticTimeline, buildAgenticWorkStatus, buildAutomationInstallPlan, buildCanonicalEvent, buildCodeHooksInstallPlan, buildCodePromotionResult, buildCodeStatusResult, buildCodeSyncResult, buildCollaborationActor, buildCollaborationGuardActionCards, buildCollaborationHooksInstallPlan, buildCompanionEngineeringLeadPlanReport, buildContextPackStats, buildEvalCaseArtifact, buildGeneratedWorkflowPlanDocument, buildHostedCodeOverlayUploadPayload, buildHostedGuardPayload, buildJournalCheckpointEntry, buildLocalCallersResult, buildLocalCodeOverlay, buildLocalContextPackReceipt, buildLocalContextPackReceipts, buildLocalImpactResult, buildLocalImportsResult, buildLocalNeighborsResult, buildLocalShortestPathResult, buildMemoryAudit, buildOnboardFolderManifest, buildOrchestratorHandoff, buildProjectIntelligenceBrief, buildProjectIntelligenceRun, buildProjectJudgmentCard, buildSessionBootstrapQuality, buildSyncDocumentsDryRun, buildTeamSyncHandoffRecord, buildTeamSyncStartWorkRecord, buildTeamSyncSummary, buildToolCallPayload, buildToolResultPayload, buildVerificationPlan, buildWorkflowImpactGate, buildWorkflowPhaseCommitSummary, buildWorkflowPlanScaffold, categoryFromGuardTag, classifyToolResult, cleanContextPacks, collaborationIdeStatusCommand, collectAgentReadinessLocalSignals, collectSyncDocuments, collectSyncDocumentsInput, compactHostedGuardResources, completeTeamSyncStateFromEvidence, completeTeamSyncWorkFromEvidence, contextPackCleanCommand, contextPackPackCommand, contextPackRetrieveCommand, contextPackStatsCommand, createClient, createEmptyCollaborationState, createEmptyTeamSyncState, createLocalQueryCache, deriveLocalCollaborationResourcesFromFiles, detectReleaseSurfacesFromFiles, detectRuntimeEnvironment, evalExportCommand, evalRunCommand, evaluateProjectPolicyGates, extractCommandFromToolInput, extractFilesFromToolInput, formatAgentReadinessAuditReport, formatCompanionEngineeringLeadPlanReport, formatOrchestratorRecommendationReason, formatPolicyGateDecision, formatProjectJudgmentCard, formatStuckGuardDecision, getAutomationManifestPath, getAutomationStatus, getCollaborationStatePath, getConfigPath, getContextPackStoragePaths, getLocalCodeOverlayCachePath, getLocalCodePromotionStatePath, getOrchestratorRecommendation, getPlanStepDisplayTitle, getStagedFiles, getStuckGuardInjection, getTeamSyncStatePath, ingestReferences, installAutomationBundle, leadPlanCommand, listProjectsForApiKey, loadAutomationManifest, loadCollaborationState, loadConfig, loadTeamSyncState, memoryAuditCommand, memoryCleanCandidatesCommand, memoryCompactCommand, memoryHealthCommand, memoryLocalCommand, normalizeCollaborationFiles, normalizeGuardTag, normalizeWorkflowPlanInput, packContext, parseCollaborationResources, projectIntelligenceBriefCommand, projectIntelligenceRunCommand, readLocalCodeOverlayCache, readLocalCodePromotionState, referencesIngestCommand, referencesScanCommand, resolveContextPackRecord, resolveFullWorkflowTokenBudget, resolveQueryFromToolInput, retrieveContextPack, runMemoryGuardCheck, saveCollaborationState, saveConfig, saveTeamSyncState, scanReferences, shouldSuggestOrchestratorForWorkflow, shouldSuggestRuntimeForWorkflow, summarizeLocalCodeOverlay, teamSyncSweepCommand, validatePlanResult, verifyCommand, writeLocalCodeOverlayCache, writeLocalCodePromotionState, writeOrchestratorHandoff };
package/dist/index.js CHANGED
@@ -35,6 +35,8 @@ __export(index_exports, {
35
35
  AutomationInstallConflictError: () => AutomationInstallConflictError,
36
36
  AutomationUnsupportedHookBundleError: () => AutomationUnsupportedHookBundleError,
37
37
  COLLABORATION_STATE_RELATIVE_PATH: () => COLLABORATION_STATE_RELATIVE_PATH,
38
+ ENGINEERING_LEAD_EXECUTION_RECEIPT_STAGES: () => ENGINEERING_LEAD_EXECUTION_RECEIPT_STAGES,
39
+ ENGINEERING_LEAD_EXECUTION_RECEIPT_STATUSES: () => ENGINEERING_LEAD_EXECUTION_RECEIPT_STATUSES,
38
40
  ENGINEERING_LEAD_POSTURES: () => ENGINEERING_LEAD_POSTURES,
39
41
  ENGINEERING_LEAD_ROUTING_MODES: () => ENGINEERING_LEAD_ROUTING_MODES,
40
42
  ENGINEERING_LEAD_STATUSES: () => ENGINEERING_LEAD_STATUSES,
@@ -10499,6 +10501,23 @@ var PROJECT_INTELLIGENCE_ENGINEERING_LEAD_SUPERVISION_STATUSES = [
10499
10501
  "cold_start",
10500
10502
  "unknown"
10501
10503
  ];
10504
+ var PROJECT_INTELLIGENCE_ENGINEERING_LEAD_EXECUTION_RECEIPT_STATUSES = [
10505
+ "pending_handoff",
10506
+ "handoff_ready",
10507
+ "executing",
10508
+ "verification_required",
10509
+ "blocked",
10510
+ "closed",
10511
+ "unknown"
10512
+ ];
10513
+ var PROJECT_INTELLIGENCE_ENGINEERING_LEAD_EXECUTION_RECEIPT_STAGES = [
10514
+ "handoff",
10515
+ "claim",
10516
+ "approval",
10517
+ "proof",
10518
+ "outcome",
10519
+ "brain_update"
10520
+ ];
10502
10521
 
10503
10522
  // src/commands/lead-plan.ts
10504
10523
  var ENGINEERING_LEAD_STATUSES = PROJECT_HEALTH_COCKPIT_STATUSES;
@@ -10507,6 +10526,8 @@ var ENGINEERING_LEAD_WORKER_ROLES = PROJECT_INTELLIGENCE_ENGINEERING_LEAD_WORKER
10507
10526
  var ENGINEERING_LEAD_ROUTING_MODES = PROJECT_INTELLIGENCE_ENGINEERING_LEAD_ROUTING_MODES;
10508
10527
  var ENGINEERING_LEAD_WORK_PACKAGE_STATUSES = PROJECT_INTELLIGENCE_ENGINEERING_LEAD_WORK_PACKAGE_STATUSES;
10509
10528
  var ENGINEERING_LEAD_SUPERVISION_STATUSES = PROJECT_INTELLIGENCE_ENGINEERING_LEAD_SUPERVISION_STATUSES;
10529
+ var ENGINEERING_LEAD_EXECUTION_RECEIPT_STATUSES = PROJECT_INTELLIGENCE_ENGINEERING_LEAD_EXECUTION_RECEIPT_STATUSES;
10530
+ var ENGINEERING_LEAD_EXECUTION_RECEIPT_STAGES = PROJECT_INTELLIGENCE_ENGINEERING_LEAD_EXECUTION_RECEIPT_STAGES;
10510
10531
  var TARGET_LABELS = {
10511
10532
  codex: "Codex",
10512
10533
  "claude-code": "Claude Code",
@@ -10851,6 +10872,133 @@ function buildLocalSupervision(input) {
10851
10872
  ]
10852
10873
  };
10853
10874
  }
10875
+ function executionReceiptRequiredStagesForRecommendation(recommendation) {
10876
+ const stages = /* @__PURE__ */ new Set(["handoff", "proof", "outcome"]);
10877
+ if (recommendation && recommendation.role !== "main_agent") {
10878
+ stages.add("claim");
10879
+ }
10880
+ if (recommendation?.contract.approvalRequired) {
10881
+ stages.add("approval");
10882
+ }
10883
+ if ((recommendation?.brainUpdateCandidates.length ?? 0) > 0) {
10884
+ stages.add("brain_update");
10885
+ }
10886
+ return ENGINEERING_LEAD_EXECUTION_RECEIPT_STAGES.filter((stage) => stages.has(stage));
10887
+ }
10888
+ function missingRequirementsForExecutionReceipt(input) {
10889
+ const completed = new Set(input.completedStages);
10890
+ const missing = /* @__PURE__ */ new Set();
10891
+ if (!input.workPackage.owner) missing.add("owner");
10892
+ if (input.workPackage.writeScope.length === 0) missing.add("write_scope");
10893
+ if (input.workPackage.acceptanceCriteria.length === 0) missing.add("acceptance_criteria");
10894
+ if (input.workPackage.proofRequired.length === 0) missing.add("proof_gate");
10895
+ if (input.requiredStages.includes("handoff") && !completed.has("handoff")) {
10896
+ missing.add("handoff_receipt");
10897
+ }
10898
+ if (input.requiredStages.includes("claim") && !completed.has("claim")) {
10899
+ missing.add("claim_id");
10900
+ }
10901
+ if (input.requiredStages.includes("approval") && !completed.has("approval")) {
10902
+ missing.add("approval_receipt");
10903
+ }
10904
+ if (input.requiredStages.includes("proof") && !completed.has("proof")) {
10905
+ missing.add("proof_receipt");
10906
+ }
10907
+ if (input.requiredStages.includes("outcome") && !completed.has("outcome")) {
10908
+ missing.add("outcome_receipt");
10909
+ }
10910
+ if (input.brainUpdateCandidates.length > 0 && input.requiredStages.includes("brain_update") && !completed.has("brain_update")) {
10911
+ missing.add("brain_update_receipt");
10912
+ }
10913
+ return Array.from(missing).sort();
10914
+ }
10915
+ function executionReceiptStatusFromWorkPackage(input) {
10916
+ if (input.workPackage.status === "blocked") return "blocked";
10917
+ if (input.workPackage.status === "closed" && input.requiredStages.every((stage) => input.completedStages.includes(stage))) {
10918
+ return "closed";
10919
+ }
10920
+ if (input.workPackage.status === "executing") return "executing";
10921
+ if (input.workPackage.status === "verifying") return "verification_required";
10922
+ if (input.workPackage.status === "ready_for_handoff") return "handoff_ready";
10923
+ if (input.missingRequirements.length > 0) return "pending_handoff";
10924
+ return "handoff_ready";
10925
+ }
10926
+ function executionReceiptNextAction(input) {
10927
+ if (input.status === "blocked") {
10928
+ return "Resolve the blocking receipt or proof issue before delegated execution.";
10929
+ }
10930
+ if (input.missingRequirements.includes("handoff_receipt")) {
10931
+ return "Create or attach the handoff receipt before treating this package as delegated.";
10932
+ }
10933
+ if (input.missingRequirements.includes("approval_receipt")) {
10934
+ return "Capture approval before delegated execution can proceed.";
10935
+ }
10936
+ if (input.missingRequirements.includes("proof_receipt")) {
10937
+ return "Attach proof receipts before closure.";
10938
+ }
10939
+ if (input.missingRequirements.includes("outcome_receipt")) {
10940
+ return "Attach an outcome or closure receipt before Brain promotion.";
10941
+ }
10942
+ if (input.missingRequirements.includes("brain_update_receipt")) {
10943
+ return "Record the reviewed Project Brain update receipt.";
10944
+ }
10945
+ if (input.status === "closed") {
10946
+ return "Keep the closed receipt linked for future routing calibration.";
10947
+ }
10948
+ if (input.status === "executing") {
10949
+ return "Monitor liveness and collect proof, outcome, and Brain-update receipts.";
10950
+ }
10951
+ if (input.status === "verification_required") {
10952
+ return "Verify proof and outcome receipts before closure.";
10953
+ }
10954
+ return "Issue the explicit handoff package and collect the required receipts.";
10955
+ }
10956
+ function buildExpectedExecutionReceipts(input) {
10957
+ const recommendationsByWorkPackageId = new Map(
10958
+ input.workerRecommendations.filter((recommendation) => recommendation.workPackageId).map((recommendation) => [recommendation.workPackageId, recommendation])
10959
+ );
10960
+ return input.workPackages.map((workPackage) => {
10961
+ const recommendation = recommendationsByWorkPackageId.get(workPackage.id);
10962
+ const requiredStages = executionReceiptRequiredStagesForRecommendation(recommendation);
10963
+ const completedStages = [];
10964
+ const brainUpdateCandidates2 = recommendation?.brainUpdateCandidates ?? [];
10965
+ const missingRequirements = missingRequirementsForExecutionReceipt({
10966
+ workPackage,
10967
+ requiredStages,
10968
+ completedStages,
10969
+ brainUpdateCandidates: brainUpdateCandidates2
10970
+ });
10971
+ const status = executionReceiptStatusFromWorkPackage({
10972
+ workPackage,
10973
+ requiredStages,
10974
+ completedStages,
10975
+ missingRequirements
10976
+ });
10977
+ return {
10978
+ id: `engineering-lead-receipt:${workPackage.id}`,
10979
+ workPackageId: workPackage.id,
10980
+ workPackageTitle: workPackage.title,
10981
+ status,
10982
+ requiredStages,
10983
+ completedStages,
10984
+ handoffReceiptId: null,
10985
+ claimId: null,
10986
+ htaskId: null,
10987
+ approvalReceiptId: null,
10988
+ proofReceiptIds: [],
10989
+ outcomeReceiptId: null,
10990
+ brainUpdateReceiptId: null,
10991
+ proofRequired: workPackage.proofRequired,
10992
+ proofExecuted: [],
10993
+ missingRequirements,
10994
+ nextAction: executionReceiptNextAction({ status, missingRequirements }),
10995
+ replanTriggers: workPackage.replanTriggers,
10996
+ brainUpdateCandidates: brainUpdateCandidates2,
10997
+ evidence: workPackage.evidence,
10998
+ reasonCodes: [`engineering_lead_execution_receipt_${status}`, ...workPackage.reasonCodes]
10999
+ };
11000
+ });
11001
+ }
10854
11002
  function buildLocalEngineeringLeadPlan(input) {
10855
11003
  const score = computeScore(input);
10856
11004
  const posture = postureForLocalPlan({ ...input, score });
@@ -10919,6 +11067,10 @@ function buildLocalEngineeringLeadPlan(input) {
10919
11067
  workPackages,
10920
11068
  localSignals: input.localSignals
10921
11069
  });
11070
+ const executionReceipts = buildExpectedExecutionReceipts({
11071
+ workPackages,
11072
+ workerRecommendations: [worker]
11073
+ });
10922
11074
  return {
10923
11075
  version: PROJECT_INTELLIGENCE_ENGINEERING_LEAD_PLAN_VERSION,
10924
11076
  contractVersion: PROJECT_INTELLIGENCE_ENGINEERING_LEAD_CONTRACT_VERSION,
@@ -10932,6 +11084,7 @@ function buildLocalEngineeringLeadPlan(input) {
10932
11084
  failClosedFallback: "main_agent",
10933
11085
  workPackages,
10934
11086
  supervision,
11087
+ executionReceipts,
10935
11088
  workerRecommendations: [worker],
10936
11089
  proofGates: input.proofGates,
10937
11090
  brainUpdateActions: brainCandidates,
@@ -11048,6 +11201,93 @@ function normalizeWorkPackage(value, index) {
11048
11201
  reasonCodes
11049
11202
  };
11050
11203
  }
11204
+ function normalizeReceiptStages(field, value) {
11205
+ if (!Array.isArray(value)) {
11206
+ return { stages: [], reasonCodes: [] };
11207
+ }
11208
+ const stages = [];
11209
+ const reasonCodes = /* @__PURE__ */ new Set();
11210
+ for (const item of value) {
11211
+ const stage = cockpitEnumValue(
11212
+ field,
11213
+ ENGINEERING_LEAD_EXECUTION_RECEIPT_STAGES,
11214
+ item,
11215
+ "handoff"
11216
+ );
11217
+ if (stage.droppedReasonCode) {
11218
+ reasonCodes.add(stage.droppedReasonCode);
11219
+ continue;
11220
+ }
11221
+ if (!stages.includes(stage.value)) {
11222
+ stages.push(stage.value);
11223
+ }
11224
+ }
11225
+ return { stages, reasonCodes: Array.from(reasonCodes) };
11226
+ }
11227
+ function normalizeExecutionReceipt(value, index, workPackages, workerRecommendations) {
11228
+ const workPackageId = stringValue3(value.workPackageId) ?? workPackages[index]?.id ?? `work-package:${index + 1}`;
11229
+ const workPackage = workPackages.find((candidate) => candidate.id === workPackageId);
11230
+ const recommendation = workerRecommendations.find(
11231
+ (candidate) => candidate.workPackageId === workPackageId
11232
+ );
11233
+ const fallbackRequiredStages = executionReceiptRequiredStagesForRecommendation(recommendation);
11234
+ const requiredStages = normalizeReceiptStages("execution_receipt_stage", value.requiredStages);
11235
+ const completedStages = normalizeReceiptStages("execution_receipt_stage", value.completedStages);
11236
+ const normalizedRequiredStages = requiredStages.stages.length > 0 ? requiredStages.stages : fallbackRequiredStages;
11237
+ const normalizedCompletedStages = completedStages.stages.filter(
11238
+ (stage) => normalizedRequiredStages.includes(stage)
11239
+ );
11240
+ const brainUpdateCandidates2 = stringList(value.brainUpdateCandidates).length > 0 ? stringList(value.brainUpdateCandidates) : recommendation?.brainUpdateCandidates ?? [];
11241
+ const derivedMissing = workPackage && missingRequirementsForExecutionReceipt({
11242
+ workPackage,
11243
+ requiredStages: normalizedRequiredStages,
11244
+ completedStages: normalizedCompletedStages,
11245
+ brainUpdateCandidates: brainUpdateCandidates2
11246
+ });
11247
+ const missingRequirements = stringList(value.missingRequirements).length > 0 ? stringList(value.missingRequirements) : derivedMissing ?? [];
11248
+ const fallbackStatus = workPackage ? executionReceiptStatusFromWorkPackage({
11249
+ workPackage,
11250
+ requiredStages: normalizedRequiredStages,
11251
+ completedStages: normalizedCompletedStages,
11252
+ missingRequirements
11253
+ }) : "pending_handoff";
11254
+ const status = cockpitEnumValue(
11255
+ "execution_receipt_status",
11256
+ ENGINEERING_LEAD_EXECUTION_RECEIPT_STATUSES,
11257
+ value.status,
11258
+ fallbackStatus
11259
+ );
11260
+ return {
11261
+ id: stringValue3(value.id) ?? `engineering-lead-receipt:${workPackageId}`,
11262
+ workPackageId,
11263
+ workPackageTitle: stringValue3(value.workPackageTitle) ?? workPackage?.title ?? `Imported work package ${index + 1}`,
11264
+ status: status.value,
11265
+ requiredStages: normalizedRequiredStages,
11266
+ completedStages: normalizedCompletedStages,
11267
+ handoffReceiptId: stringValue3(value.handoffReceiptId) ?? null,
11268
+ claimId: stringValue3(value.claimId) ?? null,
11269
+ htaskId: stringValue3(value.htaskId) ?? null,
11270
+ approvalReceiptId: stringValue3(value.approvalReceiptId) ?? null,
11271
+ proofReceiptIds: stringList(value.proofReceiptIds),
11272
+ outcomeReceiptId: stringValue3(value.outcomeReceiptId) ?? null,
11273
+ brainUpdateReceiptId: stringValue3(value.brainUpdateReceiptId) ?? null,
11274
+ proofRequired: stringList(value.proofRequired).length > 0 ? stringList(value.proofRequired) : workPackage?.proofRequired ?? [],
11275
+ proofExecuted: stringList(value.proofExecuted),
11276
+ missingRequirements,
11277
+ nextAction: stringValue3(value.nextAction) ?? executionReceiptNextAction({ status: status.value, missingRequirements }),
11278
+ replanTriggers: stringList(value.replanTriggers).length > 0 ? stringList(value.replanTriggers) : workPackage?.replanTriggers ?? [],
11279
+ brainUpdateCandidates: brainUpdateCandidates2,
11280
+ evidence: normalizeEvidence(value.evidence).length > 0 ? normalizeEvidence(value.evidence) : workPackage?.evidence ?? [],
11281
+ reasonCodes: [
11282
+ .../* @__PURE__ */ new Set([
11283
+ ...stringList(value.reasonCodes),
11284
+ ...compactReasonCodes([status.droppedReasonCode]),
11285
+ ...requiredStages.reasonCodes,
11286
+ ...completedStages.reasonCodes
11287
+ ])
11288
+ ]
11289
+ };
11290
+ }
11051
11291
  function summarizeSupervisionFromWorkPackages(workPackages) {
11052
11292
  const blockedWorkPackages = workPackages.filter(
11053
11293
  (workPackage) => workPackage.status === "blocked"
@@ -11150,6 +11390,10 @@ function normalizeCockpitPlan(cockpit) {
11150
11390
  );
11151
11391
  const workPackages = recordList2(rawPlan.workPackages).map(normalizeWorkPackage);
11152
11392
  const supervision = normalizeSupervision(rawPlan.supervision, workPackages);
11393
+ const rawExecutionReceipts = recordList2(rawPlan.executionReceipts);
11394
+ const executionReceipts = rawExecutionReceipts.length > 0 ? rawExecutionReceipts.map(
11395
+ (receipt, index) => normalizeExecutionReceipt(receipt, index, workPackages, workerRecommendations)
11396
+ ) : buildExpectedExecutionReceipts({ workPackages, workerRecommendations });
11153
11397
  const posture = cockpitEnumValue(
11154
11398
  "posture",
11155
11399
  ENGINEERING_LEAD_POSTURES,
@@ -11171,6 +11415,9 @@ function normalizeCockpitPlan(cockpit) {
11171
11415
  const supervisionDroppedReasonCodes = supervision.reasonCodes.filter(
11172
11416
  (code2) => code2.startsWith("companion_dropped_unknown_")
11173
11417
  );
11418
+ const executionReceiptDroppedReasonCodes = executionReceipts.flatMap(
11419
+ (receipt) => receipt.reasonCodes.filter((code2) => code2.startsWith("companion_dropped_unknown_"))
11420
+ );
11174
11421
  return {
11175
11422
  version: PROJECT_INTELLIGENCE_ENGINEERING_LEAD_PLAN_VERSION,
11176
11423
  contractVersion: PROJECT_INTELLIGENCE_ENGINEERING_LEAD_CONTRACT_VERSION,
@@ -11184,6 +11431,7 @@ function normalizeCockpitPlan(cockpit) {
11184
11431
  failClosedFallback: "main_agent",
11185
11432
  workPackages,
11186
11433
  supervision,
11434
+ executionReceipts,
11187
11435
  workerRecommendations,
11188
11436
  proofGates: stringList(rawPlan.proofGates),
11189
11437
  brainUpdateActions: stringList(rawPlan.brainUpdateActions),
@@ -11206,7 +11454,8 @@ function normalizeCockpitPlan(cockpit) {
11206
11454
  ...stringList(rawPlan.reasonCodes),
11207
11455
  ...workerDroppedReasonCodes,
11208
11456
  ...workPackageDroppedReasonCodes,
11209
- ...supervisionDroppedReasonCodes
11457
+ ...supervisionDroppedReasonCodes,
11458
+ ...executionReceiptDroppedReasonCodes
11210
11459
  ])
11211
11460
  ]
11212
11461
  };
@@ -11223,6 +11472,7 @@ function reconcileEngineeringLeadPlan(input) {
11223
11472
  const reasonCodes = /* @__PURE__ */ new Set(["companion_lead_plan_reconciled"]);
11224
11473
  const plannedScope = scopeSetForPlan(input.plan);
11225
11474
  const outOfScopeFiles = input.changedFiles.filter((file) => !plannedScope.has(file));
11475
+ const executionReceipts = input.plan.executionReceipts ?? [];
11226
11476
  if (input.plan.workPackages.length === 0) {
11227
11477
  changedSignals.add("no_imported_work_packages");
11228
11478
  recommendedActions.add("Create or import bounded work packages before delegation.");
@@ -11270,9 +11520,25 @@ function reconcileEngineeringLeadPlan(input) {
11270
11520
  for (const trigger of input.plan.supervision.replanTriggers) {
11271
11521
  recommendedActions.add(trigger);
11272
11522
  }
11273
- const blocked = input.plan.supervision.status === "blocked" || input.plan.workPackages.some((workPackage) => workPackage.status === "blocked");
11523
+ for (const receipt of executionReceipts) {
11524
+ if (receipt.status === "blocked") {
11525
+ changedSignals.add(`blocked_execution_receipt:${receipt.workPackageId}`);
11526
+ recommendedActions.add(receipt.nextAction);
11527
+ reasonCodes.add("companion_reconcile_execution_receipt_blocked");
11528
+ }
11529
+ if (receipt.missingRequirements.length > 0) {
11530
+ changedSignals.add(
11531
+ `execution_receipt_missing:${receipt.workPackageId}:${receipt.missingRequirements.join(",")}`
11532
+ );
11533
+ recommendedActions.add(
11534
+ `Attach missing execution receipt requirement(s) for ${receipt.workPackageTitle}: ${receipt.missingRequirements.join(", ")}.`
11535
+ );
11536
+ reasonCodes.add("companion_reconcile_execution_receipt_missing_requirements");
11537
+ }
11538
+ }
11539
+ const blocked = input.plan.supervision.status === "blocked" || input.plan.workPackages.some((workPackage) => workPackage.status === "blocked") || executionReceipts.some((receipt) => receipt.status === "blocked");
11274
11540
  const replanRequired = blocked || input.plan.supervision.replanRequired || outOfScopeFiles.length > 0 || !input.localSignals.workflow.present || input.localSignals.workflow.status !== "active";
11275
- const reviewRequired = replanRequired || input.plan.supervision.reviewRequired || !input.localSignals.teamSync.present || input.declaredRisks.length > 0;
11541
+ const reviewRequired = replanRequired || input.plan.supervision.reviewRequired || executionReceipts.some((receipt) => receipt.missingRequirements.length > 0) || !input.localSignals.teamSync.present || input.declaredRisks.length > 0;
11276
11542
  const status = blocked ? "blocked" : replanRequired ? "needs_replan" : reviewRequired ? "needs_review" : "on_track";
11277
11543
  return {
11278
11544
  status,
@@ -11390,6 +11656,7 @@ function formatList2(values, empty = "none") {
11390
11656
  }
11391
11657
  function formatCompanionEngineeringLeadPlanReport(report) {
11392
11658
  const plan = report.engineeringLeadPlan;
11659
+ const executionReceipts = plan.executionReceipts ?? [];
11393
11660
  const lines = [];
11394
11661
  lines.push("Companion Engineering Lead Plan");
11395
11662
  lines.push(`Generated: ${report.generatedAt}`);
@@ -11437,6 +11704,25 @@ function formatCompanionEngineeringLeadPlanReport(report) {
11437
11704
  }
11438
11705
  }
11439
11706
  lines.push("");
11707
+ lines.push("Execution Receipts");
11708
+ if (executionReceipts.length === 0) {
11709
+ lines.push("- none");
11710
+ } else {
11711
+ for (const receipt of executionReceipts) {
11712
+ lines.push(`- [${receipt.status}] ${receipt.workPackageTitle}`);
11713
+ lines.push(` package: ${receipt.workPackageId}`);
11714
+ lines.push(` required stages: ${formatList2(receipt.requiredStages)}`);
11715
+ lines.push(` completed stages: ${formatList2(receipt.completedStages)}`);
11716
+ lines.push(` handoff receipt: ${receipt.handoffReceiptId ?? "missing"}`);
11717
+ lines.push(` claim: ${receipt.claimId ?? "missing"}`);
11718
+ lines.push(` approval receipt: ${receipt.approvalReceiptId ?? "missing"}`);
11719
+ lines.push(` outcome receipt: ${receipt.outcomeReceiptId ?? "missing"}`);
11720
+ lines.push(` brain update receipt: ${receipt.brainUpdateReceiptId ?? "missing"}`);
11721
+ lines.push(` missing: ${formatList2(receipt.missingRequirements)}`);
11722
+ lines.push(` next: ${receipt.nextAction}`);
11723
+ }
11724
+ }
11725
+ lines.push("");
11440
11726
  lines.push("Worker Recommendations");
11441
11727
  for (const worker of plan.workerRecommendations) {
11442
11728
  lines.push(`- [${worker.status}] ${worker.label} (${worker.role}, ${worker.routingMode})`);
@@ -14341,7 +14627,8 @@ function buildOrchestratorHandoff(options) {
14341
14627
  requirements: options.adaptiveRouting.requirements,
14342
14628
  routingCard: options.adaptiveRouting.routingCard,
14343
14629
  ...options.adaptiveRouting.gateway ? { gateway: options.adaptiveRouting.gateway } : {},
14344
- ...options.adaptiveRouting.runtimeCatalog ? { runtimeCatalog: options.adaptiveRouting.runtimeCatalog } : {}
14630
+ ...options.adaptiveRouting.runtimeCatalog ? { runtimeCatalog: options.adaptiveRouting.runtimeCatalog } : {},
14631
+ ...options.adaptiveRouting.resolution ? { resolution: options.adaptiveRouting.resolution } : {}
14345
14632
  } : {}
14346
14633
  },
14347
14634
  task: {
@@ -14394,8 +14681,12 @@ function buildAdaptiveWorkRoutingRecommendation(options) {
14394
14681
  const reasoningDepth = inferAdaptiveReasoningDepth(risk, taskType);
14395
14682
  const workerRole = options.workerRole ?? inferAdaptiveWorkerRole(taskType);
14396
14683
  const plannerRetainsReasoning = options.plannerRetainsReasoning ?? preferredEndpointTypes.includes("local");
14684
+ const preferredProfileStrengths = normalizeProfileStrengths(
14685
+ options.preferredProfileStrengths ?? inferAdaptivePreferredProfileStrengths(taskType, options.query, changedFiles, workerRole)
14686
+ );
14397
14687
  const capabilities = inferAdaptiveCapabilities(taskType, workerRole);
14398
14688
  const forbiddenCapabilities = risk === "high" ? ["secrets", "prod_write"] : ["secrets"];
14689
+ const structuredOutputRequired = options.structuredOutputRequired ?? inferAdaptiveStructuredOutputRequirement(taskType, options.query, changedFiles, workerRole);
14399
14690
  const workProfile = compactObject2({
14400
14691
  taskType,
14401
14692
  risk,
@@ -14403,6 +14694,7 @@ function buildAdaptiveWorkRoutingRecommendation(options) {
14403
14694
  contextBudget,
14404
14695
  reasoningDepth,
14405
14696
  evidenceRequirements: inferAdaptiveEvidenceRequirements(options.query, risk),
14697
+ preferredProfileStrengths,
14406
14698
  notes: [
14407
14699
  "Generated by snipara-companion as recommendation-only routing metadata.",
14408
14700
  "snipara-orchestrator must resolve the worker against the runtime catalog before execution."
@@ -14418,6 +14710,7 @@ function buildAdaptiveWorkRoutingRecommendation(options) {
14418
14710
  capabilities,
14419
14711
  forbiddenCapabilities,
14420
14712
  writeScope: changedFiles,
14713
+ structuredOutputRequired: structuredOutputRequired ? true : void 0,
14421
14714
  preferredEndpointTypes,
14422
14715
  allowedEndpointTypes,
14423
14716
  catalogLimit: options.catalogLimit,
@@ -14534,6 +14827,54 @@ function inferAdaptiveCapabilities(taskType, workerRole) {
14534
14827
  }
14535
14828
  return ["execution"];
14536
14829
  }
14830
+ function inferAdaptivePreferredProfileStrengths(taskType, query, changedFiles, workerRole) {
14831
+ const normalizedQuery = query.toLowerCase();
14832
+ const strengths = /* @__PURE__ */ new Set();
14833
+ const codeLikeScope = workerRole === "coding" || workerRole === "testing" || taskType === "coding" || taskType === "critical_code" || changedFiles.some((file) => /\.(ts|tsx|js|jsx|py|go|rs|java|kt|swift|rb|php)$/i.test(file));
14834
+ if (codeLikeScope) {
14835
+ strengths.add("code");
14836
+ }
14837
+ if (/\b(structured|json|schema|signature|serialization|contract|patch|file operations?)\b/i.test(
14838
+ normalizedQuery
14839
+ ) || codeLikeScope) {
14840
+ strengths.add("structured_output");
14841
+ }
14842
+ if (/\b(refactor|rewrite|rename|sweep|cross-file|multi-file)\b/i.test(normalizedQuery) || changedFiles.length > 8) {
14843
+ strengths.add("refactor");
14844
+ }
14845
+ if (/\b(repo|repository|codebase|explore|scan|survey|context|continuity|architecture)\b/i.test(
14846
+ normalizedQuery
14847
+ ) || changedFiles.length > 5) {
14848
+ strengths.add("long_context");
14849
+ strengths.add("repo_scan");
14850
+ }
14851
+ if (/\b(agent|workflow|checkpoint|handoff|delegate|orchestrat)\b/i.test(normalizedQuery)) {
14852
+ strengths.add("agentic_exploration");
14853
+ }
14854
+ if (taskType === "release" || taskType === "critical_code" || workerRole === "validation") {
14855
+ strengths.add("execution_safe");
14856
+ }
14857
+ return Array.from(strengths).sort();
14858
+ }
14859
+ function inferAdaptiveStructuredOutputRequirement(taskType, query, changedFiles, workerRole) {
14860
+ if (workerRole === "documentation" && taskType === "documentation") {
14861
+ return false;
14862
+ }
14863
+ if (workerRole === "coding" || workerRole === "testing") {
14864
+ return true;
14865
+ }
14866
+ if (taskType === "coding" || taskType === "critical_code" || taskType === "tests") {
14867
+ return true;
14868
+ }
14869
+ if (/\b(structured|json|schema|signature|serialization|contract|patch|file operations?)\b/i.test(
14870
+ query
14871
+ )) {
14872
+ return true;
14873
+ }
14874
+ return changedFiles.some(
14875
+ (file) => /\.(ts|tsx|js|jsx|py|go|rs|java|kt|swift|rb|php)$/i.test(file)
14876
+ );
14877
+ }
14537
14878
  function inferAdaptiveEvidenceRequirements(query, risk) {
14538
14879
  const evidence = /* @__PURE__ */ new Set();
14539
14880
  if (/\b(test|tests|pytest|unit|integration|e2e|smoke|verify|verification)\b/i.test(query)) {
@@ -14547,6 +14888,13 @@ function inferAdaptiveEvidenceRequirements(query, risk) {
14547
14888
  }
14548
14889
  return Array.from(evidence).sort();
14549
14890
  }
14891
+ function normalizeProfileStrengths(values) {
14892
+ return Array.from(
14893
+ new Set(
14894
+ (values ?? []).map((value) => stringValue8(value)?.toLowerCase()).filter((value) => Boolean(value))
14895
+ )
14896
+ ).sort();
14897
+ }
14550
14898
  function normalizeEndpointTypes(values) {
14551
14899
  return Array.from(
14552
14900
  new Set(
@@ -17950,6 +18298,7 @@ var FINAL_COMMIT_RETRY_TIMEOUT_MS = 45e3;
17950
18298
  var FINAL_COMMIT_SUMMARY_MAX_CHARS = 1200;
17951
18299
  var FINAL_COMMIT_RETRY_SUMMARY_MAX_CHARS = 600;
17952
18300
  var DEFAULT_ADAPTIVE_ROUTING_CATALOG_LIMIT = 20;
18301
+ var DEFAULT_LOCAL_ORCHESTRATOR_TIMEOUT_MS = 8e3;
17953
18302
  var ADAPTIVE_ROUTING_POLICY_RELATIVE_PATH = path21.join(".snipara", "adaptive-routing.json");
17954
18303
  var SHARED_CONTEXT_INTENT_PATTERN = /\b(standard|standards|convention|conventions|guideline|guidelines|best practice|best practices|policy|policies|compliance|compliant|security rules|team rules|style guide|playbook|checklist)\b/i;
17955
18304
  var DOCUMENT_SYNC_FORMATS = {
@@ -20491,10 +20840,21 @@ function printAdaptiveRoutingRecommendation(routing) {
20491
20840
  }
20492
20841
  if (routing.gateway) {
20493
20842
  printKeyValue(
20494
- "Hosted catalog:",
20843
+ routing.gateway.source === "local_orchestrator" ? "Local route:" : "Hosted catalog:",
20495
20844
  routing.gateway.success ? `${routing.gateway.candidateCount} candidate(s), ${routing.gateway.resolutionStatus ?? "ready"}` : "unavailable"
20496
20845
  );
20497
20846
  }
20847
+ const selectedCandidate = adaptiveRoutingSelectedCandidate(routing.resolution);
20848
+ if (selectedCandidate) {
20849
+ printKeyValue("Selected candidate:", selectedCandidate.candidateId);
20850
+ if (selectedCandidate.endpointType) {
20851
+ printKeyValue("Selected endpoint:", selectedCandidate.endpointType);
20852
+ }
20853
+ }
20854
+ const selectedWorkerEndpoint = selectedCandidate && routing.runtimeCatalog?.workerEndpoints ? routing.runtimeCatalog.workerEndpoints[selectedCandidate.candidateId] : void 0;
20855
+ if (selectedWorkerEndpoint?.model) {
20856
+ printKeyValue("Selected model:", String(selectedWorkerEndpoint.model));
20857
+ }
20498
20858
  if (routing.routingCard.reasons.length > 0) {
20499
20859
  console.log("Reasons:");
20500
20860
  for (const reason of routing.routingCard.reasons) {
@@ -20679,11 +21039,191 @@ function normalizeAdaptiveRoutingCatalog(value) {
20679
21039
  const candidates = Array.isArray(record.candidates) ? record.candidates.filter(
20680
21040
  (candidate) => Boolean(candidate) && typeof candidate === "object" && !Array.isArray(candidate)
20681
21041
  ) : [];
21042
+ const models = Array.isArray(record.models) ? record.models.map((item) => stringValue9(item)).filter((item) => Boolean(item)) : void 0;
21043
+ const workerEndpoints = isRecord12(record.workerEndpoints) ? Object.fromEntries(
21044
+ Object.entries(record.workerEndpoints).filter(
21045
+ ([key, value2]) => Boolean(stringValue9(key)) && isRecord12(value2)
21046
+ )
21047
+ ) : void 0;
21048
+ const workerProfiles = isRecord12(record.workerProfiles) ? Object.fromEntries(
21049
+ Object.entries(record.workerProfiles).filter(
21050
+ ([key, value2]) => Boolean(stringValue9(key)) && isRecord12(value2)
21051
+ )
21052
+ ) : void 0;
20682
21053
  return {
20683
21054
  version: stringValue9(record.version),
21055
+ source: stringValue9(record.source),
21056
+ provider: stringValue9(record.provider),
21057
+ baseUrl: stringValue9(record.baseUrl),
21058
+ ...models && models.length > 0 ? { models } : {},
21059
+ ...isRecord12(record.apiPaths) ? { apiPaths: record.apiPaths } : {},
21060
+ ...workerEndpoints ? { workerEndpoints } : {},
21061
+ ...workerProfiles ? { workerProfiles } : {},
20684
21062
  candidates
20685
21063
  };
20686
21064
  }
21065
+ function adaptiveRoutingSelectedCandidate(resolution) {
21066
+ if (!resolution || !isRecord12(resolution.selected)) {
21067
+ return void 0;
21068
+ }
21069
+ const candidate = isRecord12(resolution.selected.candidate) ? resolution.selected.candidate : void 0;
21070
+ const candidateId = stringValue9(candidate?.candidateId);
21071
+ if (!candidateId) {
21072
+ return void 0;
21073
+ }
21074
+ return {
21075
+ candidateId,
21076
+ workerClass: stringValue9(candidate?.workerClass),
21077
+ endpointType: stringValue9(candidate?.endpointType),
21078
+ catalogSource: stringValue9(candidate?.catalogSource)
21079
+ };
21080
+ }
21081
+ function normalizeAdaptiveRoutingResolution(value) {
21082
+ if (!isRecord12(value)) {
21083
+ return void 0;
21084
+ }
21085
+ const selected = isRecord12(value.selected) ? value.selected : void 0;
21086
+ const candidate = selected && isRecord12(selected.candidate) ? selected.candidate : void 0;
21087
+ const selectedPayload = selected && candidate ? {
21088
+ candidate,
21089
+ ...numberValue6(selected.score) !== void 0 ? { score: numberValue6(selected.score) } : {},
21090
+ ...isRecord12(selected.scoreBreakdown) ? { scoreBreakdown: selected.scoreBreakdown } : {},
21091
+ ...normalizeStringArray3(selected.reasons) ? { reasons: normalizeStringArray3(selected.reasons) } : {}
21092
+ } : void 0;
21093
+ const reasons = normalizeStringArray3(value.reasons);
21094
+ const warnings = normalizeStringArray3(value.warnings);
21095
+ return {
21096
+ status: stringValue9(value.status),
21097
+ ...selectedPayload ? { selected: selectedPayload } : {},
21098
+ ...isRecord12(value.policyDecision) ? { policyDecision: value.policyDecision } : {},
21099
+ ...numberValue6(value.evaluatedCount) !== void 0 ? { evaluatedCount: numberValue6(value.evaluatedCount) } : {},
21100
+ ...numberValue6(value.rejectedCount) !== void 0 ? { rejectedCount: numberValue6(value.rejectedCount) } : {},
21101
+ ...stringValue9(value.fallback) ? { fallback: stringValue9(value.fallback) } : {},
21102
+ ...reasons ? { reasons } : {},
21103
+ ...warnings ? { warnings } : {}
21104
+ };
21105
+ }
21106
+ function shouldResolveAdaptiveRoutingLocally(options, routing) {
21107
+ if (!routing) {
21108
+ return false;
21109
+ }
21110
+ if (!options.routeLocalWorkers && !options.routingLocalBaseUrl && !options.routingLocalModel && !options.routingLocalPreferModel && !options.routingLocalProvider) {
21111
+ return false;
21112
+ }
21113
+ const preferred = routing.requirements.preferredEndpointTypes ?? [];
21114
+ const allowed = routing.requirements.allowedEndpointTypes ?? [];
21115
+ return preferred.includes("local") || allowed.length === 0 || allowed.includes("local");
21116
+ }
21117
+ function runOrchestratorJsonCommand(args, cwd = process.cwd()) {
21118
+ const output = (0, import_node_child_process8.execFileSync)("snipara-orchestrator", args, {
21119
+ cwd,
21120
+ encoding: "utf8",
21121
+ stdio: ["ignore", "pipe", "pipe"],
21122
+ timeout: DEFAULT_LOCAL_ORCHESTRATOR_TIMEOUT_MS
21123
+ }).trim();
21124
+ return output ? parseJsonRecord(output, "snipara-orchestrator JSON output") : {};
21125
+ }
21126
+ function enrichAdaptiveRoutingWithLocalOrchestrator(routing, options, cwd = process.cwd()) {
21127
+ try {
21128
+ const catalogArgs = [
21129
+ "local-model-catalog",
21130
+ "--json",
21131
+ "--worker-role",
21132
+ routing.requirements.workerRole
21133
+ ];
21134
+ for (const writeScope of routing.requirements.writeScope ?? []) {
21135
+ catalogArgs.push("--write-scope", writeScope);
21136
+ }
21137
+ if (options.routingLocalBaseUrl) {
21138
+ catalogArgs.push("--base-url", options.routingLocalBaseUrl);
21139
+ }
21140
+ if (options.routingLocalModel) {
21141
+ catalogArgs.push("--model", options.routingLocalModel);
21142
+ } else if (options.routingLocalPreferModel) {
21143
+ catalogArgs.push("--prefer-model", options.routingLocalPreferModel);
21144
+ } else if (options.routeLocalWorkers) {
21145
+ catalogArgs.push("--all-models");
21146
+ }
21147
+ if (options.routingLocalProvider) {
21148
+ catalogArgs.push("--provider", options.routingLocalProvider);
21149
+ }
21150
+ const runtimeCatalog = normalizeAdaptiveRoutingCatalog(
21151
+ runOrchestratorJsonCommand(catalogArgs, cwd)
21152
+ );
21153
+ const routeArgs = [
21154
+ "route",
21155
+ "--dry-run",
21156
+ "--json",
21157
+ "--work-profile-json",
21158
+ JSON.stringify(routing.workProfile),
21159
+ "--requirements-json",
21160
+ JSON.stringify(routing.requirements)
21161
+ ];
21162
+ for (const candidate of runtimeCatalog.candidates) {
21163
+ routeArgs.push("--candidate-json", JSON.stringify(candidate));
21164
+ }
21165
+ const resolution = normalizeAdaptiveRoutingResolution(
21166
+ runOrchestratorJsonCommand(routeArgs, cwd)
21167
+ );
21168
+ const selectedCandidate = adaptiveRoutingSelectedCandidate(resolution);
21169
+ const selectedEndpoint = selectedCandidate && runtimeCatalog.workerEndpoints ? runtimeCatalog.workerEndpoints[selectedCandidate.candidateId] : void 0;
21170
+ const resolutionWarnings = normalizeStringArray3(resolution?.warnings) ?? [];
21171
+ const resolutionReasons = normalizeStringArray3(resolution?.reasons) ?? [];
21172
+ const approvalRequired = booleanValue2(
21173
+ isRecord12(resolution?.policyDecision) ? resolution.policyDecision.approvalRequired : void 0
21174
+ );
21175
+ const gatewayWarnings = uniqueStrings5([
21176
+ ...resolutionWarnings,
21177
+ ...selectedCandidate ? [] : ["Local orchestrator did not select a worker candidate and will fail closed."]
21178
+ ]);
21179
+ const gateway = {
21180
+ source: "local_orchestrator",
21181
+ success: stringValue9(resolution?.status) === "resolved",
21182
+ resolutionStatus: stringValue9(resolution?.status),
21183
+ candidateCount: runtimeCatalog.candidates.length,
21184
+ fallback: stringValue9(resolution?.fallback) ?? routing.requirements.fallback,
21185
+ warnings: gatewayWarnings
21186
+ };
21187
+ return {
21188
+ ...routing,
21189
+ gateway,
21190
+ runtimeCatalog,
21191
+ ...resolution ? { resolution } : {},
21192
+ routingCard: {
21193
+ ...routing.routingCard,
21194
+ ...selectedCandidate?.workerClass ? { recommendedWorkerClass: selectedCandidate.workerClass } : {},
21195
+ ...approvalRequired !== void 0 ? { humanApprovalRequired: approvalRequired } : {},
21196
+ reasons: uniqueStrings5([
21197
+ ...routing.routingCard.reasons,
21198
+ ...resolutionReasons,
21199
+ ...selectedCandidate ? [
21200
+ `local orchestrator resolved worker candidate ${selectedCandidate.candidateId}`,
21201
+ ...selectedCandidate.endpointType ? [`selected worker endpoint is ${selectedCandidate.endpointType}`] : [],
21202
+ ...stringValue9(selectedEndpoint?.model) ? [`selected local model ${String(selectedEndpoint?.model)}`] : []
21203
+ ] : ["local orchestrator could not resolve a concrete worker candidate"]
21204
+ ]),
21205
+ warnings: uniqueStrings5([...routing.routingCard.warnings, ...gatewayWarnings])
21206
+ }
21207
+ };
21208
+ } catch (error) {
21209
+ const warning = `Local orchestrator routing unavailable; keeping current routing metadata (${toPreview(error)}).`;
21210
+ return {
21211
+ ...routing,
21212
+ gateway: {
21213
+ source: "local_orchestrator",
21214
+ success: false,
21215
+ resolutionStatus: "unavailable",
21216
+ candidateCount: 0,
21217
+ fallback: routing.requirements.fallback,
21218
+ warnings: [warning]
21219
+ },
21220
+ routingCard: {
21221
+ ...routing.routingCard,
21222
+ warnings: uniqueStrings5([...routing.routingCard.warnings, warning])
21223
+ }
21224
+ };
21225
+ }
21226
+ }
20687
21227
  function printUploadResult(path23, result) {
20688
21228
  printKeyValue("Uploaded:", path23);
20689
21229
  printCompactObject(result, ["message", "document_id", "documentId", "version", "status"]);
@@ -22170,7 +22710,8 @@ async function workflowRunCommand(options) {
22170
22710
  hostedConfigured
22171
22711
  );
22172
22712
  const adaptiveRoutingDryRun = adaptiveRoutingIntent.shouldBuild ? buildWorkflowAdaptiveRouting(options, adaptiveRoutingPolicy, adaptiveRoutingIntent.warnings) : null;
22173
- const adaptiveRouting = adaptiveRoutingDryRun && adaptiveRoutingIntent.shouldUseHostedCatalog && client ? await enrichAdaptiveRoutingWithHostedCatalog(client, adaptiveRoutingDryRun) : adaptiveRoutingDryRun;
22713
+ const adaptiveRoutingWithCatalog = adaptiveRoutingDryRun && adaptiveRoutingIntent.shouldUseHostedCatalog && client ? await enrichAdaptiveRoutingWithHostedCatalog(client, adaptiveRoutingDryRun) : adaptiveRoutingDryRun;
22714
+ const adaptiveRouting = shouldResolveAdaptiveRoutingLocally(options, adaptiveRoutingWithCatalog) ? enrichAdaptiveRoutingWithLocalOrchestrator(adaptiveRoutingWithCatalog, options) : adaptiveRoutingWithCatalog;
22174
22715
  const orchestratorRecommendation = getOrchestratorRecommendation(options.query, options.mode, {
22175
22716
  policyAutoRoute: options.autoRouteOrchestrator,
22176
22717
  policySource: options.orchestratorPolicySource,
@@ -22393,7 +22934,7 @@ async function workflowRunCommand(options) {
22393
22934
  }
22394
22935
  function shouldBuildAdaptiveRouting(options) {
22395
22936
  return Boolean(
22396
- options.adaptiveRoutingDryRun || options.routeLocalWorkers || options.routingWorkerRole || options.routingPreferredEndpoints?.length || options.routingAllowedEndpoints?.length || options.plannerRetainsReasoning
22937
+ options.adaptiveRoutingDryRun || options.routeLocalWorkers || options.routingWorkerRole || options.routingPreferredEndpoints?.length || options.routingAllowedEndpoints?.length || options.routingLocalBaseUrl || options.routingLocalModel || options.routingLocalPreferModel || options.routingLocalProvider || options.plannerRetainsReasoning
22397
22938
  );
22398
22939
  }
22399
22940
  function buildWorkflowAdaptiveRouting(options, policy = null, intentWarnings = []) {
@@ -24508,6 +25049,12 @@ workflow.command("run").description("Run a LITE/STANDARD/FULL/orchestrate workfl
24508
25049
  collectOption,
24509
25050
  []
24510
25051
  ).option(
25052
+ "--routing-local-base-url <url>",
25053
+ "Local OpenAI-compatible runtime base URL for explicit worker routing"
25054
+ ).option("--routing-local-model <id>", "Explicit local model id for worker routing").option(
25055
+ "--routing-local-prefer-model <text>",
25056
+ "Prefer a local /v1/models entry containing this text during worker routing"
25057
+ ).option("--routing-local-provider <provider>", "Provider label for local worker routing").option(
24511
25058
  "--planner-retains-reasoning",
24512
25059
  "Mark the main planner as retaining deep reasoning while the worker executes scoped work"
24513
25060
  ).option("--write-plan-file <file>", "Write the generated FULL-mode plan as workflow JSON").option(
@@ -24530,6 +25077,10 @@ workflow.command("run").description("Run a LITE/STANDARD/FULL/orchestrate workfl
24530
25077
  routingWorkerRole: options.routingWorkerRole,
24531
25078
  routingPreferredEndpoints: options.routingPreferredEndpoint,
24532
25079
  routingAllowedEndpoints: options.routingAllowedEndpoint,
25080
+ routingLocalBaseUrl: options.routingLocalBaseUrl,
25081
+ routingLocalModel: options.routingLocalModel,
25082
+ routingLocalPreferModel: options.routingLocalPreferModel,
25083
+ routingLocalProvider: options.routingLocalProvider,
24533
25084
  plannerRetainsReasoning: options.plannerRetainsReasoning ? true : void 0,
24534
25085
  writePlanFile: options.writePlanFile,
24535
25086
  startWorkflowFromPlan: Boolean(options.startWorkflowFromPlan),
@@ -25326,6 +25877,8 @@ if (require.main === module) {
25326
25877
  AutomationInstallConflictError,
25327
25878
  AutomationUnsupportedHookBundleError,
25328
25879
  COLLABORATION_STATE_RELATIVE_PATH,
25880
+ ENGINEERING_LEAD_EXECUTION_RECEIPT_STAGES,
25881
+ ENGINEERING_LEAD_EXECUTION_RECEIPT_STATUSES,
25329
25882
  ENGINEERING_LEAD_POSTURES,
25330
25883
  ENGINEERING_LEAD_ROUTING_MODES,
25331
25884
  ENGINEERING_LEAD_STATUSES,
@@ -273,6 +273,62 @@ Project credentials stay server-side behind the hosted gateway; local endpoints
273
273
  such as Ollama, LM Studio, AnythingLLM, or other OpenAI-compatible servers must
274
274
  be reachable from the worker execution environment.
275
275
 
276
+ For a local LM Studio or OpenAI-compatible worker, use Companion to emit the
277
+ handoff, then let `snipara-orchestrator` resolve that handoff against an explicit
278
+ local runtime catalog. In the Codex workflow, Codex remains the chief architect,
279
+ lead orchestrator, and quality verifier; Qwen and Devstral are bounded local
280
+ worker candidates whose outputs still need Codex review and proof gates.
281
+
282
+ Use Qwen for reflection, architecture, and documentation:
283
+
284
+ ```bash
285
+ snipara-companion workflow run \
286
+ --mode full \
287
+ --adaptive-routing-dry-run \
288
+ --route-local-workers \
289
+ --routing-worker-role documentation \
290
+ --routing-preferred-endpoint local \
291
+ --routing-allowed-endpoint local \
292
+ --planner-retains-reasoning \
293
+ "Update a scoped docs surface"
294
+
295
+ snipara-orchestrator local-model-catalog \
296
+ --base-url http://127.0.0.1:1234 \
297
+ --model qwen/qwen3-30b-a3b-2507 \
298
+ --worker-role documentation \
299
+ --capability documentation \
300
+ --capability architecture_review \
301
+ --capability planning \
302
+ --json > .snipara/local-qwen-docs-runtime-catalog.json
303
+
304
+ snipara-orchestrator route --dry-run \
305
+ --work-profile-json '{"taskType":"documentation","risk":"low","scope":["docs/**"],"contextBudget":"small","reasoningDepth":"low"}' \
306
+ --requirements-json '{"workerRole":"documentation","plannerRetainsReasoning":true,"preferredEndpointTypes":["local"],"allowedEndpointTypes":["local"],"writeScope":["docs/**"],"capabilities":["documentation"]}' \
307
+ --catalog-file .snipara/local-qwen-docs-runtime-catalog.json \
308
+ --json
309
+ ```
310
+
311
+ Use Devstral for development and refactoring work:
312
+
313
+ ```bash
314
+ snipara-orchestrator local-model-catalog \
315
+ --base-url http://127.0.0.1:1234 \
316
+ --prefer-model devstral \
317
+ --worker-role coding \
318
+ --capability code_edit \
319
+ --capability refactor \
320
+ --json > .snipara/local-devstral-runtime-catalog.json
321
+ ```
322
+
323
+ The local catalog records the OpenAI-compatible routes exposed by LM Studio:
324
+ `GET /v1/models`, `POST /v1/responses`, `POST /v1/chat/completions`,
325
+ `POST /v1/completions`, and `POST /v1/embeddings`. `--prefer-model devstral`
326
+ selects the first `/v1/models` id containing `devstral`; use `--model <id>` to
327
+ pin Qwen or any other exact local model id. This makes Qwen, Devstral, or
328
+ another local model routable through the Companion/Orchestrator contract while
329
+ keeping execution fail-closed: the selected candidate is a receipt-backed worker
330
+ target, not an automatically launched process.
331
+
276
332
  For the open package without Snipara SaaS, add a local policy file:
277
333
 
278
334
  ```json
@@ -313,6 +369,12 @@ Health: posture, score, routing mode, bounded worker contract, supervised work
313
369
  packages, supervision/replan status, proof gates, candidate Project Brain
314
370
  updates, `workersSpawned: 0`, and `main_agent` fallback.
315
371
 
372
+ Engineering Lead Execution Receipts V1 adds `executionReceipts` to that plan.
373
+ Each receipt records the expected handoff, claim, approval, proof, outcome, and
374
+ Project Brain update stages for a work package, plus missing requirements and
375
+ next actions. Unknown future receipt enum values fail closed with
376
+ `companion_dropped_unknown_execution_receipt_*` reason codes.
377
+
316
378
  Use `--from-cockpit <file>` or `--from-plan <file>` when Project Health has
317
379
  exported a cockpit/lead-plan JSON artifact and Companion only needs to normalize
318
380
  it into Markdown or JSON for handoff. Add `--reconcile` to compare the imported
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snipara-companion",
3
- "version": "2.2.0",
3
+ "version": "2.3.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": {