snipara-companion 3.2.14 → 3.2.15

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
@@ -77,6 +77,7 @@ These commands are useful without hosted Snipara:
77
77
  | `workflow start` / `phase-start` / `phase-commit` / `resume` | Agent continuity that survives compaction |
78
78
  | `workflow timeline` / `workflow session` | Append-only local activity log and Session Snapshot V0 |
79
79
  | `workflow decisions` / `workflow decide` | Local human decision requests and response receipts |
80
+ | `run --emit-policy-decisions` | Project Policy review requests in the agent workflow |
80
81
  | `workflow producer-triage` | Ask for human review of unreviewed Producer Loop samples |
81
82
  | `workflow producer-report` | Local Producer Loop adoption and calibration report |
82
83
  | `workflow producer-review` | Mark local Producer Loop samples reviewed or rejected |
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { ProjectIntentDetectionResult, ProjectPolicyDecision, ProjectRealityCheckResult, ProjectIntelligenceEngineeringLeadPlanSummary, ProjectPolicyRule, OutcomeIntelligenceCalibration, ControlledWorkerExecutionMode, ControlledWorkerExecutionReceipt } from '@snipara/project-intelligence-contracts';
2
+ import { ProjectIntentDetectionResult, ProjectPolicyDecision, ProjectRealityCheckResult, ProjectIntelligenceEngineeringLeadPlanSummary, ProjectPolicyRule, DecisionRequest, OutcomeIntelligenceCalibration, ControlledWorkerExecutionMode, ControlledWorkerExecutionReceipt } from '@snipara/project-intelligence-contracts';
3
3
 
4
4
  declare function resolveQueryFromToolInput(toolInput?: string, tool?: string): string | null;
5
5
 
