snipara-companion 3.2.8 → 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 +511 -67
- 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) {
|
|
@@ -17121,6 +17266,12 @@ function scoreBootstrapBriefEntry(entry, source2, now) {
|
|
|
17121
17266
|
}
|
|
17122
17267
|
if (type === "decision") {
|
|
17123
17268
|
score += 25;
|
|
17269
|
+
const authorityStatus = bootstrapAuthorityStatus(entry);
|
|
17270
|
+
if (authorityStatus === "canonical") {
|
|
17271
|
+
score += 55;
|
|
17272
|
+
} else if (authorityStatus === "approved" || authorityStatus === "authoritative") {
|
|
17273
|
+
score += 20;
|
|
17274
|
+
}
|
|
17124
17275
|
} else if (type === "context") {
|
|
17125
17276
|
score += 20;
|
|
17126
17277
|
} else if (type === "learning") {
|
|
@@ -17166,6 +17317,89 @@ function scoreBootstrapBriefEntry(entry, source2, now) {
|
|
|
17166
17317
|
function estimateBootstrapEntryTokens(entry) {
|
|
17167
17318
|
return Math.max(8, Math.ceil(compactSessionEntryLine(entry).length / 4));
|
|
17168
17319
|
}
|
|
17320
|
+
function bootstrapEntryType(entry) {
|
|
17321
|
+
return typeof entry.type === "string" ? entry.type.toLowerCase() : "";
|
|
17322
|
+
}
|
|
17323
|
+
function isBootstrapDecisionEntry(entry) {
|
|
17324
|
+
return bootstrapEntryType(entry) === "decision";
|
|
17325
|
+
}
|
|
17326
|
+
function bootstrapAuthorityStatus(entry) {
|
|
17327
|
+
const authority = isRecord9(entry.authority) ? entry.authority : void 0;
|
|
17328
|
+
return (stringValue7(entry.authority_status) ?? stringValue7(authority?.authorityStatus) ?? stringValue7(authority?.level) ?? "").toLowerCase();
|
|
17329
|
+
}
|
|
17330
|
+
function bootstrapSimilarityTokens(entry) {
|
|
17331
|
+
const stopWords = /* @__PURE__ */ new Set([
|
|
17332
|
+
"checkpoint",
|
|
17333
|
+
"workflow",
|
|
17334
|
+
"final",
|
|
17335
|
+
"commit",
|
|
17336
|
+
"phase",
|
|
17337
|
+
"summary",
|
|
17338
|
+
"context",
|
|
17339
|
+
"team",
|
|
17340
|
+
"sync",
|
|
17341
|
+
"handoff",
|
|
17342
|
+
"released",
|
|
17343
|
+
"release"
|
|
17344
|
+
]);
|
|
17345
|
+
const text = readSessionEntryPreview(entry).toLowerCase().replace(/snipara-companion@\d+\.\d+\.\d+/g, "snipara-companion").replace(/[^a-z0-9]+/g, " ");
|
|
17346
|
+
return new Set(text.split(/\s+/).filter((token) => token.length >= 4 && !stopWords.has(token)));
|
|
17347
|
+
}
|
|
17348
|
+
function buildBootstrapTopicTokens(ranked) {
|
|
17349
|
+
const tokens = /* @__PURE__ */ new Set();
|
|
17350
|
+
for (const candidate of ranked) {
|
|
17351
|
+
if (tokens.size >= 48) {
|
|
17352
|
+
break;
|
|
17353
|
+
}
|
|
17354
|
+
if (candidate.score <= 0 || !isSessionCarryoverEntry(candidate.entry)) {
|
|
17355
|
+
continue;
|
|
17356
|
+
}
|
|
17357
|
+
for (const token of bootstrapSimilarityTokens(candidate.entry)) {
|
|
17358
|
+
tokens.add(token);
|
|
17359
|
+
}
|
|
17360
|
+
}
|
|
17361
|
+
return tokens;
|
|
17362
|
+
}
|
|
17363
|
+
function isDecisionRelevantToBootstrap(entry, topicTokens, hasCarryoverCandidate) {
|
|
17364
|
+
if (!isBootstrapDecisionEntry(entry)) {
|
|
17365
|
+
return false;
|
|
17366
|
+
}
|
|
17367
|
+
if (!hasCarryoverCandidate) {
|
|
17368
|
+
return true;
|
|
17369
|
+
}
|
|
17370
|
+
const text = readBootstrapEntryText(entry).toLowerCase();
|
|
17371
|
+
const hasExplicitTopic = text.includes("control plane") || text.includes("control-plane") || text.includes("lite") || text.includes("session-bootstrap") || text.includes("bootstrap brief");
|
|
17372
|
+
if (hasExplicitTopic) {
|
|
17373
|
+
return true;
|
|
17374
|
+
}
|
|
17375
|
+
const category = typeof entry.category === "string" ? entry.category.toLowerCase() : "";
|
|
17376
|
+
if (category.includes("workflow-phase") || category.includes("final-commit") || category.includes("journal:") || category.includes("team_sync")) {
|
|
17377
|
+
return false;
|
|
17378
|
+
}
|
|
17379
|
+
let overlap = 0;
|
|
17380
|
+
for (const token of bootstrapSimilarityTokens(entry)) {
|
|
17381
|
+
if (topicTokens.has(token)) {
|
|
17382
|
+
overlap += 1;
|
|
17383
|
+
}
|
|
17384
|
+
}
|
|
17385
|
+
return overlap >= 3;
|
|
17386
|
+
}
|
|
17387
|
+
function areBootstrapEntriesSimilar(a, b) {
|
|
17388
|
+
const aTokens = bootstrapSimilarityTokens(a);
|
|
17389
|
+
const bTokens = bootstrapSimilarityTokens(b);
|
|
17390
|
+
if (aTokens.size === 0 || bTokens.size === 0) {
|
|
17391
|
+
return false;
|
|
17392
|
+
}
|
|
17393
|
+
let overlap = 0;
|
|
17394
|
+
for (const token of aTokens) {
|
|
17395
|
+
if (bTokens.has(token)) {
|
|
17396
|
+
overlap += 1;
|
|
17397
|
+
}
|
|
17398
|
+
}
|
|
17399
|
+
const smaller = Math.min(aTokens.size, bTokens.size);
|
|
17400
|
+
const larger = Math.max(aTokens.size, bTokens.size);
|
|
17401
|
+
return overlap / smaller >= 0.6 || overlap >= 8 && overlap / larger >= 0.5;
|
|
17402
|
+
}
|
|
17169
17403
|
function buildSessionBootstrapBrief(result, options) {
|
|
17170
17404
|
const normalized = normalizeSessionMemoriesResult(result);
|
|
17171
17405
|
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
@@ -17184,8 +17418,17 @@ function buildSessionBootstrapBrief(result, options) {
|
|
|
17184
17418
|
const hasFreshCandidate = ranked.some(
|
|
17185
17419
|
(candidate) => candidate.score > 0 && !isLikelyStaleBootstrapEntry(candidate.entry, now) && !isLikelyTestMemory(candidate.entry)
|
|
17186
17420
|
);
|
|
17421
|
+
const topicTokens = buildBootstrapTopicTokens(ranked);
|
|
17422
|
+
const hasCarryoverCandidate = ranked.some(
|
|
17423
|
+
(candidate) => candidate.score > 0 && isSessionCarryoverEntry(candidate.entry) && !isLikelyStaleBootstrapEntry(candidate.entry, now) && !isLikelyTestMemory(candidate.entry)
|
|
17424
|
+
);
|
|
17425
|
+
const hasFreshDecisionCandidate = maxEntries >= 4 && ranked.some(
|
|
17426
|
+
(candidate) => candidate.score > 0 && isDecisionRelevantToBootstrap(candidate.entry, topicTokens, hasCarryoverCandidate) && !isLikelyStaleBootstrapEntry(candidate.entry, now) && !isLikelyTestMemory(candidate.entry)
|
|
17427
|
+
);
|
|
17187
17428
|
const entries = [];
|
|
17188
17429
|
let estimatedTokens = 0;
|
|
17430
|
+
let selectedCarryoverCount = 0;
|
|
17431
|
+
let selectedDecisionCount = 0;
|
|
17189
17432
|
for (const candidate of ranked) {
|
|
17190
17433
|
if (hasFreshCandidate && (isLikelyStaleBootstrapEntry(candidate.entry, now) || isLikelyTestMemory(candidate.entry))) {
|
|
17191
17434
|
continue;
|
|
@@ -17196,13 +17439,30 @@ function buildSessionBootstrapBrief(result, options) {
|
|
|
17196
17439
|
if (seen.has(key)) {
|
|
17197
17440
|
continue;
|
|
17198
17441
|
}
|
|
17199
|
-
|
|
17442
|
+
if (entries.some((entry) => areBootstrapEntriesSimilar(entry, candidate.entry))) {
|
|
17443
|
+
continue;
|
|
17444
|
+
}
|
|
17445
|
+
const isCarryover = isSessionCarryoverEntry(candidate.entry);
|
|
17446
|
+
const isDecision = isBootstrapDecisionEntry(candidate.entry);
|
|
17447
|
+
if (isDecision && !isDecisionRelevantToBootstrap(candidate.entry, topicTokens, hasCarryoverCandidate)) {
|
|
17448
|
+
continue;
|
|
17449
|
+
}
|
|
17450
|
+
if (hasFreshDecisionCandidate && selectedDecisionCount === 0 && isCarryover && selectedCarryoverCount >= maxEntries - 1) {
|
|
17451
|
+
continue;
|
|
17452
|
+
}
|
|
17200
17453
|
const entryTokens = estimateBootstrapEntryTokens(candidate.entry);
|
|
17201
17454
|
if (entries.length > 0 && estimatedTokens + entryTokens > budgetTokens) {
|
|
17202
17455
|
continue;
|
|
17203
17456
|
}
|
|
17457
|
+
seen.add(key);
|
|
17204
17458
|
entries.push(candidate.entry);
|
|
17205
17459
|
estimatedTokens += entryTokens;
|
|
17460
|
+
if (isCarryover) {
|
|
17461
|
+
selectedCarryoverCount += 1;
|
|
17462
|
+
}
|
|
17463
|
+
if (isDecision) {
|
|
17464
|
+
selectedDecisionCount += 1;
|
|
17465
|
+
}
|
|
17206
17466
|
if (entries.length >= maxEntries) {
|
|
17207
17467
|
break;
|
|
17208
17468
|
}
|
|
@@ -17835,7 +18095,7 @@ function buildProducerLoopArtifact(options) {
|
|
|
17835
18095
|
workflowId ?? "unmanaged",
|
|
17836
18096
|
options.phase?.id ? `phase:${options.phase.id}` : "final"
|
|
17837
18097
|
].join(":");
|
|
17838
|
-
const reasonCodes =
|
|
18098
|
+
const reasonCodes = uniqueStrings14([
|
|
17839
18099
|
"producer_loop_v0",
|
|
17840
18100
|
options.kind,
|
|
17841
18101
|
`outcome_${options.outcome}`,
|
|
@@ -18027,8 +18287,8 @@ function summarizeProducerLoopArtifactFile(filePath, cwd) {
|
|
|
18027
18287
|
relativePath: relativePath2,
|
|
18028
18288
|
artifactHash: `sha256:${hashContent(content)}`,
|
|
18029
18289
|
ledgerHash: stringValue7(parsed.ledgerHash),
|
|
18030
|
-
reasonCodes:
|
|
18031
|
-
files:
|
|
18290
|
+
reasonCodes: uniqueStrings14(stringArrayValue(ledger?.reasonCodes)),
|
|
18291
|
+
files: uniqueStrings14(stringArrayValue(producer.files)),
|
|
18032
18292
|
calibrationStatus: stringValue7(calibration?.status),
|
|
18033
18293
|
reviewStatus,
|
|
18034
18294
|
reviewOutcome: stringValue7(review?.outcome),
|
|
@@ -18075,10 +18335,10 @@ function buildProducerLoopReport(options = {}) {
|
|
|
18075
18335
|
(left, right) => left.generatedAt === right.generatedAt ? left.relativePath.localeCompare(right.relativePath) : left.generatedAt.localeCompare(right.generatedAt)
|
|
18076
18336
|
);
|
|
18077
18337
|
const invalidArtifacts = summaries.map((entry) => entry.invalid).filter((entry) => Boolean(entry));
|
|
18078
|
-
const producerKinds =
|
|
18338
|
+
const producerKinds = uniqueStrings14(artifacts.map((artifact) => artifact.producerKind)).filter(
|
|
18079
18339
|
(kind) => isProducerLoopProducerKind(kind)
|
|
18080
18340
|
);
|
|
18081
|
-
const workflowIds =
|
|
18341
|
+
const workflowIds = uniqueStrings14(
|
|
18082
18342
|
artifacts.map((artifact) => artifact.workflowId).filter((id) => Boolean(id))
|
|
18083
18343
|
);
|
|
18084
18344
|
const reasonCodeCounts = countStringOccurrences(
|
|
@@ -18229,7 +18489,7 @@ function readProducerLoopArtifactForReview(filePath) {
|
|
|
18229
18489
|
return parsed;
|
|
18230
18490
|
}
|
|
18231
18491
|
function applyProducerLoopArtifactReview(artifact, options) {
|
|
18232
|
-
const reviewNotes =
|
|
18492
|
+
const reviewNotes = uniqueStrings14(options.notes ?? []);
|
|
18233
18493
|
const reviewNote = options.status === "sample_rejected" ? "Sample rejected by local operator review." : "Sample reviewed by local operator.";
|
|
18234
18494
|
const existingCalibration = artifact.calibration ?? {
|
|
18235
18495
|
status: "sample_unreviewed",
|
|
@@ -18244,7 +18504,7 @@ function applyProducerLoopArtifactReview(artifact, options) {
|
|
|
18244
18504
|
status: options.status,
|
|
18245
18505
|
sampleSize: 1,
|
|
18246
18506
|
hardGateReady: false,
|
|
18247
|
-
notes:
|
|
18507
|
+
notes: uniqueStrings14([
|
|
18248
18508
|
...stringArrayValue(existingCalibration.notes),
|
|
18249
18509
|
reviewNote,
|
|
18250
18510
|
...reviewNotes.map((note) => `Review note: ${note}`)
|
|
@@ -18459,7 +18719,7 @@ function applyDecisionRequestLocally(options) {
|
|
|
18459
18719
|
reject: isRejectChoice(options.choice),
|
|
18460
18720
|
outcome: isRejectChoice(options.choice) ? "false_positive" : "useful",
|
|
18461
18721
|
reviewer: options.reviewer,
|
|
18462
|
-
notes:
|
|
18722
|
+
notes: uniqueStrings14([
|
|
18463
18723
|
`decision_request:${request.requestId}`,
|
|
18464
18724
|
...options.note ? [options.note] : []
|
|
18465
18725
|
])
|
|
@@ -18482,7 +18742,7 @@ function recurringPolicySuggestionTargetCategory(request) {
|
|
|
18482
18742
|
const metadata = isRecord9(item.metadata) ? item.metadata : void 0;
|
|
18483
18743
|
return stringValue7(metadata?.category) ?? stringValue7(metadata?.type) ?? item.kind;
|
|
18484
18744
|
}).filter((value) => Boolean(value)) ?? [];
|
|
18485
|
-
return
|
|
18745
|
+
return uniqueStrings14(evidenceCategories).sort().join("|") || request.evidence.applyPath || request.decision;
|
|
18486
18746
|
}
|
|
18487
18747
|
function buildRecurringDecisionPolicySuggestionRequest(resolvedRecords) {
|
|
18488
18748
|
const grouped = /* @__PURE__ */ new Map();
|
|
@@ -18520,12 +18780,12 @@ function buildRecurringDecisionPolicySuggestionRequest(resolvedRecords) {
|
|
|
18520
18780
|
status: record.response.choice,
|
|
18521
18781
|
files: record.request.evidence.files?.slice(0, 12)
|
|
18522
18782
|
})),
|
|
18523
|
-
reasonCodes:
|
|
18783
|
+
reasonCodes: uniqueStrings14([
|
|
18524
18784
|
"recurring_decision_receipts",
|
|
18525
18785
|
"never_ask_twice_candidate",
|
|
18526
18786
|
...latest.request.evidence.reasonCodes
|
|
18527
18787
|
]),
|
|
18528
|
-
files:
|
|
18788
|
+
files: uniqueStrings14(repeated.flatMap((record) => record.request.evidence.files ?? [])),
|
|
18529
18789
|
applyPath: "manual_context_review",
|
|
18530
18790
|
applyCommand: "Review the suggested rule and add it to the appropriate project policy or AGENTS.md section manually."
|
|
18531
18791
|
},
|
|
@@ -18667,12 +18927,12 @@ function buildProducerTriageRequest(report) {
|
|
|
18667
18927
|
summary: `${candidates.length} unreviewed Producer Loop samples; ${report.invalidArtifacts.length} invalid artifacts; hardGateReady remains false.`,
|
|
18668
18928
|
refs,
|
|
18669
18929
|
items,
|
|
18670
|
-
reasonCodes:
|
|
18930
|
+
reasonCodes: uniqueStrings14([
|
|
18671
18931
|
"triage_rules_v0",
|
|
18672
18932
|
"producer_loop_report_valid",
|
|
18673
18933
|
...report.invalidArtifacts.length === 0 ? ["no_invalid_artifacts"] : ["invalid_artifacts_present"]
|
|
18674
18934
|
]),
|
|
18675
|
-
files:
|
|
18935
|
+
files: uniqueStrings14(candidates.flatMap((artifact) => artifact.files)),
|
|
18676
18936
|
applyPath: "workflow producer-review",
|
|
18677
18937
|
applyCommand: "snipara-companion workflow decide <request-id> --choose accept_all --reviewer <name>"
|
|
18678
18938
|
},
|
|
@@ -20448,8 +20708,8 @@ async function enrichAdaptiveRoutingWithHostedCatalog(client, routing) {
|
|
|
20448
20708
|
runtimeCatalog: catalog,
|
|
20449
20709
|
routingCard: {
|
|
20450
20710
|
...routing.routingCard,
|
|
20451
|
-
reasons:
|
|
20452
|
-
warnings:
|
|
20711
|
+
reasons: uniqueStrings14(reasons),
|
|
20712
|
+
warnings: uniqueStrings14([...routing.routingCard.warnings, ...gatewayWarnings])
|
|
20453
20713
|
}
|
|
20454
20714
|
};
|
|
20455
20715
|
} catch (error) {
|
|
@@ -20466,7 +20726,7 @@ async function enrichAdaptiveRoutingWithHostedCatalog(client, routing) {
|
|
|
20466
20726
|
},
|
|
20467
20727
|
routingCard: {
|
|
20468
20728
|
...routing.routingCard,
|
|
20469
|
-
warnings:
|
|
20729
|
+
warnings: uniqueStrings14([...routing.routingCard.warnings, warning])
|
|
20470
20730
|
}
|
|
20471
20731
|
};
|
|
20472
20732
|
}
|
|
@@ -20657,7 +20917,7 @@ function enrichAdaptiveRoutingWithLocalOrchestrator(routing, options, cwd = proc
|
|
|
20657
20917
|
const approvalRequired = booleanValue4(
|
|
20658
20918
|
isRecord9(resolution?.policyDecision) ? resolution.policyDecision.approvalRequired : void 0
|
|
20659
20919
|
);
|
|
20660
|
-
const gatewayWarnings =
|
|
20920
|
+
const gatewayWarnings = uniqueStrings14([
|
|
20661
20921
|
...resolutionWarnings,
|
|
20662
20922
|
...selectedCandidate ? [] : ["Local orchestrator did not select a worker candidate and will fail closed."]
|
|
20663
20923
|
]);
|
|
@@ -20679,7 +20939,7 @@ function enrichAdaptiveRoutingWithLocalOrchestrator(routing, options, cwd = proc
|
|
|
20679
20939
|
...selectedCandidate?.workerClass ? { recommendedWorkerClass: selectedCandidate.workerClass } : {},
|
|
20680
20940
|
...resolutionRejectedReasons ? { rejectedReasons: resolutionRejectedReasons } : {},
|
|
20681
20941
|
...approvalRequired !== void 0 ? { humanApprovalRequired: approvalRequired } : {},
|
|
20682
|
-
reasons:
|
|
20942
|
+
reasons: uniqueStrings14([
|
|
20683
20943
|
...routing.routingCard.reasons,
|
|
20684
20944
|
...resolutionReasons,
|
|
20685
20945
|
...selectedCandidate ? [
|
|
@@ -20688,7 +20948,7 @@ function enrichAdaptiveRoutingWithLocalOrchestrator(routing, options, cwd = proc
|
|
|
20688
20948
|
...stringValue7(selectedEndpoint?.model) ? [`selected local model ${String(selectedEndpoint?.model)}`] : []
|
|
20689
20949
|
] : ["local orchestrator could not resolve a concrete worker candidate"]
|
|
20690
20950
|
]),
|
|
20691
|
-
warnings:
|
|
20951
|
+
warnings: uniqueStrings14([...routing.routingCard.warnings, ...gatewayWarnings])
|
|
20692
20952
|
}
|
|
20693
20953
|
};
|
|
20694
20954
|
} catch (error) {
|
|
@@ -20705,7 +20965,7 @@ function enrichAdaptiveRoutingWithLocalOrchestrator(routing, options, cwd = proc
|
|
|
20705
20965
|
},
|
|
20706
20966
|
routingCard: {
|
|
20707
20967
|
...routing.routingCard,
|
|
20708
|
-
warnings:
|
|
20968
|
+
warnings: uniqueStrings14([...routing.routingCard.warnings, warning])
|
|
20709
20969
|
}
|
|
20710
20970
|
};
|
|
20711
20971
|
}
|
|
@@ -22574,8 +22834,8 @@ function buildWorkflowAdaptiveRouting(options, policy = null, intentWarnings = [
|
|
|
22574
22834
|
...routing,
|
|
22575
22835
|
routingCard: {
|
|
22576
22836
|
...routing.routingCard,
|
|
22577
|
-
reasons:
|
|
22578
|
-
warnings:
|
|
22837
|
+
reasons: uniqueStrings14([...routing.routingCard.reasons, ...policyReasons]),
|
|
22838
|
+
warnings: uniqueStrings14([...routing.routingCard.warnings, ...policyWarnings])
|
|
22579
22839
|
}
|
|
22580
22840
|
};
|
|
22581
22841
|
}
|
|
@@ -22591,7 +22851,7 @@ function normalizeAdaptiveRoutingMode(value) {
|
|
|
22591
22851
|
return normalized === "off" || normalized === "recommend" || normalized === "catalog" ? normalized : null;
|
|
22592
22852
|
}
|
|
22593
22853
|
function normalizeAdaptiveWorkerClasses(values) {
|
|
22594
|
-
return
|
|
22854
|
+
return uniqueStrings14((values ?? []).map(canonicalAdaptiveWorkerClass)).filter(
|
|
22595
22855
|
(value) => ["documentation", "tests", "review", "coding"].includes(value)
|
|
22596
22856
|
);
|
|
22597
22857
|
}
|
|
@@ -23891,7 +24151,25 @@ async function loadDocumentCommand(options) {
|
|
|
23891
24151
|
printLoadDocumentResult(options.path, result);
|
|
23892
24152
|
}
|
|
23893
24153
|
async function sessionBootstrapCommand(options) {
|
|
23894
|
-
|
|
24154
|
+
if (!isConfigured()) {
|
|
24155
|
+
if (options.json) {
|
|
24156
|
+
printJson2({
|
|
24157
|
+
critical: { memories: [], count: 0, tokens: 0 },
|
|
24158
|
+
daily: { memories: [], count: 0, tokens: 0 },
|
|
24159
|
+
total_tokens: 0,
|
|
24160
|
+
session_context: {
|
|
24161
|
+
included: Boolean(options.includeSessionContext),
|
|
24162
|
+
max_tokens: options.includeSessionContext ? DEFAULT_SESSION_CONTEXT_TOKENS : 0
|
|
24163
|
+
},
|
|
24164
|
+
session_bootstrap_quality: buildSessionBootstrapQuality({
|
|
24165
|
+
critical: { memories: [], count: 0, tokens: 0 },
|
|
24166
|
+
daily: { memories: [], count: 0, tokens: 0 },
|
|
24167
|
+
total_tokens: 0
|
|
24168
|
+
})
|
|
24169
|
+
});
|
|
24170
|
+
}
|
|
24171
|
+
return;
|
|
24172
|
+
}
|
|
23895
24173
|
const resolvedContextTokens = options.maxContextTokens !== void 0 ? options.maxContextTokens : options.includeSessionContext ? DEFAULT_SESSION_CONTEXT_TOKENS : 0;
|
|
23896
24174
|
const client = createClient(15e3);
|
|
23897
24175
|
const result = await client.getSessionMemories(options.maxCriticalTokens, resolvedContextTokens);
|
|
@@ -26800,7 +27078,7 @@ function normalizeCaptureEvent(event, now, index) {
|
|
|
26800
27078
|
const reasons = normalizeStringList4(event.reason).map(redactText);
|
|
26801
27079
|
const evidence = normalizeStringList4(event.evidence).map(redactText);
|
|
26802
27080
|
const commands = normalizeStringList4(event.commands).map(redactText);
|
|
26803
|
-
const redactionPatterns =
|
|
27081
|
+
const redactionPatterns = uniqueStrings15([
|
|
26804
27082
|
...summary.patterns,
|
|
26805
27083
|
...outcome.patterns,
|
|
26806
27084
|
...status.patterns,
|
|
@@ -26833,7 +27111,7 @@ function normalizeEventKind(value) {
|
|
|
26833
27111
|
return "feedback";
|
|
26834
27112
|
}
|
|
26835
27113
|
function reasonCodesForEvent(event, kind, status) {
|
|
26836
|
-
return
|
|
27114
|
+
return uniqueStrings15([
|
|
26837
27115
|
"why_outcome_capture_v1",
|
|
26838
27116
|
"review_pending_authority",
|
|
26839
27117
|
`source_${event.kind}`,
|
|
@@ -26898,7 +27176,7 @@ function readEventsFromFile(filePath) {
|
|
|
26898
27176
|
function stableHash2(parts) {
|
|
26899
27177
|
return (0, import_node_crypto8.createHash)("sha256").update(parts.join("\0")).digest("hex");
|
|
26900
27178
|
}
|
|
26901
|
-
function
|
|
27179
|
+
function uniqueStrings15(values) {
|
|
26902
27180
|
return Array.from(new Set(values.filter(Boolean)));
|
|
26903
27181
|
}
|
|
26904
27182
|
function compactWhitespace3(value) {
|
|
@@ -28149,6 +28427,108 @@ function actionList(value) {
|
|
|
28149
28427
|
return reason ? `${priority}${preview3(title, 80)} - ${preview3(reason, 140)}` : `${priority}${preview3(title, 160)}`;
|
|
28150
28428
|
}).filter(Boolean);
|
|
28151
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
|
+
}
|
|
28152
28532
|
function buildSuggestedCommands2(args) {
|
|
28153
28533
|
const commands = [
|
|
28154
28534
|
"snipara-companion team-sync what-changed",
|
|
@@ -28241,6 +28621,16 @@ async function buildProjectIntelligenceBrief(options) {
|
|
|
28241
28621
|
});
|
|
28242
28622
|
}
|
|
28243
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
|
+
}
|
|
28244
28634
|
brief.verificationPlan = buildVerificationPlan({
|
|
28245
28635
|
task: options.task,
|
|
28246
28636
|
changedFiles,
|
|
@@ -28406,6 +28796,19 @@ async function projectIntelligenceBriefCommand(options) {
|
|
|
28406
28796
|
console.log(import_chalk9.default.bold("Memory Authority And Health"));
|
|
28407
28797
|
printMemoryHealth2(brief.memoryHealth);
|
|
28408
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
|
+
}
|
|
28409
28812
|
console.log(import_chalk9.default.bold("Code Impact"));
|
|
28410
28813
|
if (brief.codeImpactSourceSelection) {
|
|
28411
28814
|
console.log(
|
|
@@ -29113,9 +29516,46 @@ function gateSummary(gates) {
|
|
|
29113
29516
|
function packageReviewCommand2(input) {
|
|
29114
29517
|
return input.packageReview?.command ?? "npm view snipara-companion version bin dist-tags --json";
|
|
29115
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
|
+
}
|
|
29116
29525
|
function evaluateProjectPolicyGates(input) {
|
|
29117
29526
|
const changedFiles = normalizeChangedFiles(input.changedFiles);
|
|
29118
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
|
+
}
|
|
29119
29559
|
if (input.release) {
|
|
29120
29560
|
gates.push(
|
|
29121
29561
|
gate({
|
|
@@ -29374,6 +29814,7 @@ function evaluateProjectPolicyGates(input) {
|
|
|
29374
29814
|
release: Boolean(input.release),
|
|
29375
29815
|
summary,
|
|
29376
29816
|
gates,
|
|
29817
|
+
...projectPolicyDecision ? { projectPolicyDecision } : {},
|
|
29377
29818
|
suggestedCommands: suggestedCommands3
|
|
29378
29819
|
};
|
|
29379
29820
|
}
|
|
@@ -29878,7 +30319,10 @@ async function buildProjectIntelligenceRun(options) {
|
|
|
29878
30319
|
skipPackageReview: options.skipPackageReview,
|
|
29879
30320
|
guard,
|
|
29880
30321
|
packageReview,
|
|
29881
|
-
judgmentCard
|
|
30322
|
+
judgmentCard,
|
|
30323
|
+
projectPolicy: brief.projectPolicyDecision ? {
|
|
30324
|
+
decision: brief.projectPolicyDecision
|
|
30325
|
+
} : void 0
|
|
29882
30326
|
});
|
|
29883
30327
|
const verificationEvidence = verificationEvidenceFromRun({
|
|
29884
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
|