snipara-companion 3.0.8 → 3.0.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.js +330 -88
- package/docs/FULL_REFERENCE.md +10 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9750,15 +9750,15 @@ function parseEnvLine(line) {
|
|
|
9750
9750
|
return null;
|
|
9751
9751
|
}
|
|
9752
9752
|
const withoutExport = withoutWhitespace.startsWith("export ") ? withoutWhitespace.slice("export ".length).trim() : withoutWhitespace;
|
|
9753
|
-
const
|
|
9754
|
-
if (
|
|
9753
|
+
const separatorIndex2 = withoutExport.indexOf("=");
|
|
9754
|
+
if (separatorIndex2 <= 0) {
|
|
9755
9755
|
return null;
|
|
9756
9756
|
}
|
|
9757
|
-
const key = withoutExport.slice(0,
|
|
9757
|
+
const key = withoutExport.slice(0, separatorIndex2).trim();
|
|
9758
9758
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
|
|
9759
9759
|
return null;
|
|
9760
9760
|
}
|
|
9761
|
-
const value = parseEnvValue(withoutExport.slice(
|
|
9761
|
+
const value = parseEnvValue(withoutExport.slice(separatorIndex2 + 1).trim());
|
|
9762
9762
|
return { key, value };
|
|
9763
9763
|
}
|
|
9764
9764
|
function parseEnvValue(rawValue) {
|
|
@@ -19612,7 +19612,7 @@ async function agentReadinessAuditCommand(options) {
|
|
|
19612
19612
|
var fs21 = __toESM(require("fs"));
|
|
19613
19613
|
var path20 = __toESM(require("path"));
|
|
19614
19614
|
|
|
19615
|
-
// ../project-intelligence-contracts/src/
|
|
19615
|
+
// ../project-intelligence-contracts/src/engineering-lead.ts
|
|
19616
19616
|
var PROJECT_HEALTH_COCKPIT_STATUSES = ["healthy", "watch", "risk", "unknown"];
|
|
19617
19617
|
var PROJECT_INTELLIGENCE_ENGINEERING_LEAD_PLAN_VERSION = "project-intelligence-engineering-lead-plan-v0";
|
|
19618
19618
|
var PROJECT_INTELLIGENCE_ENGINEERING_LEAD_CONTRACT_VERSION = "engineering-lead-contract-v1";
|
|
@@ -19686,9 +19686,8 @@ var PROJECT_INTELLIGENCE_ENGINEERING_LEAD_PROOF_VERIFICATION_SOURCES = [
|
|
|
19686
19686
|
"manual",
|
|
19687
19687
|
"unknown"
|
|
19688
19688
|
];
|
|
19689
|
-
|
|
19690
|
-
|
|
19691
|
-
var PROJECT_UNKNOWN_REGISTRY_VERSION = "unknown-registry-v1";
|
|
19689
|
+
|
|
19690
|
+
// ../project-intelligence-contracts/src/shared.ts
|
|
19692
19691
|
var SENSITIVE_SURFACES = [
|
|
19693
19692
|
{
|
|
19694
19693
|
key: "billing_atomicity",
|
|
@@ -19764,23 +19763,11 @@ function hasPattern(values, patterns) {
|
|
|
19764
19763
|
function matchesAnyText(text, patterns) {
|
|
19765
19764
|
return patterns.some((pattern) => pattern.test(text));
|
|
19766
19765
|
}
|
|
19767
|
-
function
|
|
19768
|
-
if (severity === "blocking") return 0;
|
|
19769
|
-
if (severity === "review_required") return 30;
|
|
19770
|
-
if (severity === "watch") return 70;
|
|
19771
|
-
return 90;
|
|
19772
|
-
}
|
|
19773
|
-
function resultStatusFromFindings(findings) {
|
|
19774
|
-
if (findings.some((finding) => finding.severity === "blocking")) return "blocking";
|
|
19775
|
-
if (findings.some((finding) => finding.severity === "review_required")) return "review_required";
|
|
19776
|
-
if (findings.some((finding) => finding.severity === "watch")) return "advisory";
|
|
19777
|
-
return "pass";
|
|
19778
|
-
}
|
|
19779
|
-
function makeFindingId(type, key, files) {
|
|
19766
|
+
function makeScopedId(prefix, type, key, files) {
|
|
19780
19767
|
const compactFiles = files.slice(0, 3).map(
|
|
19781
19768
|
(file) => file.replace(/[^a-z0-9]+/gi, "-").replace(/^-|-$/g, "").toLowerCase()
|
|
19782
19769
|
).filter(Boolean).join("-");
|
|
19783
|
-
return [
|
|
19770
|
+
return [prefix, type, key, compactFiles || "project"].join(":").slice(0, 180);
|
|
19784
19771
|
}
|
|
19785
19772
|
function decisionMatchesChangedFiles(decision, changedFiles) {
|
|
19786
19773
|
const anchors = decision.affectedAnchors ?? [];
|
|
@@ -19795,7 +19782,15 @@ function decisionText(decision) {
|
|
|
19795
19782
|
decision.decision,
|
|
19796
19783
|
decision.rationale,
|
|
19797
19784
|
decision.scope,
|
|
19798
|
-
|
|
19785
|
+
decision.owner,
|
|
19786
|
+
...decision.constraints ?? [],
|
|
19787
|
+
...decision.antiGoals ?? [],
|
|
19788
|
+
...decision.rejectedAlternatives ?? [],
|
|
19789
|
+
decision.intent?.goal,
|
|
19790
|
+
decision.intent?.owner,
|
|
19791
|
+
...decision.intent?.constraints ?? [],
|
|
19792
|
+
...decision.intent?.antiGoals ?? [],
|
|
19793
|
+
...decision.intent?.rejectedAlternatives ?? []
|
|
19799
19794
|
].filter(Boolean).join(" ");
|
|
19800
19795
|
}
|
|
19801
19796
|
function confidenceBand(score) {
|
|
@@ -19807,12 +19802,83 @@ function normalizeConfidenceScore(value, fallback) {
|
|
|
19807
19802
|
if (typeof value !== "number" || Number.isNaN(value)) return fallback;
|
|
19808
19803
|
return Math.max(0, Math.min(1, value));
|
|
19809
19804
|
}
|
|
19810
|
-
function
|
|
19811
|
-
const
|
|
19812
|
-
|
|
19813
|
-
|
|
19814
|
-
|
|
19815
|
-
|
|
19805
|
+
function anchorMatchesFile(anchor, file) {
|
|
19806
|
+
const normalizedAnchor = anchor.replace(/^\.\//, "").trim();
|
|
19807
|
+
const normalizedFile = file.replace(/^\.\//, "").trim();
|
|
19808
|
+
return normalizedAnchor.length > 0 && normalizedFile.length > 0 && (normalizedFile.includes(normalizedAnchor) || normalizedAnchor.includes(normalizedFile));
|
|
19809
|
+
}
|
|
19810
|
+
function surfaceFiles(surface, changedFiles) {
|
|
19811
|
+
return changedFiles.filter((file) => surface.patterns.some((pattern) => pattern.test(file)));
|
|
19812
|
+
}
|
|
19813
|
+
|
|
19814
|
+
// ../project-intelligence-contracts/src/intent-ledger.ts
|
|
19815
|
+
var PROJECT_INTENT_LEDGER_VERSION = "intent-ledger-v1";
|
|
19816
|
+
var PROJECT_INTENT_LEDGER_DEFAULT_FRESHNESS_HORIZON_DAYS = 90;
|
|
19817
|
+
var DEFAULT_PROJECT_INTENT_LEDGER_POLICY = {
|
|
19818
|
+
freshnessHorizonDays: PROJECT_INTENT_LEDGER_DEFAULT_FRESHNESS_HORIZON_DAYS
|
|
19819
|
+
};
|
|
19820
|
+
var DECISION_STATUS_ALIASES = {
|
|
19821
|
+
approved: ["approved", "accepted", "active", "confirmed"],
|
|
19822
|
+
review_pending: ["review_pending", "pending_review", "pending", "candidate", "draft"],
|
|
19823
|
+
stale: ["stale", "expired", "deprecated"],
|
|
19824
|
+
superseded: ["superseded", "replaced", "overridden"],
|
|
19825
|
+
contradicted: ["contradicted", "conflicted", "conflict"]
|
|
19826
|
+
};
|
|
19827
|
+
var INTENT_SECTION_ALIASES = {
|
|
19828
|
+
goal: ["goal", "intent", "why", "purpose", "rationale"],
|
|
19829
|
+
constraints: ["constraint", "constraints", "rule", "rules", "must"],
|
|
19830
|
+
antiGoals: ["anti_goal", "anti_goals", "avoid", "forbidden", "do_not"],
|
|
19831
|
+
rejectedAlternatives: [
|
|
19832
|
+
"rejected_alternative",
|
|
19833
|
+
"rejected_alternatives",
|
|
19834
|
+
"rejected",
|
|
19835
|
+
"not_chosen",
|
|
19836
|
+
"alternative_rejected",
|
|
19837
|
+
"alternatives_rejected"
|
|
19838
|
+
],
|
|
19839
|
+
owner: ["owner", "owners"],
|
|
19840
|
+
freshnessHorizonDays: ["freshness_horizon_days", "horizon_days", "staleness_horizon_days"]
|
|
19841
|
+
};
|
|
19842
|
+
var INTENT_DOCUMENT_KIND_TOKENS = [
|
|
19843
|
+
"adr",
|
|
19844
|
+
"decision",
|
|
19845
|
+
"intent",
|
|
19846
|
+
"rationale",
|
|
19847
|
+
"constraint",
|
|
19848
|
+
"architecture",
|
|
19849
|
+
"runbook"
|
|
19850
|
+
];
|
|
19851
|
+
function normalizeIdentifier(value) {
|
|
19852
|
+
const normalized = [];
|
|
19853
|
+
let previousWasSeparator = false;
|
|
19854
|
+
for (const char of value?.trim().toLowerCase() ?? "") {
|
|
19855
|
+
const code2 = char.charCodeAt(0);
|
|
19856
|
+
const isAlphaNumeric = code2 >= 48 && code2 <= 57 || code2 >= 97 && code2 <= 122;
|
|
19857
|
+
if (isAlphaNumeric) {
|
|
19858
|
+
normalized.push(char);
|
|
19859
|
+
previousWasSeparator = false;
|
|
19860
|
+
continue;
|
|
19861
|
+
}
|
|
19862
|
+
if (!previousWasSeparator && normalized.length > 0) {
|
|
19863
|
+
normalized.push("_");
|
|
19864
|
+
previousWasSeparator = true;
|
|
19865
|
+
}
|
|
19866
|
+
}
|
|
19867
|
+
if (normalized[normalized.length - 1] === "_") normalized.pop();
|
|
19868
|
+
return normalized.join("");
|
|
19869
|
+
}
|
|
19870
|
+
function statusFromDecisionStatus(decision) {
|
|
19871
|
+
const status = normalizeIdentifier(decision.status);
|
|
19872
|
+
if (!status) return "review_pending";
|
|
19873
|
+
for (const [ledgerStatus, aliases] of Object.entries(DECISION_STATUS_ALIASES)) {
|
|
19874
|
+
if (aliases.includes(status)) return ledgerStatus;
|
|
19875
|
+
}
|
|
19876
|
+
const statusParts = status.split("_").filter(Boolean);
|
|
19877
|
+
for (const [ledgerStatus, aliases] of Object.entries(DECISION_STATUS_ALIASES)) {
|
|
19878
|
+
if (aliases.some((alias) => statusParts.includes(alias))) {
|
|
19879
|
+
return ledgerStatus;
|
|
19880
|
+
}
|
|
19881
|
+
}
|
|
19816
19882
|
return "review_pending";
|
|
19817
19883
|
}
|
|
19818
19884
|
function intentConfidence(score, status, reasonCodes) {
|
|
@@ -19823,7 +19889,14 @@ function intentConfidence(score, status, reasonCodes) {
|
|
|
19823
19889
|
reasonCodes
|
|
19824
19890
|
};
|
|
19825
19891
|
}
|
|
19826
|
-
function
|
|
19892
|
+
function normalizeFreshnessHorizonDays(value) {
|
|
19893
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return null;
|
|
19894
|
+
return Math.round(value);
|
|
19895
|
+
}
|
|
19896
|
+
function resolveFreshnessHorizonDays(specificValue, policy) {
|
|
19897
|
+
return normalizeFreshnessHorizonDays(specificValue) ?? normalizeFreshnessHorizonDays(policy.freshnessHorizonDays) ?? null;
|
|
19898
|
+
}
|
|
19899
|
+
function stalenessFromStatus(status, freshnessHorizonDays) {
|
|
19827
19900
|
if (status === "stale" || status === "superseded") {
|
|
19828
19901
|
return {
|
|
19829
19902
|
state: "stale",
|
|
@@ -19836,12 +19909,11 @@ function stalenessFromStatus(status) {
|
|
|
19836
19909
|
reason: "The intent has not been reviewed as current project truth."
|
|
19837
19910
|
};
|
|
19838
19911
|
}
|
|
19839
|
-
return {
|
|
19840
|
-
|
|
19841
|
-
|
|
19842
|
-
|
|
19843
|
-
|
|
19844
|
-
return normalizedAnchor.length > 0 && normalizedFile.length > 0 && (normalizedFile.includes(normalizedAnchor) || normalizedAnchor.includes(normalizedFile));
|
|
19912
|
+
return {
|
|
19913
|
+
state: "fresh",
|
|
19914
|
+
horizonDays: freshnessHorizonDays,
|
|
19915
|
+
reason: freshnessHorizonDays === null ? "No freshness horizon was supplied by source metadata or policy." : null
|
|
19916
|
+
};
|
|
19845
19917
|
}
|
|
19846
19918
|
function intentEntryMatchesFile(entry, file) {
|
|
19847
19919
|
return entry.affectedAnchors.some((anchor) => anchorMatchesFile(anchor, file));
|
|
@@ -19855,40 +19927,150 @@ function inferDecisionAnchors(decision, changedFiles) {
|
|
|
19855
19927
|
);
|
|
19856
19928
|
return uniqueStrings8(inferred);
|
|
19857
19929
|
}
|
|
19858
|
-
function
|
|
19930
|
+
function normalizeIntentPhrase(value) {
|
|
19931
|
+
let normalized = value.trim();
|
|
19932
|
+
if (normalized.startsWith("- ") || normalized.startsWith("* ")) {
|
|
19933
|
+
normalized = normalized.slice(2).trim();
|
|
19934
|
+
}
|
|
19935
|
+
const dotIndex = normalized.indexOf(". ");
|
|
19936
|
+
if (dotIndex > 0) {
|
|
19937
|
+
const prefix = normalized.slice(0, dotIndex);
|
|
19938
|
+
if ([...prefix].every((char) => char >= "0" && char <= "9")) {
|
|
19939
|
+
normalized = normalized.slice(dotIndex + 2).trim();
|
|
19940
|
+
}
|
|
19941
|
+
}
|
|
19942
|
+
return normalized;
|
|
19943
|
+
}
|
|
19944
|
+
function splitExplicitIntentList(value) {
|
|
19859
19945
|
if (!value) return [];
|
|
19860
|
-
return uniqueStrings8(
|
|
19861
|
-
|
|
19862
|
-
|
|
19946
|
+
return uniqueStrings8(value.split(";").map(normalizeIntentPhrase).filter(Boolean)).slice(0, 6);
|
|
19947
|
+
}
|
|
19948
|
+
function normalizeIntentList(values) {
|
|
19949
|
+
return uniqueStrings8(values.flatMap((value) => splitExplicitIntentList(value))).slice(0, 8);
|
|
19950
|
+
}
|
|
19951
|
+
function emptyParsedIntentSections() {
|
|
19952
|
+
return {
|
|
19953
|
+
constraints: [],
|
|
19954
|
+
antiGoals: [],
|
|
19955
|
+
rejectedAlternatives: [],
|
|
19956
|
+
sourceFields: []
|
|
19957
|
+
};
|
|
19863
19958
|
}
|
|
19864
|
-
function
|
|
19865
|
-
const
|
|
19866
|
-
|
|
19959
|
+
function intentSectionKey(label) {
|
|
19960
|
+
const normalized = normalizeIdentifier(label);
|
|
19961
|
+
for (const [key, aliases] of Object.entries(INTENT_SECTION_ALIASES)) {
|
|
19962
|
+
if (aliases.includes(normalized)) {
|
|
19963
|
+
return key;
|
|
19964
|
+
}
|
|
19965
|
+
}
|
|
19966
|
+
return void 0;
|
|
19967
|
+
}
|
|
19968
|
+
function separatorIndex(value) {
|
|
19969
|
+
const colon = value.indexOf(":");
|
|
19970
|
+
const equals = value.indexOf("=");
|
|
19971
|
+
if (colon < 0) return equals;
|
|
19972
|
+
if (equals < 0) return colon;
|
|
19973
|
+
return Math.min(colon, equals);
|
|
19974
|
+
}
|
|
19975
|
+
function addSectionValue(parsed, key, value) {
|
|
19976
|
+
const normalizedValue = normalizeIntentPhrase(value);
|
|
19977
|
+
if (!normalizedValue) return;
|
|
19978
|
+
parsed.sourceFields.push(key);
|
|
19979
|
+
if (key === "goal") {
|
|
19980
|
+
parsed.goal = parsed.goal ?? normalizedValue;
|
|
19981
|
+
return;
|
|
19982
|
+
}
|
|
19983
|
+
if (key === "owner") {
|
|
19984
|
+
parsed.owner = parsed.owner ?? normalizedValue;
|
|
19985
|
+
return;
|
|
19986
|
+
}
|
|
19987
|
+
if (key === "freshnessHorizonDays") {
|
|
19988
|
+
parsed.freshnessHorizonDays = parsed.freshnessHorizonDays ?? normalizeFreshnessHorizonDays(Number(normalizedValue));
|
|
19989
|
+
return;
|
|
19990
|
+
}
|
|
19991
|
+
parsed[key].push(...splitExplicitIntentList(normalizedValue));
|
|
19992
|
+
}
|
|
19993
|
+
function parseIntentSections(value) {
|
|
19994
|
+
const parsed = emptyParsedIntentSections();
|
|
19995
|
+
if (!value) return parsed;
|
|
19996
|
+
let currentKey;
|
|
19997
|
+
const lines = value.replaceAll("\r\n", "\n").replaceAll("\r", "\n").split("\n");
|
|
19998
|
+
for (const rawLine of lines) {
|
|
19999
|
+
const line = normalizeIntentPhrase(rawLine);
|
|
20000
|
+
if (!line) continue;
|
|
20001
|
+
const splitAt = separatorIndex(line);
|
|
20002
|
+
if (splitAt > 0) {
|
|
20003
|
+
const maybeKey = intentSectionKey(line.slice(0, splitAt));
|
|
20004
|
+
if (maybeKey) {
|
|
20005
|
+
currentKey = maybeKey;
|
|
20006
|
+
addSectionValue(parsed, maybeKey, line.slice(splitAt + 1));
|
|
20007
|
+
continue;
|
|
20008
|
+
}
|
|
20009
|
+
}
|
|
20010
|
+
if (currentKey && (rawLine.trim().startsWith("- ") || rawLine.trim().startsWith("* "))) {
|
|
20011
|
+
addSectionValue(parsed, currentKey, line);
|
|
20012
|
+
}
|
|
20013
|
+
}
|
|
20014
|
+
return {
|
|
20015
|
+
...parsed,
|
|
20016
|
+
constraints: uniqueStrings8(parsed.constraints).slice(0, 8),
|
|
20017
|
+
antiGoals: uniqueStrings8(parsed.antiGoals).slice(0, 8),
|
|
20018
|
+
rejectedAlternatives: uniqueStrings8(parsed.rejectedAlternatives).slice(0, 8),
|
|
20019
|
+
sourceFields: uniqueStrings8(parsed.sourceFields)
|
|
20020
|
+
};
|
|
20021
|
+
}
|
|
20022
|
+
function hasStructuredIntentFields(intent) {
|
|
20023
|
+
return Boolean(
|
|
20024
|
+
intent?.goal || intent?.owner || intent?.freshnessHorizonDays || (intent?.constraints?.length ?? 0) > 0 || (intent?.antiGoals?.length ?? 0) > 0 || (intent?.rejectedAlternatives?.length ?? 0) > 0
|
|
19867
20025
|
);
|
|
19868
|
-
return uniqueStrings8(matches).slice(0, 5);
|
|
19869
20026
|
}
|
|
19870
|
-
function
|
|
19871
|
-
const
|
|
19872
|
-
|
|
19873
|
-
|
|
19874
|
-
|
|
20027
|
+
function extractionMetadata(input) {
|
|
20028
|
+
const sectionFields = input.structuredSections.sourceFields.map((field) => `section:${field}`);
|
|
20029
|
+
return {
|
|
20030
|
+
mode: input.structuredFields ? "structured_fields" : sectionFields.length > 0 ? "structured_sections" : "legacy_source_fields",
|
|
20031
|
+
sourceFields: uniqueStrings8([
|
|
20032
|
+
input.structuredFields ? "intent" : void 0,
|
|
20033
|
+
...sectionFields
|
|
20034
|
+
]).slice(0, 12),
|
|
20035
|
+
fallbackUsed: input.fallbackUsed
|
|
20036
|
+
};
|
|
20037
|
+
}
|
|
20038
|
+
function textHasAnyToken(value, tokens) {
|
|
20039
|
+
const normalized = normalizeIdentifier(value);
|
|
20040
|
+
const parts = normalized.split("_").filter(Boolean);
|
|
20041
|
+
return tokens.some((token) => parts.includes(token));
|
|
19875
20042
|
}
|
|
19876
20043
|
function documentLooksLikeIntent(doc) {
|
|
19877
|
-
|
|
19878
|
-
|
|
20044
|
+
if (hasStructuredIntentFields(doc.intent)) return true;
|
|
20045
|
+
if (parseIntentSections(doc.contentPreview).sourceFields.length > 0) return true;
|
|
20046
|
+
return [doc.path, doc.title, doc.kind].some(
|
|
20047
|
+
(value) => textHasAnyToken(value ?? "", INTENT_DOCUMENT_KIND_TOKENS)
|
|
20048
|
+
);
|
|
19879
20049
|
}
|
|
19880
|
-
function buildDecisionIntentEntry(decision, changedFiles) {
|
|
19881
|
-
const status =
|
|
20050
|
+
function buildDecisionIntentEntry(decision, changedFiles, policy) {
|
|
20051
|
+
const status = statusFromDecisionStatus(decision);
|
|
19882
20052
|
const anchors = inferDecisionAnchors(decision, changedFiles);
|
|
19883
|
-
const
|
|
20053
|
+
const sectionIntent = parseIntentSections(
|
|
20054
|
+
[decision.scope, decision.rationale, decision.decision].join("\n")
|
|
20055
|
+
);
|
|
20056
|
+
const structuredFields = hasStructuredIntentFields(decision.intent);
|
|
20057
|
+
const fallbackGoal = decision.rationale || decision.decision || decision.title;
|
|
20058
|
+
const goal = decision.intent?.goal || sectionIntent.goal || fallbackGoal;
|
|
19884
20059
|
const confidenceScore = normalizeConfidenceScore(
|
|
19885
20060
|
decision.confidenceScore,
|
|
19886
20061
|
status === "approved" ? 0.86 : 0.66
|
|
19887
20062
|
);
|
|
20063
|
+
const freshnessHorizonDays = resolveFreshnessHorizonDays(
|
|
20064
|
+
decision.intent?.freshnessHorizonDays ?? decision.freshnessHorizonDays ?? sectionIntent.freshnessHorizonDays,
|
|
20065
|
+
policy
|
|
20066
|
+
);
|
|
19888
20067
|
const reasonCodes = uniqueStrings8([
|
|
19889
20068
|
"decision_intent",
|
|
19890
20069
|
status === "approved" ? "reviewed_source" : "review_needed",
|
|
19891
|
-
anchors.length > 0 ? "affected_anchors_present" : "affected_anchors_missing"
|
|
20070
|
+
anchors.length > 0 ? "affected_anchors_present" : "affected_anchors_missing",
|
|
20071
|
+
structuredFields ? "structured_intent_fields" : void 0,
|
|
20072
|
+
sectionIntent.sourceFields.length > 0 ? "structured_intent_sections" : void 0,
|
|
20073
|
+
goal === fallbackGoal ? "legacy_goal_fallback" : void 0
|
|
19892
20074
|
]);
|
|
19893
20075
|
return {
|
|
19894
20076
|
id: `intent:${decision.id}`,
|
|
@@ -19898,16 +20080,30 @@ function buildDecisionIntentEntry(decision, changedFiles) {
|
|
|
19898
20080
|
sourceDecisionId: decision.id,
|
|
19899
20081
|
sourceDocumentPath: null,
|
|
19900
20082
|
intent: {
|
|
19901
|
-
goal
|
|
20083
|
+
goal,
|
|
19902
20084
|
constraints: uniqueStrings8([
|
|
19903
20085
|
...decision.constraints ?? [],
|
|
19904
|
-
...
|
|
20086
|
+
...decision.intent?.constraints ?? [],
|
|
20087
|
+
...sectionIntent.constraints
|
|
19905
20088
|
]).slice(0, 8),
|
|
19906
|
-
antiGoals:
|
|
19907
|
-
|
|
20089
|
+
antiGoals: normalizeIntentList([
|
|
20090
|
+
...decision.antiGoals ?? [],
|
|
20091
|
+
...decision.intent?.antiGoals ?? [],
|
|
20092
|
+
...sectionIntent.antiGoals
|
|
20093
|
+
]),
|
|
20094
|
+
rejectedAlternatives: normalizeIntentList([
|
|
20095
|
+
...decision.rejectedAlternatives ?? [],
|
|
20096
|
+
...decision.intent?.rejectedAlternatives ?? [],
|
|
20097
|
+
...sectionIntent.rejectedAlternatives
|
|
20098
|
+
])
|
|
19908
20099
|
},
|
|
20100
|
+
extraction: extractionMetadata({
|
|
20101
|
+
structuredFields,
|
|
20102
|
+
structuredSections: sectionIntent,
|
|
20103
|
+
fallbackUsed: goal === fallbackGoal
|
|
20104
|
+
}),
|
|
19909
20105
|
affectedAnchors: anchors,
|
|
19910
|
-
owner: null,
|
|
20106
|
+
owner: decision.intent?.owner ?? sectionIntent.owner ?? decision.owner ?? null,
|
|
19911
20107
|
evidence: decision.evidence && decision.evidence.length > 0 ? decision.evidence : [
|
|
19912
20108
|
{
|
|
19913
20109
|
kind: "decision",
|
|
@@ -19917,7 +20113,7 @@ function buildDecisionIntentEntry(decision, changedFiles) {
|
|
|
19917
20113
|
}
|
|
19918
20114
|
],
|
|
19919
20115
|
confidence: intentConfidence(confidenceScore, status, reasonCodes),
|
|
19920
|
-
staleness: stalenessFromStatus(status),
|
|
20116
|
+
staleness: stalenessFromStatus(status, freshnessHorizonDays),
|
|
19921
20117
|
reasonCodes,
|
|
19922
20118
|
recommendedActions: status === "approved" ? ["Keep this intent linked when changing its affected anchors."] : ["Review this intent candidate before treating it as governing project truth."],
|
|
19923
20119
|
caveats: [
|
|
@@ -19925,10 +20121,22 @@ function buildDecisionIntentEntry(decision, changedFiles) {
|
|
|
19925
20121
|
]
|
|
19926
20122
|
};
|
|
19927
20123
|
}
|
|
19928
|
-
function buildDocumentIntentEntry(doc) {
|
|
19929
|
-
const
|
|
19930
|
-
const
|
|
19931
|
-
const
|
|
20124
|
+
function buildDocumentIntentEntry(doc, policy) {
|
|
20125
|
+
const sectionIntent = parseIntentSections(doc.contentPreview);
|
|
20126
|
+
const structuredFields = hasStructuredIntentFields(doc.intent);
|
|
20127
|
+
const goal = doc.intent?.goal ?? sectionIntent.goal ?? doc.title ?? doc.path;
|
|
20128
|
+
const reasonCodes = uniqueStrings8([
|
|
20129
|
+
"document_intent_candidate",
|
|
20130
|
+
"review_needed",
|
|
20131
|
+
structuredFields ? "structured_intent_fields" : void 0,
|
|
20132
|
+
sectionIntent.sourceFields.length > 0 ? "structured_intent_sections" : void 0,
|
|
20133
|
+
goal === doc.path || goal === doc.title ? "legacy_goal_fallback" : void 0
|
|
20134
|
+
]);
|
|
20135
|
+
const confidenceScore = textHasAnyToken(doc.kind ?? "", ["adr", "decision"]) ? 0.66 : 0.58;
|
|
20136
|
+
const freshnessHorizonDays = resolveFreshnessHorizonDays(
|
|
20137
|
+
doc.intent?.freshnessHorizonDays ?? doc.freshnessHorizonDays ?? sectionIntent.freshnessHorizonDays,
|
|
20138
|
+
policy
|
|
20139
|
+
);
|
|
19932
20140
|
return {
|
|
19933
20141
|
id: `intent:doc:${doc.path}`,
|
|
19934
20142
|
title: doc.title || doc.path,
|
|
@@ -19937,13 +20145,27 @@ function buildDocumentIntentEntry(doc) {
|
|
|
19937
20145
|
sourceDecisionId: null,
|
|
19938
20146
|
sourceDocumentPath: doc.path,
|
|
19939
20147
|
intent: {
|
|
19940
|
-
goal
|
|
19941
|
-
constraints:
|
|
19942
|
-
|
|
19943
|
-
|
|
20148
|
+
goal,
|
|
20149
|
+
constraints: uniqueStrings8([
|
|
20150
|
+
...doc.intent?.constraints ?? [],
|
|
20151
|
+
...sectionIntent.constraints
|
|
20152
|
+
]).slice(0, 4),
|
|
20153
|
+
antiGoals: normalizeIntentList([
|
|
20154
|
+
...doc.intent?.antiGoals ?? [],
|
|
20155
|
+
...sectionIntent.antiGoals
|
|
20156
|
+
]),
|
|
20157
|
+
rejectedAlternatives: normalizeIntentList([
|
|
20158
|
+
...doc.intent?.rejectedAlternatives ?? [],
|
|
20159
|
+
...sectionIntent.rejectedAlternatives
|
|
20160
|
+
])
|
|
19944
20161
|
},
|
|
20162
|
+
extraction: extractionMetadata({
|
|
20163
|
+
structuredFields,
|
|
20164
|
+
structuredSections: sectionIntent,
|
|
20165
|
+
fallbackUsed: goal === doc.path || goal === doc.title
|
|
20166
|
+
}),
|
|
19945
20167
|
affectedAnchors: [doc.path],
|
|
19946
|
-
owner: null,
|
|
20168
|
+
owner: doc.intent?.owner ?? sectionIntent.owner ?? doc.owner ?? null,
|
|
19947
20169
|
evidence: [
|
|
19948
20170
|
{
|
|
19949
20171
|
kind: "document",
|
|
@@ -19955,7 +20177,8 @@ function buildDocumentIntentEntry(doc) {
|
|
|
19955
20177
|
confidence: intentConfidence(confidenceScore, "review_pending", reasonCodes),
|
|
19956
20178
|
staleness: {
|
|
19957
20179
|
state: "unknown",
|
|
19958
|
-
reason: "Document-derived intent candidates need review before becoming governing truth."
|
|
20180
|
+
reason: "Document-derived intent candidates need review before becoming governing truth.",
|
|
20181
|
+
horizonDays: freshnessHorizonDays
|
|
19959
20182
|
},
|
|
19960
20183
|
reasonCodes,
|
|
19961
20184
|
recommendedActions: ["Promote, reject, or link this document intent candidate to a decision."],
|
|
@@ -19966,15 +20189,19 @@ function buildDocumentIntentEntry(doc) {
|
|
|
19966
20189
|
}
|
|
19967
20190
|
function buildProjectIntentLedger(input, changedFilesOverride) {
|
|
19968
20191
|
const changedFiles = uniqueStrings8(changedFilesOverride ?? input.changedFiles);
|
|
20192
|
+
const policy = {
|
|
20193
|
+
...DEFAULT_PROJECT_INTENT_LEDGER_POLICY,
|
|
20194
|
+
...input.intentPolicy ?? {}
|
|
20195
|
+
};
|
|
19969
20196
|
const decisionEntries = (input.decisions ?? []).map(
|
|
19970
|
-
(decision) => buildDecisionIntentEntry(decision, changedFiles)
|
|
20197
|
+
(decision) => buildDecisionIntentEntry(decision, changedFiles, policy)
|
|
19971
20198
|
);
|
|
19972
20199
|
const decisionDocumentPaths = new Set(
|
|
19973
20200
|
decisionEntries.flatMap(
|
|
19974
20201
|
(entry) => entry.evidence.map((evidence) => evidence.sourceRef).filter(Boolean)
|
|
19975
20202
|
)
|
|
19976
20203
|
);
|
|
19977
|
-
const documentEntries = (input.documents ?? []).filter(documentLooksLikeIntent).filter((doc) => !decisionDocumentPaths.has(doc.path)).map(buildDocumentIntentEntry);
|
|
20204
|
+
const documentEntries = (input.documents ?? []).filter(documentLooksLikeIntent).filter((doc) => !decisionDocumentPaths.has(doc.path)).map((doc) => buildDocumentIntentEntry(doc, policy));
|
|
19978
20205
|
const entries = [...decisionEntries, ...documentEntries];
|
|
19979
20206
|
const linkedIntentIds = new Set(
|
|
19980
20207
|
entries.filter((entry) => changedFiles.some((file) => intentEntryMatchesFile(entry, file))).map((entry) => entry.id)
|
|
@@ -20006,11 +20233,11 @@ function buildProjectIntentLedger(input, changedFilesOverride) {
|
|
|
20006
20233
|
].filter((item) => Boolean(item))
|
|
20007
20234
|
};
|
|
20008
20235
|
}
|
|
20236
|
+
|
|
20237
|
+
// ../project-intelligence-contracts/src/unknown-registry.ts
|
|
20238
|
+
var PROJECT_UNKNOWN_REGISTRY_VERSION = "unknown-registry-v1";
|
|
20009
20239
|
function unknownId(category, key, scope) {
|
|
20010
|
-
return
|
|
20011
|
-
"reality:decision-vs-code",
|
|
20012
|
-
"unknown"
|
|
20013
|
-
);
|
|
20240
|
+
return makeScopedId("unknown", category, key, scope);
|
|
20014
20241
|
}
|
|
20015
20242
|
function unknownStatusFromSeverity(unknowns) {
|
|
20016
20243
|
if (unknowns.some(
|
|
@@ -20236,8 +20463,23 @@ function buildProjectUnknownRegistry(input) {
|
|
|
20236
20463
|
].filter((item) => Boolean(item))
|
|
20237
20464
|
};
|
|
20238
20465
|
}
|
|
20239
|
-
|
|
20240
|
-
|
|
20466
|
+
|
|
20467
|
+
// ../project-intelligence-contracts/src/reality-check.ts
|
|
20468
|
+
var PROJECT_REALITY_CHECK_VERSION = "project-reality-check-v0";
|
|
20469
|
+
function findingSeverityScore(severity) {
|
|
20470
|
+
if (severity === "blocking") return 0;
|
|
20471
|
+
if (severity === "review_required") return 30;
|
|
20472
|
+
if (severity === "watch") return 70;
|
|
20473
|
+
return 90;
|
|
20474
|
+
}
|
|
20475
|
+
function resultStatusFromFindings(findings) {
|
|
20476
|
+
if (findings.some((finding) => finding.severity === "blocking")) return "blocking";
|
|
20477
|
+
if (findings.some((finding) => finding.severity === "review_required")) return "review_required";
|
|
20478
|
+
if (findings.some((finding) => finding.severity === "watch")) return "advisory";
|
|
20479
|
+
return "pass";
|
|
20480
|
+
}
|
|
20481
|
+
function makeFindingId(type, key, files) {
|
|
20482
|
+
return makeScopedId("reality", type, key, files);
|
|
20241
20483
|
}
|
|
20242
20484
|
function testFiles(changedFiles) {
|
|
20243
20485
|
return changedFiles.filter(
|
|
@@ -26069,17 +26311,17 @@ function normalizeCollaborationFiles(files) {
|
|
|
26069
26311
|
function parseCollaborationResources(values) {
|
|
26070
26312
|
return normalizeResources(
|
|
26071
26313
|
(values ?? []).map((value) => {
|
|
26072
|
-
const
|
|
26073
|
-
if (
|
|
26314
|
+
const separatorIndex2 = value.indexOf(":");
|
|
26315
|
+
if (separatorIndex2 <= 0) {
|
|
26074
26316
|
throw new Error(`Resource must use KIND:id format: ${value}`);
|
|
26075
26317
|
}
|
|
26076
|
-
const kind = normalizeResourceKind(value.slice(0,
|
|
26318
|
+
const kind = normalizeResourceKind(value.slice(0, separatorIndex2));
|
|
26077
26319
|
if (!kind) {
|
|
26078
26320
|
throw new Error(
|
|
26079
|
-
`Unsupported collaboration resource kind: ${value.slice(0,
|
|
26321
|
+
`Unsupported collaboration resource kind: ${value.slice(0, separatorIndex2)}`
|
|
26080
26322
|
);
|
|
26081
26323
|
}
|
|
26082
|
-
const id = value.slice(
|
|
26324
|
+
const id = value.slice(separatorIndex2 + 1).trim();
|
|
26083
26325
|
if (!id) {
|
|
26084
26326
|
throw new Error(`Resource id is required for ${kind}`);
|
|
26085
26327
|
}
|
|
@@ -27609,12 +27851,12 @@ function parseKeyValueEntries(entries, label) {
|
|
|
27609
27851
|
}
|
|
27610
27852
|
const result = {};
|
|
27611
27853
|
for (const entry of entries) {
|
|
27612
|
-
const
|
|
27613
|
-
if (
|
|
27854
|
+
const separatorIndex2 = entry.indexOf("=");
|
|
27855
|
+
if (separatorIndex2 <= 0 || separatorIndex2 === entry.length - 1) {
|
|
27614
27856
|
throw new Error(`Invalid ${label} entry '${entry}'. Expected KEY=value.`);
|
|
27615
27857
|
}
|
|
27616
|
-
const key = entry.slice(0,
|
|
27617
|
-
const value = entry.slice(
|
|
27858
|
+
const key = entry.slice(0, separatorIndex2).trim();
|
|
27859
|
+
const value = entry.slice(separatorIndex2 + 1).trim();
|
|
27618
27860
|
if (!key || !value) {
|
|
27619
27861
|
throw new Error(`Invalid ${label} entry '${entry}'. Expected KEY=value.`);
|
|
27620
27862
|
}
|
package/docs/FULL_REFERENCE.md
CHANGED
|
@@ -201,7 +201,12 @@ snipara-companion workflow resume --include-session-context
|
|
|
201
201
|
dirty local evidence, architecture drift, stale/review-pending intent, and
|
|
202
202
|
heuristic-calibration gaps. Keep `--enforce` opt-in for narrow hooks or
|
|
203
203
|
calibrated CI adapters; the V1 heuristics are advisory and can produce false
|
|
204
|
-
positives on broad text/path matches.
|
|
204
|
+
positives on broad text/path matches. Intent Ledger extraction prefers
|
|
205
|
+
structured contract fields or explicit labeled sections such as `Goal:`,
|
|
206
|
+
`Constraints:`, `Anti-goals:`, `Rejected alternatives:`, `Owner:`, and
|
|
207
|
+
`Freshness horizon days:`. Generic prose remains a legacy fallback for goal
|
|
208
|
+
text only; anti-goals and rejected alternatives are not inferred from loose
|
|
209
|
+
words in free text.
|
|
205
210
|
- `timeline` is the Git-style log for workflow starts, phase starts, phase
|
|
206
211
|
commits, final commits, and Team Sync handoffs.
|
|
207
212
|
- `workflow impact-gate` audits committed local workflow phases that are ahead
|
|
@@ -948,7 +953,7 @@ CI adapter needs the contradiction-to-reality gate without a full hosted brief:
|
|
|
948
953
|
snipara-companion reality-check \
|
|
949
954
|
--task "refactor auth middleware" \
|
|
950
955
|
--changed-files src/auth/middleware.ts \
|
|
951
|
-
--decision
|
|
956
|
+
--decision $'DEC-001: Goal: keep auth middleware side effects explicit\nConstraints:\n- auth middleware stays synchronous\nAnti-goals:\n- implicit token refresh' \
|
|
952
957
|
--verification "pnpm test auth" \
|
|
953
958
|
--enforce
|
|
954
959
|
```
|
|
@@ -958,7 +963,9 @@ The command reads the local Git scope by default, includes dirty files unless
|
|
|
958
963
|
hooks or CI collectors. `--enforce` exits non-zero for `review_required` or
|
|
959
964
|
`blocking` findings, but should stay opt-in until the matched surfaces,
|
|
960
965
|
verification signals, and project-specific thresholds have been calibrated.
|
|
961
|
-
|
|
966
|
+
Intent can be supplied as structured sections inside `--decision` or
|
|
967
|
+
`--document`, using labels such as `Goal:`, `Constraints:`, `Anti-goals:`,
|
|
968
|
+
`Rejected alternatives:`, and `Owner:`. JSON output is available with `--json`.
|
|
962
969
|
|
|
963
970
|
Use `intelligence ledger-export` when an agent run, review, or replay benchmark
|
|
964
971
|
needs a portable Coding Intelligence Ledger instead of a raw transcript:
|