@@ -2073,6 +2073,14 @@ interface RealityCheckCommandOptions {
2073
2073
  declare function buildLocalProjectRealityCheck(options: RealityCheckCommandOptions): ProjectRealityCheckResult;
2074
2074
  declare function realityCheckCommand(options: RealityCheckCommandOptions): Promise<void>;
2075
2075
 
2076
+ interface DecisionRequestWriteResult {
2077
+ status: "written" | "duplicate_pending" | "duplicate_resolved";
2078
+ requestId: string;
2079
+ fingerprint: string;
2080
+ path?: string;
2081
+ relativePath?: string;
2082
+ }
2083
+
2076
2084
  interface MemoryHealthCommandOptions {
2077
2085
  scope?: MemoryScope;
2078
2086
  includeInactive?: boolean;
@@ -2463,6 +2471,7 @@ interface ProjectRunCommandOptions {
2463
2471
  servedJudgmentId?: string;
2464
2472
  skipAdvisorReceipts?: boolean;
2465
2473
  outcomeReceiptFiles?: string[];
2474
+ emitPolicyDecisions?: boolean;
2466
2475
  json?: boolean;
2467
2476
  }
2468
2477
  interface ProjectRunGuardResult {
@@ -2509,11 +2518,20 @@ interface ProjectIntelligenceRunResult {
2509
2518
  guard?: ProjectRunGuardResult;
2510
2519
  packageReview?: ProjectRunPackageReview;
2511
2520
  policyGates: ProjectPolicyGatesResult;
2521
+ policyDecisionRequests?: ProjectRunPolicyDecisionRequests;
2512
2522
  advisorReceiptCapture?: ProjectRunAdvisorReceiptCapture;
2513
2523
  outcomeCalibration?: OutcomeIntelligenceCalibration;
2514
2524
  judgmentCard: ProjectIntelligenceJudgmentCard;
2515
2525
  suggestedCommands: string[];
2516
2526
  }
2527
+ interface ProjectRunPolicyDecisionRequests {
2528
+ version: "project-intelligence.policy-decision-requests.v1";
2529
+ emitted: boolean;
2530
+ requestCount: number;
2531
+ requests: DecisionRequest[];
2532
+ writes: DecisionRequestWriteResult[];
2533
+ caveats: string[];
2534
+ }
2517
2535
  declare function buildProjectIntelligenceRun(options: ProjectRunCommandOptions): Promise<ProjectIntelligenceRunResult>;
2518
2536
  declare function projectIntelligenceRunCommand(options: ProjectRunCommandOptions): Promise<void>;
2519
2537
 
package/dist/index.js CHANGED
@@ -30575,6 +30575,9 @@ var ADVISOR_RECEIPT_WRITE_LIMIT = 6;
30575
30575
  function normalizeStringList6(values) {
30576
30576
  return [...new Set((values ?? []).map((value) => value.trim()).filter(Boolean))];
30577
30577
  }
30578
+ function uniqueStrings18(values) {
30579
+ return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
30580
+ }
30578
30581
  function isRecord17(value) {
30579
30582
  return typeof value === "object" && value !== null && !Array.isArray(value);
30580
30583
  }
@@ -30832,6 +30835,73 @@ function verificationExecutedFromEvidence(evidence) {
30832
30835
  (item) => item.command ? `${item.label}: ${item.command} (${item.status})` : `${item.label}: ${item.status}`
30833
30836
  );
30834
30837
  }
30838
+ function buildPolicyDecisionRequest(args) {
30839
+ const decision = args.run.policyGates.projectPolicyDecision;
30840
+ if (!decision || decision.verdict === "allow") return void 0;
30841
+ const changedFiles = args.run.brief.changedFiles.slice(0, 24);
30842
+ const matchedRules = decision.matchedRules.slice(0, 8);
30843
+ const options = decision.verdict === "block" ? ["respect_block", "request_exception", "mark_policy_stale"] : ["approve_once", "require_changes", "mark_policy_stale", "keep_advisory"];
30844
+ const recommendation = decision.verdict === "block" ? "respect_block" : "approve_once";
30845
+ return buildDecisionRequest({
30846
+ producer: {
30847
+ kind: "project_policy_review",
30848
+ command: "run --emit-policy-decisions",
30849
+ sourceRef: decision.receipt.receiptId
30850
+ },
30851
+ decision: `project_policy_${decision.verdict}`,
30852
+ question: decision.verdict === "block" ? "Project Policy blocked this action. Should the agent stop, request an exception, or mark the policy stale?" : "Project Policy requires human review. May the agent proceed once, change plan, or mark the policy stale?",
30853
+ evidence: {
30854
+ summary: `Project Policy verdict ${decision.verdict} for task '${args.run.brief.task ?? "unspecified"}'. Receipt ${decision.receipt.receiptId}.`,
30855
+ refs: uniqueStrings18([decision.receipt.receiptId, ...decision.receipt.ruleRefs]),
30856
+ items: matchedRules.map((rule) => ({
30857
+ ref: rule.source.ref,
30858
+ title: rule.title,
30859
+ summary: rule.requirement,
30860
+ kind: rule.source.kind,
30861
+ status: rule.strength,
30862
+ metadata: {
30863
+ ruleId: rule.id,
30864
+ scope: rule.scope,
30865
+ confidence: rule.confidence,
30866
+ reviewStatus: rule.source.reviewStatus ?? null
30867
+ }
30868
+ })),
30869
+ reasonCodes: uniqueStrings18(["project_policy_review", ...decision.reasonCodes]),
30870
+ files: changedFiles,
30871
+ applyPath: "manual_context_review",
30872
+ applyCommand: "Resolve with `snipara-companion workflow decide <request-id> --choose <option> --reviewer <name>`; if policy is stale, update or invalidate the cited decision/policy before rerunning `snipara-companion run`."
30873
+ },
30874
+ options,
30875
+ recommendation,
30876
+ rationale: "Project Policy decisions stay agent-first: the agent asks for explicit human governance and records a response receipt; no dashboard or silent policy mutation is required.",
30877
+ blocking: true,
30878
+ fingerprintParts: [
30879
+ "project_policy_review_v1",
30880
+ decision.receipt.receiptId,
30881
+ decision.verdict,
30882
+ decision.receipt.ruleRefs,
30883
+ changedFiles
30884
+ ]
30885
+ });
30886
+ }
30887
+ function emitPolicyDecisionRequests(run) {
30888
+ const requests = [buildPolicyDecisionRequest({ run })].filter(
30889
+ (request) => Boolean(request)
30890
+ );
30891
+ const writes = requests.map((request) => writeDecisionRequest(request));
30892
+ return {
30893
+ version: "project-intelligence.policy-decision-requests.v1",
30894
+ emitted: true,
30895
+ requestCount: requests.length,
30896
+ requests,
30897
+ writes,
30898
+ caveats: [
30899
+ "Policy decision requests never apply policy changes automatically.",
30900
+ "Resolve them with workflow decide so the human choice is recorded as a local response receipt.",
30901
+ "Marking a policy stale is a governance signal; the cited memory or policy still needs explicit update or invalidation."
30902
+ ]
30903
+ };
30904
+ }
30835
30905
  async function recordFirstPartyAdvisorReceipts(args) {
30836
30906
  const allRecommendations = args.judgmentCard.advisorRecommendations;
30837
30907
  if (args.options.skipAdvisorReceipts) {
@@ -31123,7 +31193,7 @@ async function buildProjectIntelligenceRun(options) {
31123
31193
  ...!options.skipPackageReview && packageReview?.status !== "ok" ? [packageReviewCommand3()] : []
31124
31194
  ] : []
31125
31195
  ];
31126
- return {
31196
+ const result = {
31127
31197
  version: "project-intelligence.production-run.v1",
31128
31198
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
31129
31199
  release: Boolean(options.release),
@@ -31136,6 +31206,10 @@ async function buildProjectIntelligenceRun(options) {
31136
31206
  judgmentCard,
31137
31207
  suggestedCommands: [...new Set(suggestedCommands3)]
31138
31208
  };
31209
+ if (options.emitPolicyDecisions) {
31210
+ result.policyDecisionRequests = emitPolicyDecisionRequests(result);
31211
+ }
31212
+ return result;
31139
31213
  }
31140
31214
  async function projectIntelligenceRunCommand(options) {
31141
31215
  const result = await buildProjectIntelligenceRun(options);
@@ -33304,6 +33378,9 @@ program.command("lead-plan").description("Create a fail-closed Companion Enginee
33304
33378
  program.command("run").description("Run the production Project Intelligence judgment flow for a task or release").option("--task <task>", "Current task or change summary").option("--branch <branch>", "Branch to scope continuity signals").option("--changed-files <changedFiles...>", "Changed files to analyze").option("--recent-files <recentFiles...>", "Recently touched files for continuity lookup").option("--diff-summary <diffSummary>", "Natural-language summary for code impact").option("--max-tokens <number>", "Resume context token budget", "4000").option("--release", "Run release-oriented guard and package surface review").option("--skip-impact", "Do not run companion code impact").option("--skip-memory-health", "Do not call snipara_memory_health").option("--skip-guard", "Skip collaboration guard during release runs").option("--skip-package-review", "Skip npm package surface review").option("--served-judgment-id <id>", "Served judgment id to use for first-party advisor receipts").option("--skip-advisor-receipts", "Skip first-party advisor influence receipt capture").option(
33305
33379
  "--outcome-receipts <files...>",
33306
33380
  "Outcome Intelligence V0 receipt JSON files for local calibration"
33381
+ ).option(
33382
+ "--emit-policy-decisions",
33383
+ "Write local Decision Requests for Project Policy review/block findings"
33307
33384
  ).option("--json", "Print raw JSON").action(async (options) => {
33308
33385
  await projectIntelligenceRunCommand({
33309
33386
  task: options.task,
@@ -33320,6 +33397,7 @@ program.command("run").description("Run the production Project Intelligence judg
33320
33397
  servedJudgmentId: options.servedJudgmentId,
33321
33398
  skipAdvisorReceipts: Boolean(options.skipAdvisorReceipts),
33322
33399
  outcomeReceiptFiles: options.outcomeReceipts,
33400
+ emitPolicyDecisions: Boolean(options.emitPolicyDecisions),
33323
33401
  json: Boolean(options.json)
33324
33402
  });
33325
33403
  });
@@ -288,6 +288,13 @@ snipara-companion workflow resume --include-session-context
288
288
  path declared. Repeated resolved receipts with the same human choice and
289
289
  rationale can emit a review-only policy suggestion decision request; the
290
290
  suggestion still has a manual apply path and is never auto-applied.
291
+ - `run --emit-policy-decisions` keeps Project Policy administration agent-first:
292
+ when reviewed project policy evidence produces a `require_review` or `block`
293
+ verdict, Companion writes a local `project_policy_review` Decision Request.
294
+ The human resolves it with `workflow decide`; choices such as approving once,
295
+ requiring changes, respecting a block, requesting an exception, or marking
296
+ policy stale are recorded as receipts. No policy is edited or invalidated
297
+ automatically.
291
298
  - `memory reviews --scope project --emit-decisions` reads hosted memory review
292
299
  queue, clean-candidate, and duplicate-candidate surfaces, summarizes each item,
293
300
  and writes local Decision Request artifacts without mutating hosted memory.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snipara-companion",
3
- "version": "3.2.14",
3
+ "version": "3.2.15",
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": {