snipara-companion 3.2.9 → 3.2.10
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/dist/index.d.ts +8 -2
- package/dist/index.js +376 -65
- package/docs/FULL_REFERENCE.md +8 -2
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { ProjectIntentDetectionResult, ProjectRealityCheckResult, ProjectIntelligenceEngineeringLeadPlanSummary } from '@snipara/project-intelligence-contracts';
|
|
2
|
+
import { ProjectIntentDetectionResult, ProjectPolicyDecision, ProjectRealityCheckResult, ProjectIntelligenceEngineeringLeadPlanSummary, ProjectPolicyRule } from '@snipara/project-intelligence-contracts';
|
|
3
3
|
|
|
4
4
|
declare function resolveQueryFromToolInput(toolInput?: string, tool?: string): string | null;
|
|
5
5
|
|
|
@@ -2030,6 +2030,7 @@ interface ProjectIntelligenceBrief {
|
|
|
2030
2030
|
codeImpact?: Record<string, unknown>;
|
|
2031
2031
|
codeImpactSourceSelection?: CodeGraphSourceSelection;
|
|
2032
2032
|
localSessionSnapshot?: SessionSnapshot;
|
|
2033
|
+
projectPolicyDecision?: ProjectPolicyDecision;
|
|
2033
2034
|
verificationPlan?: VerificationPlan;
|
|
2034
2035
|
judgmentCard?: ProjectIntelligenceJudgmentCard;
|
|
2035
2036
|
errors: Array<{
|
|
@@ -2375,7 +2376,7 @@ declare function formatCompanionEngineeringLeadPlanReport(report: CompanionEngin
|
|
|
2375
2376
|
declare function leadPlanCommand(options: LeadPlanCommandOptions): Promise<void>;
|
|
2376
2377
|
|
|
2377
2378
|
type ProjectPolicyGateSeverity = "advisory" | "required_action" | "block";
|
|
2378
|
-
type ProjectPolicyGateSurface = "release" | "schema" | "auth" | "billing" | "deploy" | "package_surface";
|
|
2379
|
+
type ProjectPolicyGateSurface = "release" | "schema" | "auth" | "billing" | "deploy" | "package_surface" | "project_policy";
|
|
2379
2380
|
type ProjectPolicyGateSampleMode = "not_applicable" | "structural" | "explicit_contract" | "sample_gated";
|
|
2380
2381
|
interface ProjectPolicyGateSampleGate {
|
|
2381
2382
|
mode: ProjectPolicyGateSampleMode;
|
|
@@ -2417,6 +2418,7 @@ interface ProjectPolicyGatesResult {
|
|
|
2417
2418
|
release: boolean;
|
|
2418
2419
|
summary: ProjectPolicyGatesSummary;
|
|
2419
2420
|
gates: ProjectPolicyGateDecision[];
|
|
2421
|
+
projectPolicyDecision?: ProjectPolicyDecision;
|
|
2420
2422
|
suggestedCommands: string[];
|
|
2421
2423
|
}
|
|
2422
2424
|
interface EvaluateProjectPolicyGatesInput {
|
|
@@ -2438,6 +2440,10 @@ interface EvaluateProjectPolicyGatesInput {
|
|
|
2438
2440
|
command?: string;
|
|
2439
2441
|
};
|
|
2440
2442
|
judgmentCard?: ProjectIntelligenceJudgmentCard;
|
|
2443
|
+
projectPolicy?: {
|
|
2444
|
+
rules?: ProjectPolicyRule[];
|
|
2445
|
+
decision?: ProjectPolicyDecision;
|
|
2446
|
+
};
|
|
2441
2447
|
}
|
|
2442
2448
|
declare function evaluateProjectPolicyGates(input: EvaluateProjectPolicyGatesInput): ProjectPolicyGatesResult;
|
|
2443
2449
|
declare function formatPolicyGateDecision(gateDecision: ProjectPolicyGateDecision): string[];
|
package/dist/index.js
CHANGED
|
@@ -10634,6 +10634,151 @@ function buildIntentDetectionFromTimeline(events) {
|
|
|
10634
10634
|
};
|
|
10635
10635
|
}
|
|
10636
10636
|
|
|
10637
|
+
// ../project-intelligence-contracts/src/project-policy.ts
|
|
10638
|
+
var PROJECT_POLICY_DECISION_VERSION = "snipara.project_policy.decision.v0";
|
|
10639
|
+
var PROJECT_POLICY_RECEIPT_VERSION = "snipara.project_policy.receipt.v0";
|
|
10640
|
+
var VERDICT_RANK = {
|
|
10641
|
+
allow: 0,
|
|
10642
|
+
warn: 1,
|
|
10643
|
+
require_review: 2,
|
|
10644
|
+
block: 3
|
|
10645
|
+
};
|
|
10646
|
+
function evaluateProjectPolicyDecision(input) {
|
|
10647
|
+
const generatedAt = isoTimestamp2(input.now);
|
|
10648
|
+
const actionText = normalizeText2(
|
|
10649
|
+
[
|
|
10650
|
+
input.action.summary,
|
|
10651
|
+
input.action.surface,
|
|
10652
|
+
...input.action.changedFiles ?? [],
|
|
10653
|
+
...input.action.commands ?? [],
|
|
10654
|
+
metadataToText(input.action.metadata)
|
|
10655
|
+
].filter((item) => Boolean(item))
|
|
10656
|
+
);
|
|
10657
|
+
const matchedRules = normalizeRules(input.rules).filter(
|
|
10658
|
+
(rule) => ruleMatchesAction(rule, actionText, input.action)
|
|
10659
|
+
);
|
|
10660
|
+
const verdict = matchedRules.reduce(
|
|
10661
|
+
(current, rule) => strongerVerdict(current, verdictForRule(rule, actionText)),
|
|
10662
|
+
"allow"
|
|
10663
|
+
);
|
|
10664
|
+
const confidence = matchedRules.length === 0 ? 1 : Math.max(...matchedRules.map((rule) => normalizeConfidence(rule.confidence)));
|
|
10665
|
+
const reasonCodes = buildReasonCodes(matchedRules, verdict);
|
|
10666
|
+
const requiredActions = uniqueStrings7(
|
|
10667
|
+
matchedRules.flatMap((rule) => rule.requiredActions ?? [rule.requirement])
|
|
10668
|
+
);
|
|
10669
|
+
const warnings = matchedRules.filter((rule) => verdictForRule(rule, actionText) === "warn").map((rule) => rule.requirement);
|
|
10670
|
+
const actionFingerprint = hashDecisionJsonValue(input.action);
|
|
10671
|
+
const receipt = {
|
|
10672
|
+
version: PROJECT_POLICY_RECEIPT_VERSION,
|
|
10673
|
+
receiptId: buildReceiptId(actionFingerprint, matchedRules),
|
|
10674
|
+
generatedAt,
|
|
10675
|
+
verdict,
|
|
10676
|
+
actionFingerprint,
|
|
10677
|
+
ruleRefs: matchedRules.map((rule) => rule.source.ref),
|
|
10678
|
+
confidence,
|
|
10679
|
+
reasonCodes,
|
|
10680
|
+
overrideAllowed: verdict !== "block",
|
|
10681
|
+
overrideRequiresReason: verdict !== "allow"
|
|
10682
|
+
};
|
|
10683
|
+
return {
|
|
10684
|
+
version: PROJECT_POLICY_DECISION_VERSION,
|
|
10685
|
+
generatedAt,
|
|
10686
|
+
verdict,
|
|
10687
|
+
confidence,
|
|
10688
|
+
matchedRules,
|
|
10689
|
+
reasonCodes,
|
|
10690
|
+
requiredActions,
|
|
10691
|
+
warnings,
|
|
10692
|
+
receipt
|
|
10693
|
+
};
|
|
10694
|
+
}
|
|
10695
|
+
function projectPolicyVerdictToGateSeverity(verdict) {
|
|
10696
|
+
if (verdict === "block") return "block";
|
|
10697
|
+
if (verdict === "require_review") return "required_action";
|
|
10698
|
+
return "advisory";
|
|
10699
|
+
}
|
|
10700
|
+
function normalizeRules(rules) {
|
|
10701
|
+
return rules.filter(
|
|
10702
|
+
(rule) => rule.id.trim() && rule.title.trim() && rule.requirement.trim() && rule.source.reviewStatus !== "rejected" && normalizeConfidence(rule.confidence) >= 0.5
|
|
10703
|
+
);
|
|
10704
|
+
}
|
|
10705
|
+
function ruleMatchesAction(rule, actionText, action) {
|
|
10706
|
+
if (action.surface && rule.scope !== "custom" && action.surface !== rule.scope) {
|
|
10707
|
+
return false;
|
|
10708
|
+
}
|
|
10709
|
+
const anchors = uniqueStrings7([
|
|
10710
|
+
rule.scope,
|
|
10711
|
+
...rule.anchors,
|
|
10712
|
+
...rule.forbiddenActions ?? [],
|
|
10713
|
+
...rule.requiredActions ?? []
|
|
10714
|
+
]);
|
|
10715
|
+
return anchors.some((anchor) => actionText.includes(normalizeText2(anchor)));
|
|
10716
|
+
}
|
|
10717
|
+
function verdictForRule(rule, actionText) {
|
|
10718
|
+
const forbidden = (rule.forbiddenActions ?? []).some(
|
|
10719
|
+
(item) => actionText.includes(normalizeText2(item))
|
|
10720
|
+
);
|
|
10721
|
+
if (rule.strength === "blocking" && forbidden && normalizeConfidence(rule.confidence) >= 0.8) {
|
|
10722
|
+
return "block";
|
|
10723
|
+
}
|
|
10724
|
+
if (rule.strength === "blocking" || rule.strength === "review_required") {
|
|
10725
|
+
return "require_review";
|
|
10726
|
+
}
|
|
10727
|
+
return "warn";
|
|
10728
|
+
}
|
|
10729
|
+
function strongerVerdict(left, right) {
|
|
10730
|
+
return VERDICT_RANK[right] > VERDICT_RANK[left] ? right : left;
|
|
10731
|
+
}
|
|
10732
|
+
function buildReasonCodes(rules, verdict) {
|
|
10733
|
+
if (rules.length === 0) {
|
|
10734
|
+
return ["project_policy_no_match"];
|
|
10735
|
+
}
|
|
10736
|
+
return uniqueStrings7([
|
|
10737
|
+
`project_policy_${verdict}`,
|
|
10738
|
+
...rules.map((rule) => `project_policy_${rule.scope}`),
|
|
10739
|
+
...rules.map((rule) => `project_policy_${rule.strength}`)
|
|
10740
|
+
]);
|
|
10741
|
+
}
|
|
10742
|
+
function buildReceiptId(actionFingerprint, rules) {
|
|
10743
|
+
const hash = hashDecisionJsonValue({
|
|
10744
|
+
actionFingerprint,
|
|
10745
|
+
rules: rules.map((rule) => [rule.id, rule.source.ref])
|
|
10746
|
+
}).replace(/^sha256:/, "");
|
|
10747
|
+
return `project-policy-${hash.slice(0, 16)}`;
|
|
10748
|
+
}
|
|
10749
|
+
function isoTimestamp2(value) {
|
|
10750
|
+
if (value instanceof Date) return value.toISOString();
|
|
10751
|
+
if (typeof value === "string" && value.trim()) return new Date(value).toISOString();
|
|
10752
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
10753
|
+
}
|
|
10754
|
+
function normalizeConfidence(value) {
|
|
10755
|
+
if (!Number.isFinite(value)) return 0;
|
|
10756
|
+
return Math.max(0, Math.min(1, value));
|
|
10757
|
+
}
|
|
10758
|
+
function normalizeText2(value) {
|
|
10759
|
+
const text = Array.isArray(value) ? value.filter(Boolean).join("\n") : value ?? "";
|
|
10760
|
+
return text.toLowerCase().replace(/\s+/g, " ").trim();
|
|
10761
|
+
}
|
|
10762
|
+
function uniqueStrings7(values) {
|
|
10763
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10764
|
+
const result = [];
|
|
10765
|
+
for (const value of values) {
|
|
10766
|
+
const normalized = value.trim();
|
|
10767
|
+
if (!normalized || seen.has(normalized)) continue;
|
|
10768
|
+
seen.add(normalized);
|
|
10769
|
+
result.push(normalized);
|
|
10770
|
+
}
|
|
10771
|
+
return result;
|
|
10772
|
+
}
|
|
10773
|
+
function metadataToText(metadata) {
|
|
10774
|
+
if (!metadata) return "";
|
|
10775
|
+
try {
|
|
10776
|
+
return JSON.stringify(metadata).slice(0, 12e3);
|
|
10777
|
+
} catch {
|
|
10778
|
+
return "";
|
|
10779
|
+
}
|
|
10780
|
+
}
|
|
10781
|
+
|
|
10637
10782
|
// src/commands/decision-requests.ts
|
|
10638
10783
|
var fs12 = __toESM(require("fs"));
|
|
10639
10784
|
var path11 = __toESM(require("path"));
|
|
@@ -10964,7 +11109,7 @@ function memoryEvidenceItem(value, options) {
|
|
|
10964
11109
|
summary: options.summary,
|
|
10965
11110
|
kind: options.kind,
|
|
10966
11111
|
status: options.status,
|
|
10967
|
-
files:
|
|
11112
|
+
files: uniqueStrings8(evidenceRefs),
|
|
10968
11113
|
metadata: compactObject({
|
|
10969
11114
|
source: options.source,
|
|
10970
11115
|
bucket: options.bucket,
|
|
@@ -11005,7 +11150,7 @@ function reviewQueueItems(result) {
|
|
|
11005
11150
|
action: "review_queue_item",
|
|
11006
11151
|
options: ["accept", "reject", "archive", "invalidate", "keep_pending"],
|
|
11007
11152
|
recommendation: reviewStatus === "approved" || status === "active" ? "keep_pending" : "accept",
|
|
11008
|
-
reasonCodes:
|
|
11153
|
+
reasonCodes: uniqueStrings8(["memory_review_queue", reason ?? "", status ?? ""]),
|
|
11009
11154
|
evidenceItem: memoryEvidenceItem(item, {
|
|
11010
11155
|
ref: `memory:${memoryId}`,
|
|
11011
11156
|
title: `Review memory ${memoryId}`,
|
|
@@ -11044,7 +11189,7 @@ function cleanCandidateItems(result) {
|
|
|
11044
11189
|
action: `${bucket}_candidate`,
|
|
11045
11190
|
options,
|
|
11046
11191
|
recommendation,
|
|
11047
|
-
reasonCodes:
|
|
11192
|
+
reasonCodes: uniqueStrings8(["memory_clean_candidates", bucket, reason]),
|
|
11048
11193
|
evidenceItem: memoryEvidenceItem(candidate, {
|
|
11049
11194
|
ref: `memory:${memoryId}`,
|
|
11050
11195
|
title: `${bucket.replace(/_/g, " ")} memory candidate ${memoryId}`,
|
|
@@ -11081,7 +11226,7 @@ function duplicateCandidateItems(result) {
|
|
|
11081
11226
|
action: "duplicate_candidate",
|
|
11082
11227
|
options: ["merge", "supersede", "keep", "inspect"],
|
|
11083
11228
|
recommendation: keepMemoryId ? "supersede" : "inspect",
|
|
11084
|
-
reasonCodes:
|
|
11229
|
+
reasonCodes: uniqueStrings8(["memory_duplicate_candidates", `group_${index + 1}`]),
|
|
11085
11230
|
evidenceItem: memoryEvidenceItem(candidate, {
|
|
11086
11231
|
ref: `memory:${memoryId}`,
|
|
11087
11232
|
title: `Duplicate memory candidate ${memoryId}`,
|
|
@@ -11311,10 +11456,10 @@ function buildMemoryAuditSummary(audit) {
|
|
|
11311
11456
|
cleanupCandidateCounts,
|
|
11312
11457
|
...typeof compactDryRun.mutated === "boolean" ? { compactDryRunMutated: compactDryRun.mutated } : {},
|
|
11313
11458
|
...compactDryRunPlannedActions !== void 0 ? { compactDryRunPlannedActions } : {},
|
|
11314
|
-
recommendedActions:
|
|
11459
|
+
recommendedActions: uniqueStrings8(recommendedActions)
|
|
11315
11460
|
};
|
|
11316
11461
|
}
|
|
11317
|
-
function
|
|
11462
|
+
function uniqueStrings8(values) {
|
|
11318
11463
|
return Array.from(new Set(values));
|
|
11319
11464
|
}
|
|
11320
11465
|
function printMemoryAuditSummary(summary) {
|
|
@@ -11529,7 +11674,7 @@ async function memoryAuditCommand(options) {
|
|
|
11529
11674
|
var fs13 = __toESM(require("fs"));
|
|
11530
11675
|
var path12 = __toESM(require("path"));
|
|
11531
11676
|
var import_node_child_process2 = require("child_process");
|
|
11532
|
-
function
|
|
11677
|
+
function uniqueStrings9(values) {
|
|
11533
11678
|
return Array.from(new Set((values ?? []).map((value) => value.trim()).filter(Boolean)));
|
|
11534
11679
|
}
|
|
11535
11680
|
function slugify(value, fallback) {
|
|
@@ -11537,7 +11682,7 @@ function slugify(value, fallback) {
|
|
|
11537
11682
|
return slug2 || fallback;
|
|
11538
11683
|
}
|
|
11539
11684
|
function keywordHints(value) {
|
|
11540
|
-
return
|
|
11685
|
+
return uniqueStrings9(
|
|
11541
11686
|
value.split(/[^A-Za-z0-9_.:/-]+/).map((part) => part.trim()).filter((part) => part.length >= 4).slice(0, 8)
|
|
11542
11687
|
);
|
|
11543
11688
|
}
|
|
@@ -11583,17 +11728,17 @@ function expectedItems(section, values, files) {
|
|
|
11583
11728
|
}
|
|
11584
11729
|
function buildEvalCaseArtifact(options = {}) {
|
|
11585
11730
|
const rootDir = path12.resolve(options.dir ?? process.cwd());
|
|
11586
|
-
const files =
|
|
11587
|
-
const commandsRun =
|
|
11731
|
+
const files = uniqueStrings9(options.files);
|
|
11732
|
+
const commandsRun = uniqueStrings9(options.commandRun);
|
|
11588
11733
|
const summary = options.summary?.trim() || "Snipara companion local workflow evaluation";
|
|
11589
11734
|
const id = options.id?.trim() || slugify(summary, "snipara-companion-eval");
|
|
11590
11735
|
const expected = {};
|
|
11591
11736
|
const sectionInputs = {
|
|
11592
|
-
context:
|
|
11593
|
-
decisions:
|
|
11594
|
-
impact:
|
|
11595
|
-
verification:
|
|
11596
|
-
continuity:
|
|
11737
|
+
context: uniqueStrings9(options.context),
|
|
11738
|
+
decisions: uniqueStrings9(options.decision),
|
|
11739
|
+
impact: uniqueStrings9(options.impact),
|
|
11740
|
+
verification: uniqueStrings9(options.verification),
|
|
11741
|
+
continuity: uniqueStrings9(options.continuity)
|
|
11597
11742
|
};
|
|
11598
11743
|
for (const [section, values] of Object.entries(sectionInputs)) {
|
|
11599
11744
|
if (values.length > 0) {
|
|
@@ -13055,7 +13200,7 @@ var SESSION_SNAPSHOT_VERSION = "snipara.session_snapshot.v0";
|
|
|
13055
13200
|
var ACTIVITY_RELATIVE_DIR = path16.join(".snipara", "activity");
|
|
13056
13201
|
var ACTIVITY_TIMELINE_RELATIVE_PATH = path16.join(ACTIVITY_RELATIVE_DIR, "timeline.jsonl");
|
|
13057
13202
|
var SESSION_SNAPSHOT_RELATIVE_PATH = path16.join(ACTIVITY_RELATIVE_DIR, "session.json");
|
|
13058
|
-
function
|
|
13203
|
+
function uniqueStrings10(values) {
|
|
13059
13204
|
return Array.from(new Set(values.map((value) => value?.trim()).filter(Boolean)));
|
|
13060
13205
|
}
|
|
13061
13206
|
function stableJson(value) {
|
|
@@ -13128,8 +13273,8 @@ function appendActivityEvent(input) {
|
|
|
13128
13273
|
...input.phaseId ? { phaseId: input.phaseId } : {},
|
|
13129
13274
|
...input.actor ? { actor: input.actor } : {},
|
|
13130
13275
|
...input.outcome ? { outcome: input.outcome } : {},
|
|
13131
|
-
files:
|
|
13132
|
-
refs:
|
|
13276
|
+
files: uniqueStrings10(input.files ?? []),
|
|
13277
|
+
refs: uniqueStrings10(input.refs ?? []),
|
|
13133
13278
|
metadata: input.metadata ?? {}
|
|
13134
13279
|
};
|
|
13135
13280
|
const timelinePath = getActivityTimelinePath(cwd);
|
|
@@ -13224,7 +13369,7 @@ function deriveSessionSnapshotSummary(args) {
|
|
|
13224
13369
|
if (args.workflow?.status === "blocked") {
|
|
13225
13370
|
riskReasons.push("workflow is blocked");
|
|
13226
13371
|
}
|
|
13227
|
-
const touchedFiles =
|
|
13372
|
+
const touchedFiles = uniqueStrings10(args.latestEvents.flatMap((event) => event.files)).slice(
|
|
13228
13373
|
0,
|
|
13229
13374
|
20
|
|
13230
13375
|
);
|
|
@@ -13324,7 +13469,7 @@ function readSessionSnapshot(cwd = process.cwd()) {
|
|
|
13324
13469
|
}
|
|
13325
13470
|
|
|
13326
13471
|
// src/commands/journal.ts
|
|
13327
|
-
function
|
|
13472
|
+
function uniqueStrings11(values) {
|
|
13328
13473
|
if (!values) {
|
|
13329
13474
|
return [];
|
|
13330
13475
|
}
|
|
@@ -13352,7 +13497,7 @@ function buildJournalCheckpointEntry(payload) {
|
|
|
13352
13497
|
payload.actor ? `Actor: ${payload.actor}` : null,
|
|
13353
13498
|
payload.attention ? `Attention: ${payload.attention}` : null,
|
|
13354
13499
|
payload.next ? `Next: ${payload.next}` : null,
|
|
13355
|
-
|
|
13500
|
+
uniqueStrings11(payload.files).length > 0 ? `Files: ${uniqueStrings11(payload.files).join(", ")}` : null
|
|
13356
13501
|
].filter((line) => Boolean(line));
|
|
13357
13502
|
return {
|
|
13358
13503
|
text: lines.join("\n"),
|
|
@@ -13448,7 +13593,7 @@ function createRedactor(rootDir) {
|
|
|
13448
13593
|
patterns.add(item.name);
|
|
13449
13594
|
item.pattern.lastIndex = 0;
|
|
13450
13595
|
}
|
|
13451
|
-
const uniqueMatchedPatterns =
|
|
13596
|
+
const uniqueMatchedPatterns = uniqueStrings12(matchedPatterns);
|
|
13452
13597
|
if (uniqueMatchedPatterns.length > 0) {
|
|
13453
13598
|
redactedValueCount += 1;
|
|
13454
13599
|
}
|
|
@@ -13563,14 +13708,14 @@ function buildRepoState(input, options, rootDir, redactor) {
|
|
|
13563
13708
|
const inputRepo = inputRecord(input, "repoState", "repo_state", "repo");
|
|
13564
13709
|
const detected = detectGitState(rootDir);
|
|
13565
13710
|
const statusCounts = countGitStatus(detected.statusLines);
|
|
13566
|
-
const changedFiles =
|
|
13711
|
+
const changedFiles = uniqueStrings12([
|
|
13567
13712
|
...normalizeUnknownStringList(inputRepo.changedFiles),
|
|
13568
13713
|
...normalizeUnknownStringList(inputRepo.changed_files),
|
|
13569
13714
|
...normalizeUnknownStringList(input.changedFiles),
|
|
13570
13715
|
...normalizeUnknownStringList(input.changed_files),
|
|
13571
13716
|
...options.changedFiles ?? []
|
|
13572
13717
|
]).map((item) => redactor.redact(item).value);
|
|
13573
|
-
const recentFiles =
|
|
13718
|
+
const recentFiles = uniqueStrings12([
|
|
13574
13719
|
...normalizeUnknownStringList(inputRepo.recentFiles),
|
|
13575
13720
|
...normalizeUnknownStringList(inputRepo.recent_files),
|
|
13576
13721
|
...normalizeUnknownStringList(input.recentFiles),
|
|
@@ -13638,18 +13783,18 @@ function normalizeEvidenceItem(value, section, index, redactor) {
|
|
|
13638
13783
|
"command",
|
|
13639
13784
|
"check"
|
|
13640
13785
|
]) ?? fallbackSummary(value, section, index);
|
|
13641
|
-
const reasonCodes =
|
|
13786
|
+
const reasonCodes = uniqueStrings12([
|
|
13642
13787
|
`section_${section}`,
|
|
13643
13788
|
...normalizeUnknownStringList(value.reasonCodes),
|
|
13644
13789
|
...normalizeUnknownStringList(value.reason_codes)
|
|
13645
13790
|
]).map((item) => redactor.redact(item).value);
|
|
13646
|
-
const files =
|
|
13791
|
+
const files = uniqueStrings12([
|
|
13647
13792
|
...normalizeUnknownStringList(value.files),
|
|
13648
13793
|
...normalizeUnknownStringList(value.changedFiles),
|
|
13649
13794
|
...normalizeUnknownStringList(value.changed_files),
|
|
13650
13795
|
...normalizeUnknownStringList(value.file)
|
|
13651
13796
|
]).slice(0, MAX_LIST_ITEMS).map((item) => redactor.redact(item).value);
|
|
13652
|
-
const commands =
|
|
13797
|
+
const commands = uniqueStrings12([
|
|
13653
13798
|
...normalizeUnknownStringList(value.commands),
|
|
13654
13799
|
...normalizeUnknownStringList(value.command),
|
|
13655
13800
|
...normalizeUnknownStringList(value.checks),
|
|
@@ -13673,7 +13818,7 @@ function normalizeEvidenceItem(value, section, index, redactor) {
|
|
|
13673
13818
|
});
|
|
13674
13819
|
}
|
|
13675
13820
|
function collectReasonCodes(input, cliValues, items, redactor) {
|
|
13676
|
-
return
|
|
13821
|
+
return uniqueStrings12([
|
|
13677
13822
|
"coding_intelligence_ledger_v0",
|
|
13678
13823
|
...normalizeUnknownStringList(input.reasonCodes),
|
|
13679
13824
|
...normalizeUnknownStringList(input.reason_codes),
|
|
@@ -13704,13 +13849,13 @@ function buildCalibrationMetadata(input, cliValues, redactor) {
|
|
|
13704
13849
|
"calibration",
|
|
13705
13850
|
"calibration_metadata"
|
|
13706
13851
|
);
|
|
13707
|
-
const notes =
|
|
13852
|
+
const notes = uniqueStrings12([
|
|
13708
13853
|
...normalizeUnknownStringList(calibration.notes),
|
|
13709
13854
|
...normalizeUnknownStringList(calibration.note),
|
|
13710
13855
|
...normalizeUnknownStringList(input.calibrationNotes),
|
|
13711
13856
|
...cliValues ?? []
|
|
13712
13857
|
]).slice(0, MAX_LIST_ITEMS).map((item) => redactor.redact(item).value);
|
|
13713
|
-
const caveats =
|
|
13858
|
+
const caveats = uniqueStrings12([
|
|
13714
13859
|
...normalizeUnknownStringList(calibration.caveats),
|
|
13715
13860
|
...normalizeUnknownStringList(calibration.caveat),
|
|
13716
13861
|
...normalizeUnknownStringList(input.calibrationCaveats)
|
|
@@ -13907,7 +14052,7 @@ function validIso(value) {
|
|
|
13907
14052
|
const date = new Date(value);
|
|
13908
14053
|
return Number.isNaN(date.getTime()) ? void 0 : date.toISOString();
|
|
13909
14054
|
}
|
|
13910
|
-
function
|
|
14055
|
+
function uniqueStrings12(values) {
|
|
13911
14056
|
return Array.from(new Set(values.map((value) => value.trim()).filter(Boolean)));
|
|
13912
14057
|
}
|
|
13913
14058
|
function compactWhitespace(value) {
|
|
@@ -16209,16 +16354,16 @@ function upsertLocalAdaptiveRoutingPolicy(workerRole) {
|
|
|
16209
16354
|
mode: stringValue6(existing.mode) ?? "catalog",
|
|
16210
16355
|
plannerRetainsReasoning: existing.plannerRetainsReasoning !== false,
|
|
16211
16356
|
preferLocalWorkers: true,
|
|
16212
|
-
allowedEndpointTypes:
|
|
16357
|
+
allowedEndpointTypes: uniqueStrings13([
|
|
16213
16358
|
...normalizeStringList3(existing.allowedEndpointTypes),
|
|
16214
16359
|
"local",
|
|
16215
16360
|
"cloud"
|
|
16216
16361
|
]),
|
|
16217
|
-
preferredEndpointTypes:
|
|
16362
|
+
preferredEndpointTypes: uniqueStrings13([
|
|
16218
16363
|
"local",
|
|
16219
16364
|
...normalizeStringList3(existing.preferredEndpointTypes)
|
|
16220
16365
|
]),
|
|
16221
|
-
allowedWorkerClasses:
|
|
16366
|
+
allowedWorkerClasses: uniqueStrings13([
|
|
16222
16367
|
...normalizeStringList3(existing.allowedWorkerClasses),
|
|
16223
16368
|
workerRole,
|
|
16224
16369
|
"documentation",
|
|
@@ -16458,7 +16603,7 @@ function normalizeWorkerProfileLanguages(value) {
|
|
|
16458
16603
|
return value.length > 0 ? value : ["typescript"];
|
|
16459
16604
|
}
|
|
16460
16605
|
function normalizeWorkerCapabilities(values) {
|
|
16461
|
-
return values.length > 0 ?
|
|
16606
|
+
return values.length > 0 ? uniqueStrings13(values.map((value) => String(value).trim()).filter(Boolean)) : ["code", "repo_scan", "refactor"];
|
|
16462
16607
|
}
|
|
16463
16608
|
function defaultCapabilitiesForWorker(workerRole) {
|
|
16464
16609
|
if (workerRole === "documentation") {
|
|
@@ -16474,9 +16619,9 @@ function defaultCapabilitiesForWorker(workerRole) {
|
|
|
16474
16619
|
}
|
|
16475
16620
|
function normalizeStringList3(value) {
|
|
16476
16621
|
const values = Array.isArray(value) ? value : value === void 0 ? [] : [value];
|
|
16477
|
-
return
|
|
16622
|
+
return uniqueStrings13(values.map(stringValue6).filter((item) => Boolean(item)));
|
|
16478
16623
|
}
|
|
16479
|
-
function
|
|
16624
|
+
function uniqueStrings13(values) {
|
|
16480
16625
|
return Array.from(new Set(values));
|
|
16481
16626
|
}
|
|
16482
16627
|
function stringValue6(value) {
|
|
@@ -16634,7 +16779,7 @@ function numberValue4(value) {
|
|
|
16634
16779
|
const parsed = Number(text);
|
|
16635
16780
|
return Number.isFinite(parsed) ? parsed : void 0;
|
|
16636
16781
|
}
|
|
16637
|
-
function
|
|
16782
|
+
function uniqueStrings14(values) {
|
|
16638
16783
|
return Array.from(new Set(values.filter((value) => value.trim().length > 0)));
|
|
16639
16784
|
}
|
|
16640
16785
|
function normalizeEnum(value) {
|
|
@@ -17950,7 +18095,7 @@ function buildProducerLoopArtifact(options) {
|
|
|
17950
18095
|
workflowId ?? "unmanaged",
|
|
17951
18096
|
options.phase?.id ? `phase:${options.phase.id}` : "final"
|
|
17952
18097
|
].join(":");
|
|
17953
|
-
const reasonCodes =
|
|
18098
|
+
const reasonCodes = uniqueStrings14([
|
|
17954
18099
|
"producer_loop_v0",
|
|
17955
18100
|
options.kind,
|
|
17956
18101
|
`outcome_${options.outcome}`,
|
|
@@ -18142,8 +18287,8 @@ function summarizeProducerLoopArtifactFile(filePath, cwd) {
|
|
|
18142
18287
|
relativePath: relativePath2,
|
|
18143
18288
|
artifactHash: `sha256:${hashContent(content)}`,
|
|
18144
18289
|
ledgerHash: stringValue7(parsed.ledgerHash),
|
|
18145
|
-
reasonCodes:
|
|
18146
|
-
files:
|
|
18290
|
+
reasonCodes: uniqueStrings14(stringArrayValue(ledger?.reasonCodes)),
|
|
18291
|
+
files: uniqueStrings14(stringArrayValue(producer.files)),
|
|
18147
18292
|
calibrationStatus: stringValue7(calibration?.status),
|
|
18148
18293
|
reviewStatus,
|
|
18149
18294
|
reviewOutcome: stringValue7(review?.outcome),
|
|
@@ -18190,10 +18335,10 @@ function buildProducerLoopReport(options = {}) {
|
|
|
18190
18335
|
(left, right) => left.generatedAt === right.generatedAt ? left.relativePath.localeCompare(right.relativePath) : left.generatedAt.localeCompare(right.generatedAt)
|
|
18191
18336
|
);
|
|
18192
18337
|
const invalidArtifacts = summaries.map((entry) => entry.invalid).filter((entry) => Boolean(entry));
|
|
18193
|
-
const producerKinds =
|
|
18338
|
+
const producerKinds = uniqueStrings14(artifacts.map((artifact) => artifact.producerKind)).filter(
|
|
18194
18339
|
(kind) => isProducerLoopProducerKind(kind)
|
|
18195
18340
|
);
|
|
18196
|
-
const workflowIds =
|
|
18341
|
+
const workflowIds = uniqueStrings14(
|
|
18197
18342
|
artifacts.map((artifact) => artifact.workflowId).filter((id) => Boolean(id))
|
|
18198
18343
|
);
|
|
18199
18344
|
const reasonCodeCounts = countStringOccurrences(
|
|
@@ -18344,7 +18489,7 @@ function readProducerLoopArtifactForReview(filePath) {
|
|
|
18344
18489
|
return parsed;
|
|
18345
18490
|
}
|
|
18346
18491
|
function applyProducerLoopArtifactReview(artifact, options) {
|
|
18347
|
-
const reviewNotes =
|
|
18492
|
+
const reviewNotes = uniqueStrings14(options.notes ?? []);
|
|
18348
18493
|
const reviewNote = options.status === "sample_rejected" ? "Sample rejected by local operator review." : "Sample reviewed by local operator.";
|
|
18349
18494
|
const existingCalibration = artifact.calibration ?? {
|
|
18350
18495
|
status: "sample_unreviewed",
|
|
@@ -18359,7 +18504,7 @@ function applyProducerLoopArtifactReview(artifact, options) {
|
|
|
18359
18504
|
status: options.status,
|
|
18360
18505
|
sampleSize: 1,
|
|
18361
18506
|
hardGateReady: false,
|
|
18362
|
-
notes:
|
|
18507
|
+
notes: uniqueStrings14([
|
|
18363
18508
|
...stringArrayValue(existingCalibration.notes),
|
|
18364
18509
|
reviewNote,
|
|
18365
18510
|
...reviewNotes.map((note) => `Review note: ${note}`)
|
|
@@ -18574,7 +18719,7 @@ function applyDecisionRequestLocally(options) {
|
|
|
18574
18719
|
reject: isRejectChoice(options.choice),
|
|
18575
18720
|
outcome: isRejectChoice(options.choice) ? "false_positive" : "useful",
|
|
18576
18721
|
reviewer: options.reviewer,
|
|
18577
|
-
notes:
|
|
18722
|
+
notes: uniqueStrings14([
|
|
18578
18723
|
`decision_request:${request.requestId}`,
|
|
18579
18724
|
...options.note ? [options.note] : []
|
|
18580
18725
|
])
|
|
@@ -18597,7 +18742,7 @@ function recurringPolicySuggestionTargetCategory(request) {
|
|
|
18597
18742
|
const metadata = isRecord9(item.metadata) ? item.metadata : void 0;
|
|
18598
18743
|
return stringValue7(metadata?.category) ?? stringValue7(metadata?.type) ?? item.kind;
|
|
18599
18744
|
}).filter((value) => Boolean(value)) ?? [];
|
|
18600
|
-
return
|
|
18745
|
+
return uniqueStrings14(evidenceCategories).sort().join("|") || request.evidence.applyPath || request.decision;
|
|
18601
18746
|
}
|
|
18602
18747
|
function buildRecurringDecisionPolicySuggestionRequest(resolvedRecords) {
|
|
18603
18748
|
const grouped = /* @__PURE__ */ new Map();
|
|
@@ -18635,12 +18780,12 @@ function buildRecurringDecisionPolicySuggestionRequest(resolvedRecords) {
|
|
|
18635
18780
|
status: record.response.choice,
|
|
18636
18781
|
files: record.request.evidence.files?.slice(0, 12)
|
|
18637
18782
|
})),
|
|
18638
|
-
reasonCodes:
|
|
18783
|
+
reasonCodes: uniqueStrings14([
|
|
18639
18784
|
"recurring_decision_receipts",
|
|
18640
18785
|
"never_ask_twice_candidate",
|
|
18641
18786
|
...latest.request.evidence.reasonCodes
|
|
18642
18787
|
]),
|
|
18643
|
-
files:
|
|
18788
|
+
files: uniqueStrings14(repeated.flatMap((record) => record.request.evidence.files ?? [])),
|
|
18644
18789
|
applyPath: "manual_context_review",
|
|
18645
18790
|
applyCommand: "Review the suggested rule and add it to the appropriate project policy or AGENTS.md section manually."
|
|
18646
18791
|
},
|
|
@@ -18782,12 +18927,12 @@ function buildProducerTriageRequest(report) {
|
|
|
18782
18927
|
summary: `${candidates.length} unreviewed Producer Loop samples; ${report.invalidArtifacts.length} invalid artifacts; hardGateReady remains false.`,
|
|
18783
18928
|
refs,
|
|
18784
18929
|
items,
|
|
18785
|
-
reasonCodes:
|
|
18930
|
+
reasonCodes: uniqueStrings14([
|
|
18786
18931
|
"triage_rules_v0",
|
|
18787
18932
|
"producer_loop_report_valid",
|
|
18788
18933
|
...report.invalidArtifacts.length === 0 ? ["no_invalid_artifacts"] : ["invalid_artifacts_present"]
|
|
18789
18934
|
]),
|
|
18790
|
-
files:
|
|
18935
|
+
files: uniqueStrings14(candidates.flatMap((artifact) => artifact.files)),
|
|
18791
18936
|
applyPath: "workflow producer-review",
|
|
18792
18937
|
applyCommand: "snipara-companion workflow decide <request-id> --choose accept_all --reviewer <name>"
|
|
18793
18938
|
},
|
|
@@ -20563,8 +20708,8 @@ async function enrichAdaptiveRoutingWithHostedCatalog(client, routing) {
|
|
|
20563
20708
|
runtimeCatalog: catalog,
|
|
20564
20709
|
routingCard: {
|
|
20565
20710
|
...routing.routingCard,
|
|
20566
|
-
reasons:
|
|
20567
|
-
warnings:
|
|
20711
|
+
reasons: uniqueStrings14(reasons),
|
|
20712
|
+
warnings: uniqueStrings14([...routing.routingCard.warnings, ...gatewayWarnings])
|
|
20568
20713
|
}
|
|
20569
20714
|
};
|
|
20570
20715
|
} catch (error) {
|
|
@@ -20581,7 +20726,7 @@ async function enrichAdaptiveRoutingWithHostedCatalog(client, routing) {
|
|
|
20581
20726
|
},
|
|
20582
20727
|
routingCard: {
|
|
20583
20728
|
...routing.routingCard,
|
|
20584
|
-
warnings:
|
|
20729
|
+
warnings: uniqueStrings14([...routing.routingCard.warnings, warning])
|
|
20585
20730
|
}
|
|
20586
20731
|
};
|
|
20587
20732
|
}
|
|
@@ -20772,7 +20917,7 @@ function enrichAdaptiveRoutingWithLocalOrchestrator(routing, options, cwd = proc
|
|
|
20772
20917
|
const approvalRequired = booleanValue4(
|
|
20773
20918
|
isRecord9(resolution?.policyDecision) ? resolution.policyDecision.approvalRequired : void 0
|
|
20774
20919
|
);
|
|
20775
|
-
const gatewayWarnings =
|
|
20920
|
+
const gatewayWarnings = uniqueStrings14([
|
|
20776
20921
|
...resolutionWarnings,
|
|
20777
20922
|
...selectedCandidate ? [] : ["Local orchestrator did not select a worker candidate and will fail closed."]
|
|
20778
20923
|
]);
|
|
@@ -20794,7 +20939,7 @@ function enrichAdaptiveRoutingWithLocalOrchestrator(routing, options, cwd = proc
|
|
|
20794
20939
|
...selectedCandidate?.workerClass ? { recommendedWorkerClass: selectedCandidate.workerClass } : {},
|
|
20795
20940
|
...resolutionRejectedReasons ? { rejectedReasons: resolutionRejectedReasons } : {},
|
|
20796
20941
|
...approvalRequired !== void 0 ? { humanApprovalRequired: approvalRequired } : {},
|
|
20797
|
-
reasons:
|
|
20942
|
+
reasons: uniqueStrings14([
|
|
20798
20943
|
...routing.routingCard.reasons,
|
|
20799
20944
|
...resolutionReasons,
|
|
20800
20945
|
...selectedCandidate ? [
|
|
@@ -20803,7 +20948,7 @@ function enrichAdaptiveRoutingWithLocalOrchestrator(routing, options, cwd = proc
|
|
|
20803
20948
|
...stringValue7(selectedEndpoint?.model) ? [`selected local model ${String(selectedEndpoint?.model)}`] : []
|
|
20804
20949
|
] : ["local orchestrator could not resolve a concrete worker candidate"]
|
|
20805
20950
|
]),
|
|
20806
|
-
warnings:
|
|
20951
|
+
warnings: uniqueStrings14([...routing.routingCard.warnings, ...gatewayWarnings])
|
|
20807
20952
|
}
|
|
20808
20953
|
};
|
|
20809
20954
|
} catch (error) {
|
|
@@ -20820,7 +20965,7 @@ function enrichAdaptiveRoutingWithLocalOrchestrator(routing, options, cwd = proc
|
|
|
20820
20965
|
},
|
|
20821
20966
|
routingCard: {
|
|
20822
20967
|
...routing.routingCard,
|
|
20823
|
-
warnings:
|
|
20968
|
+
warnings: uniqueStrings14([...routing.routingCard.warnings, warning])
|
|
20824
20969
|
}
|
|
20825
20970
|
};
|
|
20826
20971
|
}
|
|
@@ -22689,8 +22834,8 @@ function buildWorkflowAdaptiveRouting(options, policy = null, intentWarnings = [
|
|
|
22689
22834
|
...routing,
|
|
22690
22835
|
routingCard: {
|
|
22691
22836
|
...routing.routingCard,
|
|
22692
|
-
reasons:
|
|
22693
|
-
warnings:
|
|
22837
|
+
reasons: uniqueStrings14([...routing.routingCard.reasons, ...policyReasons]),
|
|
22838
|
+
warnings: uniqueStrings14([...routing.routingCard.warnings, ...policyWarnings])
|
|
22694
22839
|
}
|
|
22695
22840
|
};
|
|
22696
22841
|
}
|
|
@@ -22706,7 +22851,7 @@ function normalizeAdaptiveRoutingMode(value) {
|
|
|
22706
22851
|
return normalized === "off" || normalized === "recommend" || normalized === "catalog" ? normalized : null;
|
|
22707
22852
|
}
|
|
22708
22853
|
function normalizeAdaptiveWorkerClasses(values) {
|
|
22709
|
-
return
|
|
22854
|
+
return uniqueStrings14((values ?? []).map(canonicalAdaptiveWorkerClass)).filter(
|
|
22710
22855
|
(value) => ["documentation", "tests", "review", "coding"].includes(value)
|
|
22711
22856
|
);
|
|
22712
22857
|
}
|
|
@@ -26933,7 +27078,7 @@ function normalizeCaptureEvent(event, now, index) {
|
|
|
26933
27078
|
const reasons = normalizeStringList4(event.reason).map(redactText);
|
|
26934
27079
|
const evidence = normalizeStringList4(event.evidence).map(redactText);
|
|
26935
27080
|
const commands = normalizeStringList4(event.commands).map(redactText);
|
|
26936
|
-
const redactionPatterns =
|
|
27081
|
+
const redactionPatterns = uniqueStrings15([
|
|
26937
27082
|
...summary.patterns,
|
|
26938
27083
|
...outcome.patterns,
|
|
26939
27084
|
...status.patterns,
|
|
@@ -26966,7 +27111,7 @@ function normalizeEventKind(value) {
|
|
|
26966
27111
|
return "feedback";
|
|
26967
27112
|
}
|
|
26968
27113
|
function reasonCodesForEvent(event, kind, status) {
|
|
26969
|
-
return
|
|
27114
|
+
return uniqueStrings15([
|
|
26970
27115
|
"why_outcome_capture_v1",
|
|
26971
27116
|
"review_pending_authority",
|
|
26972
27117
|
`source_${event.kind}`,
|
|
@@ -27031,7 +27176,7 @@ function readEventsFromFile(filePath) {
|
|
|
27031
27176
|
function stableHash2(parts) {
|
|
27032
27177
|
return (0, import_node_crypto8.createHash)("sha256").update(parts.join("\0")).digest("hex");
|
|
27033
27178
|
}
|
|
27034
|
-
function
|
|
27179
|
+
function uniqueStrings15(values) {
|
|
27035
27180
|
return Array.from(new Set(values.filter(Boolean)));
|
|
27036
27181
|
}
|
|
27037
27182
|
function compactWhitespace3(value) {
|
|
@@ -28282,6 +28427,108 @@ function actionList(value) {
|
|
|
28282
28427
|
return reason ? `${priority}${preview3(title, 80)} - ${preview3(reason, 140)}` : `${priority}${preview3(title, 160)}`;
|
|
28283
28428
|
}).filter(Boolean);
|
|
28284
28429
|
}
|
|
28430
|
+
function extractProjectPolicyRulesFromResumeContext(resumeContext) {
|
|
28431
|
+
if (!resumeContext) {
|
|
28432
|
+
return [];
|
|
28433
|
+
}
|
|
28434
|
+
return collectRecords(resumeContext).map(recordToProjectPolicyRule).filter((rule) => Boolean(rule));
|
|
28435
|
+
}
|
|
28436
|
+
function collectRecords(value, depth = 0) {
|
|
28437
|
+
if (depth > 5) {
|
|
28438
|
+
return [];
|
|
28439
|
+
}
|
|
28440
|
+
if (Array.isArray(value)) {
|
|
28441
|
+
return value.flatMap((item) => collectRecords(item, depth + 1));
|
|
28442
|
+
}
|
|
28443
|
+
if (!isRecord15(value)) {
|
|
28444
|
+
return [];
|
|
28445
|
+
}
|
|
28446
|
+
return [
|
|
28447
|
+
value,
|
|
28448
|
+
...Object.values(value).flatMap(
|
|
28449
|
+
(item) => typeof item === "object" && item !== null ? collectRecords(item, depth + 1) : []
|
|
28450
|
+
)
|
|
28451
|
+
];
|
|
28452
|
+
}
|
|
28453
|
+
function recordToProjectPolicyRule(record) {
|
|
28454
|
+
const type = preview3(record.type ?? record.memory_type ?? record.category, 80).toLowerCase();
|
|
28455
|
+
const content = preview3(record.content ?? record.text ?? record.summary ?? record.decision, 4e3);
|
|
28456
|
+
if (!content || !/(decision|policy|workflow-policy|roadmap)/i.test(type)) {
|
|
28457
|
+
return void 0;
|
|
28458
|
+
}
|
|
28459
|
+
const status = preview3(record.status ?? record.lifecycleStatus ?? "active", 40).toLowerCase();
|
|
28460
|
+
const reviewStatus = preview3(record.reviewStatus ?? record.review_status ?? "approved", 40).toLowerCase().replace("canonical", "approved");
|
|
28461
|
+
if (status && status !== "active") {
|
|
28462
|
+
return void 0;
|
|
28463
|
+
}
|
|
28464
|
+
if (reviewStatus && reviewStatus !== "approved") {
|
|
28465
|
+
return void 0;
|
|
28466
|
+
}
|
|
28467
|
+
const anchors = extractPolicyAnchors(content);
|
|
28468
|
+
if (anchors.length === 0) {
|
|
28469
|
+
return void 0;
|
|
28470
|
+
}
|
|
28471
|
+
const id = preview3(record.memory_id ?? record.id ?? record.source_id ?? anchors[0], 80);
|
|
28472
|
+
const confidence = numberValue8(record.confidence) ?? numberValue8(record.score) ?? 0.8;
|
|
28473
|
+
return {
|
|
28474
|
+
id,
|
|
28475
|
+
title: preview3(record.title ?? content, 120),
|
|
28476
|
+
scope: inferProjectPolicyScope(content, anchors),
|
|
28477
|
+
strength: inferProjectPolicyStrength(content),
|
|
28478
|
+
confidence,
|
|
28479
|
+
source: {
|
|
28480
|
+
kind: "decision_memory",
|
|
28481
|
+
ref: id.startsWith("memory:") ? id : `memory:${id}`,
|
|
28482
|
+
reviewStatus: "approved"
|
|
28483
|
+
},
|
|
28484
|
+
anchors,
|
|
28485
|
+
requirement: content.slice(0, 240),
|
|
28486
|
+
forbiddenActions: extractForbiddenActions(content)
|
|
28487
|
+
};
|
|
28488
|
+
}
|
|
28489
|
+
function extractPolicyAnchors(text) {
|
|
28490
|
+
const normalized = text.toLowerCase();
|
|
28491
|
+
return [
|
|
28492
|
+
...Array.from(normalized.matchAll(/`([^`]{3,120})`/g), (match) => match[1]),
|
|
28493
|
+
...Array.from(
|
|
28494
|
+
normalized.matchAll(/\b(?:apps|packages|deploy|docs|scripts|oss)\/[a-z0-9_[\]./-]+/g),
|
|
28495
|
+
(match) => match[0]
|
|
28496
|
+
),
|
|
28497
|
+
...["auth", "billing", "schema", "migration", "deploy", "package", "memory", "routing"].filter(
|
|
28498
|
+
(term) => normalized.includes(term)
|
|
28499
|
+
)
|
|
28500
|
+
].filter((value, index, values) => value && values.indexOf(value) === index);
|
|
28501
|
+
}
|
|
28502
|
+
function inferProjectPolicyScope(text, anchors) {
|
|
28503
|
+
const haystack = `${text}
|
|
28504
|
+
${anchors.join("\n")}`.toLowerCase();
|
|
28505
|
+
if (/\b(auth|oauth|session|permission|token|secret)\b/.test(haystack)) return "auth";
|
|
28506
|
+
if (/\b(billing|stripe|subscription|checkout|entitlement|quota)\b/.test(haystack)) {
|
|
28507
|
+
return "billing";
|
|
28508
|
+
}
|
|
28509
|
+
if (/\b(schema|migration|prisma|database)\b/.test(haystack)) return "schema";
|
|
28510
|
+
if (/\b(deploy|production|pre-deploy|zero-downtime)\b/.test(haystack)) return "deploy";
|
|
28511
|
+
if (/\b(package|npm|pypi|npx|publish|pack smoke)\b/.test(haystack)) return "package_surface";
|
|
28512
|
+
if (/\b(memory|reviewed memory|decision memory)\b/.test(haystack)) return "memory";
|
|
28513
|
+
if (/\b(routing|orchestrator|worker)\b/.test(haystack)) return "routing";
|
|
28514
|
+
return "custom";
|
|
28515
|
+
}
|
|
28516
|
+
function inferProjectPolicyStrength(text) {
|
|
28517
|
+
const normalized = text.toLowerCase();
|
|
28518
|
+
if (/\b(never|must not|do not|forbid|forbidden|disallow|block)\b/.test(normalized)) {
|
|
28519
|
+
return "blocking";
|
|
28520
|
+
}
|
|
28521
|
+
if (/\b(require review|requires review|approval|required|must)\b/.test(normalized)) {
|
|
28522
|
+
return "review_required";
|
|
28523
|
+
}
|
|
28524
|
+
return "advisory";
|
|
28525
|
+
}
|
|
28526
|
+
function extractForbiddenActions(text) {
|
|
28527
|
+
const normalized = text.toLowerCase();
|
|
28528
|
+
return ["bypass", "skip", "remove", "delete", "disable", "drop", "force"].filter(
|
|
28529
|
+
(term) => normalized.includes(term)
|
|
28530
|
+
);
|
|
28531
|
+
}
|
|
28285
28532
|
function buildSuggestedCommands2(args) {
|
|
28286
28533
|
const commands = [
|
|
28287
28534
|
"snipara-companion team-sync what-changed",
|
|
@@ -28374,6 +28621,16 @@ async function buildProjectIntelligenceBrief(options) {
|
|
|
28374
28621
|
});
|
|
28375
28622
|
}
|
|
28376
28623
|
}
|
|
28624
|
+
const projectPolicyRules = extractProjectPolicyRulesFromResumeContext(brief.resumeContext);
|
|
28625
|
+
if (projectPolicyRules.length > 0) {
|
|
28626
|
+
brief.projectPolicyDecision = evaluateProjectPolicyDecision({
|
|
28627
|
+
action: {
|
|
28628
|
+
summary: options.diffSummary ?? options.task ?? "Project Intelligence brief",
|
|
28629
|
+
changedFiles
|
|
28630
|
+
},
|
|
28631
|
+
rules: projectPolicyRules
|
|
28632
|
+
});
|
|
28633
|
+
}
|
|
28377
28634
|
brief.verificationPlan = buildVerificationPlan({
|
|
28378
28635
|
task: options.task,
|
|
28379
28636
|
changedFiles,
|
|
@@ -28539,6 +28796,19 @@ async function projectIntelligenceBriefCommand(options) {
|
|
|
28539
28796
|
console.log(import_chalk9.default.bold("Memory Authority And Health"));
|
|
28540
28797
|
printMemoryHealth2(brief.memoryHealth);
|
|
28541
28798
|
console.log("");
|
|
28799
|
+
if (brief.projectPolicyDecision) {
|
|
28800
|
+
console.log(import_chalk9.default.bold("Project Policy"));
|
|
28801
|
+
console.log(
|
|
28802
|
+
`Verdict: ${brief.projectPolicyDecision.verdict} (${Math.round(
|
|
28803
|
+
brief.projectPolicyDecision.confidence * 100
|
|
28804
|
+
)}%)`
|
|
28805
|
+
);
|
|
28806
|
+
if (brief.projectPolicyDecision.requiredActions.length > 0) {
|
|
28807
|
+
console.log(`Required: ${brief.projectPolicyDecision.requiredActions[0]}`);
|
|
28808
|
+
}
|
|
28809
|
+
console.log(`Receipt: ${brief.projectPolicyDecision.receipt.receiptId}`);
|
|
28810
|
+
console.log("");
|
|
28811
|
+
}
|
|
28542
28812
|
console.log(import_chalk9.default.bold("Code Impact"));
|
|
28543
28813
|
if (brief.codeImpactSourceSelection) {
|
|
28544
28814
|
console.log(
|
|
@@ -29246,9 +29516,46 @@ function gateSummary(gates) {
|
|
|
29246
29516
|
function packageReviewCommand2(input) {
|
|
29247
29517
|
return input.packageReview?.command ?? "npm view snipara-companion version bin dist-tags --json";
|
|
29248
29518
|
}
|
|
29519
|
+
function gateSurfaceFromPolicyScope(scope) {
|
|
29520
|
+
if (scope === "release" || scope === "schema" || scope === "auth" || scope === "billing" || scope === "deploy" || scope === "package_surface") {
|
|
29521
|
+
return scope;
|
|
29522
|
+
}
|
|
29523
|
+
return "project_policy";
|
|
29524
|
+
}
|
|
29249
29525
|
function evaluateProjectPolicyGates(input) {
|
|
29250
29526
|
const changedFiles = normalizeChangedFiles(input.changedFiles);
|
|
29251
29527
|
const gates = [];
|
|
29528
|
+
const projectPolicyDecision = input.projectPolicy?.decision ?? (input.projectPolicy?.rules?.length ? evaluateProjectPolicyDecision({
|
|
29529
|
+
action: {
|
|
29530
|
+
summary: [input.task, input.diffSummary].filter(Boolean).join("\n"),
|
|
29531
|
+
changedFiles
|
|
29532
|
+
},
|
|
29533
|
+
rules: input.projectPolicy.rules
|
|
29534
|
+
}) : void 0);
|
|
29535
|
+
if (projectPolicyDecision && projectPolicyDecision.verdict !== "allow") {
|
|
29536
|
+
const strongestRule = projectPolicyDecision.matchedRules[0];
|
|
29537
|
+
gates.push(
|
|
29538
|
+
gate({
|
|
29539
|
+
id: "policy:project:decision-consistency",
|
|
29540
|
+
surface: strongestRule ? gateSurfaceFromPolicyScope(strongestRule.scope) : "project_policy",
|
|
29541
|
+
severity: projectPolicyVerdictToGateSeverity(projectPolicyDecision.verdict),
|
|
29542
|
+
title: "Project Policy decision consistency",
|
|
29543
|
+
rationale: "Approved project policy and decision memories can require review or block when the proposed action contradicts high-confidence constraints.",
|
|
29544
|
+
evidence: [
|
|
29545
|
+
`verdict ${projectPolicyDecision.verdict}`,
|
|
29546
|
+
`receipt ${projectPolicyDecision.receipt.receiptId}`,
|
|
29547
|
+
...projectPolicyDecision.matchedRules.map((rule) => `${rule.source.ref}: ${rule.title}`)
|
|
29548
|
+
],
|
|
29549
|
+
requiredActions: projectPolicyDecision.requiredActions.length > 0 ? projectPolicyDecision.requiredActions : ["Review the matching project policy decision before proceeding."],
|
|
29550
|
+
suggestedCommands: projectPolicyDecision.verdict === "block" ? ["snipara-companion decisions request --help"] : ["snipara-companion memory reviews --emit-decisions"],
|
|
29551
|
+
sampleGate: explicitContractSampleGate(
|
|
29552
|
+
"Project Policy gates are driven by reviewed decisions and explicit receipts, not statistical outcome thresholds."
|
|
29553
|
+
),
|
|
29554
|
+
source: "project_policy_decision",
|
|
29555
|
+
reasonCodes: projectPolicyDecision.reasonCodes
|
|
29556
|
+
})
|
|
29557
|
+
);
|
|
29558
|
+
}
|
|
29252
29559
|
if (input.release) {
|
|
29253
29560
|
gates.push(
|
|
29254
29561
|
gate({
|
|
@@ -29507,6 +29814,7 @@ function evaluateProjectPolicyGates(input) {
|
|
|
29507
29814
|
release: Boolean(input.release),
|
|
29508
29815
|
summary,
|
|
29509
29816
|
gates,
|
|
29817
|
+
...projectPolicyDecision ? { projectPolicyDecision } : {},
|
|
29510
29818
|
suggestedCommands: suggestedCommands3
|
|
29511
29819
|
};
|
|
29512
29820
|
}
|
|
@@ -30011,7 +30319,10 @@ async function buildProjectIntelligenceRun(options) {
|
|
|
30011
30319
|
skipPackageReview: options.skipPackageReview,
|
|
30012
30320
|
guard,
|
|
30013
30321
|
packageReview,
|
|
30014
|
-
judgmentCard
|
|
30322
|
+
judgmentCard,
|
|
30323
|
+
projectPolicy: brief.projectPolicyDecision ? {
|
|
30324
|
+
decision: brief.projectPolicyDecision
|
|
30325
|
+
} : void 0
|
|
30015
30326
|
});
|
|
30016
30327
|
const verificationEvidence = verificationEvidenceFromRun({
|
|
30017
30328
|
guard,
|
package/docs/FULL_REFERENCE.md
CHANGED
|
@@ -1037,6 +1037,12 @@ checkouts use hosted graph impact. It prints continuity signals, memory health,
|
|
|
1037
1037
|
risk and verification hints, degraded surfaces, and the Judgment Card's
|
|
1038
1038
|
weighted readiness, evidence, and required actions.
|
|
1039
1039
|
|
|
1040
|
+
When hosted resume context includes approved decision memories that match the
|
|
1041
|
+
task or changed files, the brief also emits a Project Policy decision receipt
|
|
1042
|
+
with an `allow`, `warn`, `require_review`, or `block` verdict. This is
|
|
1043
|
+
conservative by design: blocks require high-confidence reviewed policy plus a
|
|
1044
|
+
matching forbidden action, and no new default MCP tool is exposed.
|
|
1045
|
+
|
|
1040
1046
|
Use `reality-check` or `intelligence reality-check` when a local hook, agent, or
|
|
1041
1047
|
CI adapter needs the contradiction-to-reality gate without a full hosted brief:
|
|
1042
1048
|
|
|
@@ -1146,7 +1152,7 @@ Semantics:
|
|
|
1146
1152
|
- `snipara-companion workflow timeline` = append-only activity timeline from `.snipara/activity/timeline.jsonl`, including workflow, Producer Loop, Decision Request, and Team Sync events emitted by Companion commands; add `--export md` for a redacted Markdown artifact
|
|
1147
1153
|
- `snipara-companion workflow session` = writes and prints Session Snapshot V0 at `.snipara/activity/session.json` with latest activity, risk, touched files, next action, advisory Intent Detection V0 intent/confidence/signals/suggested mode, workflow/session counts, Producer Loop calibration, decision counts, Team Sync counts, and `hardRoutingAllowed=false`
|
|
1148
1154
|
- `snipara-companion handoff` = top-level agent-ready Markdown/JSON handoff artifact plus the same local/hosted Team Sync handoff persistence
|
|
1149
|
-
- `snipara-companion intelligence brief` = one local Project Intelligence brief that combines local Session Snapshot, hosted resume context, memory health, and code impact for a task
|
|
1155
|
+
- `snipara-companion intelligence brief` = one local Project Intelligence brief that combines local Session Snapshot, hosted resume context, memory health, Project Policy decision receipts, and code impact for a task
|
|
1150
1156
|
- `snipara-companion intelligence reality-check` = Project Intelligence namespace alias for the same local Reality Check gate
|
|
1151
1157
|
- `snipara-companion intelligence ledger-export` = structured redacted Coding Intelligence Ledger JSON for replay, review, and commercial proof assets without dumping raw transcripts
|
|
1152
1158
|
- `snipara-companion run` = production Project Intelligence flow that combines the brief, guard action cards, package review, verification hints, and a final weighted Judgment Card
|
|
@@ -1172,7 +1178,7 @@ Semantics:
|
|
|
1172
1178
|
- `snipara-companion team-sync resume` = reloads local carryover plus the hosted latest handoff and checkpoint-aware resume guidance when available
|
|
1173
1179
|
- `snipara-companion final-commit` / `workflow final-commit` = final hosted commit for the managed workflow
|
|
1174
1180
|
- `snipara-companion code callers/imports/neighbors/shortest-path/impact` = primary code graph surface for agents with shell access. These commands use `--source auto` by default; clean configured checkouts use hosted MCP, dirty/ahead worktrees use the local overlay, and every response reports `sourceSelection` plus agent guidance.
|
|
1175
|
-
- `snipara-companion code symbol-card` = direct
|
|
1181
|
+
- `snipara-companion code symbol-card` = direct `snipara_code_symbol_card` for an important symbol before editing, with an agent guidance summary before raw JSON
|
|
1176
1182
|
- `snipara-companion code impact --source hosted|local` = optional source override for debugging; normal agent instructions should leave `--source auto` in place. Hosted `snipara_code_impact` is the fallback when companion is unavailable or the canonical graph check after push/reindex.
|
|
1177
1183
|
- `snipara-companion code local impact` = explicit repository-local file-level import impact from the local code overlay; keep this for power-user/debug workflows, and use `workflow impact-gate` when the file set should come from unpushed workflow commits
|
|
1178
1184
|
- `snipara-companion doctor` = local readiness check for companion version skew, Snipara auth, deterministic hosted tool catalog access, Snipara Sandbox, Snipara Sandbox MCP wiring, provider keys, and Docker
|