@c4a/context-cli 0.5.29-beta.20 → 0.5.29-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/cli.js +1534 -961
- package/package.json +1 -1
- package/plugin/commands/align.md +3 -1
- package/plugin/commands/capture.md +1 -1
- package/plugin/commands/compile.md +16 -8
- package/plugin/commands/query.md +1 -1
- package/plugin/skills/skill-align-workflow/SKILL.md +4 -2
- package/plugin/skills/skill-compile-close/SKILL.md +3 -0
- package/plugin/skills/skill-compile-draft/SKILL.md +19 -17
- package/plugin/skills/skill-compile-draft/references/refresh-and-update.md +14 -14
- package/plugin/skills/skill-context-query/SKILL.md +24 -22
- package/plugin/skills/skill-semantic-reconcile/SKILL.md +5 -4
- package/plugin/skills/skill-semantic-reconcile/references/mode-semantics.md +1 -1
- package/plugin/skills/skill-semantic-reconcile/references/temporal-and-evidence.md +13 -13
- package/plugin/skills/skill-semantic-reconcile/references/user-confirmation.md +2 -0
package/cli.js
CHANGED
|
@@ -17167,6 +17167,10 @@ function normalizeProposed(value, issues, path2) {
|
|
|
17167
17167
|
validateProposedContent(value.content, issues, `${path2}.content`);
|
|
17168
17168
|
proposed.content = value.content;
|
|
17169
17169
|
}
|
|
17170
|
+
if (value.summary === null || typeof value.summary === "string")
|
|
17171
|
+
proposed.summary = value.summary;
|
|
17172
|
+
if (value.raw === null || typeof value.raw === "string")
|
|
17173
|
+
proposed.raw = value.raw;
|
|
17170
17174
|
if (value.detail === null || typeof value.detail === "string")
|
|
17171
17175
|
proposed.detail = value.detail;
|
|
17172
17176
|
if (typeof value.confidence === "string")
|
|
@@ -17203,7 +17207,9 @@ function normalizeProposed(value, issues, path2) {
|
|
|
17203
17207
|
validateProposedContent(section.content, issues, `${path2}.sections[${index}].content`);
|
|
17204
17208
|
sections.push({
|
|
17205
17209
|
kind: section.kind,
|
|
17210
|
+
...section.summary === null || typeof section.summary === "string" ? { summary: section.summary } : {},
|
|
17206
17211
|
content: section.content,
|
|
17212
|
+
...section.raw === null || typeof section.raw === "string" ? { raw: section.raw } : {},
|
|
17207
17213
|
source_ref: section.source_ref,
|
|
17208
17214
|
...section.detail === null || typeof section.detail === "string" ? { detail: section.detail } : {},
|
|
17209
17215
|
...typeof section.confidence === "string" ? { confidence: section.confidence } : {},
|
|
@@ -17216,15 +17222,8 @@ function normalizeProposed(value, issues, path2) {
|
|
|
17216
17222
|
return proposed;
|
|
17217
17223
|
}
|
|
17218
17224
|
function validateProposedContent(content, issues, path2) {
|
|
17219
|
-
if (content.length
|
|
17220
|
-
pushIssue(issues, path2,
|
|
17221
|
-
}
|
|
17222
|
-
if (content.includes(`
|
|
17223
|
-
`) || content.includes("\r")) {
|
|
17224
|
-
pushIssue(issues, path2, "content must be a single-line claim; move multi-line prose or code into detail");
|
|
17225
|
-
}
|
|
17226
|
-
if (FENCED_CODE_RE.test(content)) {
|
|
17227
|
-
pushIssue(issues, path2, "content must not contain fenced code; put code blocks in detail");
|
|
17225
|
+
if (content.trim().length === 0) {
|
|
17226
|
+
pushIssue(issues, path2, "content must be non-empty");
|
|
17228
17227
|
}
|
|
17229
17228
|
}
|
|
17230
17229
|
function normalizeUserConfirmation(value) {
|
|
@@ -17459,7 +17458,7 @@ function parseSemanticDecisionDocument(value) {
|
|
|
17459
17458
|
}
|
|
17460
17459
|
return result.document;
|
|
17461
17460
|
}
|
|
17462
|
-
var SEMANTIC_DECISION_SCHEMA_VERSION = "1.0", SEMANTIC_LEDGER_SCHEMA_VERSION = "decisions.semantic.v2", DECISION_ARCHIVE_SCHEMA_VERSION = "decisions.archive.v1", SEMANTIC_SAFE_DEFAULT_POLICY_VERSION = "reconcile.safe-default.v2", SEMANTIC_RECONCILE_MODES, SEMANTIC_RELATIONS, SEMANTIC_ACTIONS,
|
|
17461
|
+
var SEMANTIC_DECISION_SCHEMA_VERSION = "1.0", SEMANTIC_LEDGER_SCHEMA_VERSION = "decisions.semantic.v2", DECISION_ARCHIVE_SCHEMA_VERSION = "decisions.archive.v1", SEMANTIC_SAFE_DEFAULT_POLICY_VERSION = "reconcile.safe-default.v2", SEMANTIC_RECONCILE_MODES, SEMANTIC_RELATIONS, SEMANTIC_ACTIONS, TARGET_REQUIRED_ACTIONS, OMIT_ALLOWED_RELATIONS, ASK_USER_TARGET_RELATIONS;
|
|
17463
17462
|
var init_types3 = __esm(() => {
|
|
17464
17463
|
SEMANTIC_RECONCILE_MODES = ["compile", "drop", "refresh", "restore"];
|
|
17465
17464
|
SEMANTIC_RELATIONS = [
|
|
@@ -17485,7 +17484,6 @@ var init_types3 = __esm(() => {
|
|
|
17485
17484
|
"omit",
|
|
17486
17485
|
"ask_user"
|
|
17487
17486
|
];
|
|
17488
|
-
FENCED_CODE_RE = /(^|\n)\s*(```|~~~)/u;
|
|
17489
17487
|
TARGET_REQUIRED_ACTIONS = new Set([
|
|
17490
17488
|
"duplicate_skip",
|
|
17491
17489
|
"merge_update",
|
|
@@ -18906,6 +18904,12 @@ function validateSection(section) {
|
|
|
18906
18904
|
if (typeof section.content !== "string" || section.content.length === 0) {
|
|
18907
18905
|
issues.push("content is required");
|
|
18908
18906
|
}
|
|
18907
|
+
if (section.summary !== undefined && typeof section.summary !== "string") {
|
|
18908
|
+
issues.push("summary must be a string when present");
|
|
18909
|
+
}
|
|
18910
|
+
if (section.raw !== undefined && typeof section.raw !== "string") {
|
|
18911
|
+
issues.push("raw must be a string when present");
|
|
18912
|
+
}
|
|
18909
18913
|
if (!includesValue(SECTION_STATUS_VALUES, section.status)) {
|
|
18910
18914
|
issues.push(`status must be one of ${SECTION_STATUS_VALUES.join(", ")}`);
|
|
18911
18915
|
}
|
|
@@ -19058,20 +19062,43 @@ var init_nodeDisplayGroups = __esm(() => {
|
|
|
19058
19062
|
"Changelog"
|
|
19059
19063
|
];
|
|
19060
19064
|
SECTION_GROUP_TITLES = new Set([
|
|
19061
|
-
...SECTION_GROUP_ORDER
|
|
19062
|
-
"Details"
|
|
19065
|
+
...SECTION_GROUP_ORDER
|
|
19063
19066
|
]);
|
|
19064
19067
|
});
|
|
19065
19068
|
|
|
19066
19069
|
// src/lib/nodeParserSections.ts
|
|
19067
|
-
function
|
|
19068
|
-
|
|
19069
|
-
|
|
19070
|
-
|
|
19071
|
-
|
|
19070
|
+
function isSectionOpenComment(line) {
|
|
19071
|
+
return SECTION_OPEN_RE.test(line.trim());
|
|
19072
|
+
}
|
|
19073
|
+
function isLegacySectionOpenComment(line) {
|
|
19074
|
+
const match = LEGACY_SECTION_OPEN_RE.exec(line.trim());
|
|
19075
|
+
const kind = match?.[1];
|
|
19076
|
+
return kind !== undefined && Object.values(SectionKind).includes(kind);
|
|
19077
|
+
}
|
|
19078
|
+
function decodeAttr(value) {
|
|
19079
|
+
return value.replace(/"/gu, '"').replace(/-/gu, "-").replace(/&/gu, "&");
|
|
19080
|
+
}
|
|
19081
|
+
function parseAttributes(raw) {
|
|
19082
|
+
const text = raw.trim();
|
|
19083
|
+
const attributes = new Map;
|
|
19084
|
+
let index = 0;
|
|
19085
|
+
while (index < text.length) {
|
|
19086
|
+
while (/\s/u.test(text[index] ?? ""))
|
|
19087
|
+
index += 1;
|
|
19088
|
+
if (index >= text.length)
|
|
19089
|
+
break;
|
|
19090
|
+
ATTR_RE.lastIndex = index;
|
|
19091
|
+
const match = ATTR_RE.exec(text);
|
|
19092
|
+
if (!match) {
|
|
19093
|
+
throw new Error(`invalid c4a comment attribute near: ${text.slice(index, index + 32)}`);
|
|
19072
19094
|
}
|
|
19073
|
-
|
|
19074
|
-
|
|
19095
|
+
const key = match[1];
|
|
19096
|
+
const value = match[2];
|
|
19097
|
+
if (key !== undefined && value !== undefined)
|
|
19098
|
+
attributes.set(key, decodeAttr(value));
|
|
19099
|
+
index = ATTR_RE.lastIndex;
|
|
19100
|
+
}
|
|
19101
|
+
return attributes;
|
|
19075
19102
|
}
|
|
19076
19103
|
function parseScalarAttribute(value) {
|
|
19077
19104
|
const maybeNumber = Number(value);
|
|
@@ -19080,120 +19107,120 @@ function parseScalarAttribute(value) {
|
|
|
19080
19107
|
}
|
|
19081
19108
|
return value;
|
|
19082
19109
|
}
|
|
19083
|
-
function
|
|
19084
|
-
const
|
|
19110
|
+
function requiredAttribute(attributes, key) {
|
|
19111
|
+
const value = attributes.get(key);
|
|
19112
|
+
if (value === undefined || value.length === 0) {
|
|
19113
|
+
throw new Error(`section comment must provide ${key}`);
|
|
19114
|
+
}
|
|
19115
|
+
return value;
|
|
19116
|
+
}
|
|
19117
|
+
function parseSectionComment(comment) {
|
|
19118
|
+
const match = SECTION_OPEN_RE.exec(comment.trim());
|
|
19085
19119
|
if (!match) {
|
|
19120
|
+
throw new Error("section block must start with a c4a:section comment");
|
|
19121
|
+
}
|
|
19122
|
+
const attributes = parseAttributes(match[1] ?? "");
|
|
19123
|
+
const id2 = requiredAttribute(attributes, "id");
|
|
19124
|
+
const kind = requiredAttribute(attributes, "kind");
|
|
19125
|
+
const sourceRef = requiredAttribute(attributes, "source_ref");
|
|
19126
|
+
if (!Object.values(SectionKind).includes(kind)) {
|
|
19127
|
+
throw new Error(`unsupported section kind: ${kind}`);
|
|
19128
|
+
}
|
|
19129
|
+
return {
|
|
19130
|
+
id: id2,
|
|
19131
|
+
kind,
|
|
19132
|
+
sourceRef: sourceRef === "-" ? "" : sourceRef,
|
|
19133
|
+
attributes
|
|
19134
|
+
};
|
|
19135
|
+
}
|
|
19136
|
+
function parseSectionRelationComment(line) {
|
|
19137
|
+
const match = RELATION_RE.exec(line.trim());
|
|
19138
|
+
if (!match)
|
|
19086
19139
|
return null;
|
|
19140
|
+
const attributes = parseAttributes(match[1] ?? "");
|
|
19141
|
+
const target = requiredAttribute(attributes, "target");
|
|
19142
|
+
const relation = requiredAttribute(attributes, "relation");
|
|
19143
|
+
if (!["implements", "supersedes", "refines", "conflicts", "references"].includes(relation)) {
|
|
19144
|
+
throw new Error(`unsupported section relation: ${relation}`);
|
|
19087
19145
|
}
|
|
19088
|
-
const target = match[1] ?? "";
|
|
19089
|
-
const relation = match[2];
|
|
19090
19146
|
const slashIndex = target.lastIndexOf("/");
|
|
19091
|
-
|
|
19092
|
-
|
|
19147
|
+
if (slashIndex <= 0 || slashIndex === target.length - 1) {
|
|
19148
|
+
throw new Error("c4a:relation target must use <slug>/<section-id>");
|
|
19149
|
+
}
|
|
19093
19150
|
return {
|
|
19094
|
-
target_slug:
|
|
19095
|
-
target_section_id:
|
|
19151
|
+
target_slug: target.slice(0, slashIndex),
|
|
19152
|
+
target_section_id: target.slice(slashIndex + 1),
|
|
19096
19153
|
relation
|
|
19097
19154
|
};
|
|
19098
19155
|
}
|
|
19099
|
-
function
|
|
19100
|
-
const
|
|
19101
|
-
while (
|
|
19102
|
-
|
|
19103
|
-
|
|
19104
|
-
|
|
19105
|
-
|
|
19106
|
-
}
|
|
19107
|
-
if (stripped.length === 0) {
|
|
19108
|
-
throw new Error("section blockquote is empty");
|
|
19109
|
-
}
|
|
19110
|
-
const firstLine = stripped[0] ?? "";
|
|
19111
|
-
const content = firstLine.trim();
|
|
19112
|
-
const detailLines = stripped.slice(1);
|
|
19113
|
-
while (detailLines.length > 0 && detailLines[0]?.trim() === "") {
|
|
19114
|
-
detailLines.shift();
|
|
19115
|
-
}
|
|
19116
|
-
const detail = unwrapRenderedDetail(detailLines).join(`
|
|
19117
|
-
`).trim();
|
|
19118
|
-
return detail.length > 0 ? { content, detail } : { content };
|
|
19156
|
+
function trimBlankEdges(lines) {
|
|
19157
|
+
const next = [...lines];
|
|
19158
|
+
while (next.length > 0 && (next[0]?.trim() ?? "") === "")
|
|
19159
|
+
next.shift();
|
|
19160
|
+
while (next.length > 0 && (next[next.length - 1]?.trim() ?? "") === "")
|
|
19161
|
+
next.pop();
|
|
19162
|
+
return next;
|
|
19119
19163
|
}
|
|
19120
|
-
function
|
|
19121
|
-
|
|
19122
|
-
|
|
19123
|
-
|
|
19124
|
-
|
|
19125
|
-
for (let index = lines.length - 1;index >= 0; index -= 1) {
|
|
19126
|
-
if (lines[index]?.trim().toLowerCase() === "</details>") {
|
|
19127
|
-
closeIndex = index;
|
|
19128
|
-
break;
|
|
19129
|
-
}
|
|
19164
|
+
function parseOptionalCommentBlock(input) {
|
|
19165
|
+
const start2 = input.lines.findIndex((line) => input.open.test(line.trim()));
|
|
19166
|
+
const end = input.lines.findIndex((line) => input.close.test(line.trim()));
|
|
19167
|
+
if (start2 < 0 && end >= 0) {
|
|
19168
|
+
throw new Error(`section ${input.sectionId} has c4a:${input.name} close without open`);
|
|
19130
19169
|
}
|
|
19131
|
-
if (
|
|
19132
|
-
|
|
19170
|
+
if (start2 >= 0 && end < 0) {
|
|
19171
|
+
throw new Error(`section ${input.sectionId} is missing /c4a:${input.name}`);
|
|
19133
19172
|
}
|
|
19134
|
-
|
|
19135
|
-
|
|
19136
|
-
bodyStart += 1;
|
|
19173
|
+
if (start2 >= 0 && end < start2) {
|
|
19174
|
+
throw new Error(`section ${input.sectionId} has /c4a:${input.name} before c4a:${input.name}`);
|
|
19137
19175
|
}
|
|
19138
|
-
|
|
19139
|
-
|
|
19140
|
-
unwrapped.shift();
|
|
19176
|
+
if (start2 >= 0 && input.lines.slice(start2 + 1).some((line, offset) => offset !== end - start2 - 1 && input.open.test(line.trim()))) {
|
|
19177
|
+
throw new Error(`section ${input.sectionId} must contain at most one c4a:${input.name} block`);
|
|
19141
19178
|
}
|
|
19142
|
-
|
|
19143
|
-
|
|
19179
|
+
if (start2 < 0 || end < 0)
|
|
19180
|
+
return { before: [...input.lines], after: [] };
|
|
19181
|
+
const valueLines = trimBlankEdges(input.lines.slice(start2 + 1, end));
|
|
19182
|
+
if (valueLines.length === 0) {
|
|
19183
|
+
throw new Error(`section ${input.sectionId} has empty c4a:${input.name}`);
|
|
19144
19184
|
}
|
|
19145
|
-
return
|
|
19185
|
+
return {
|
|
19186
|
+
value: valueLines.join(`
|
|
19187
|
+
`).trim(),
|
|
19188
|
+
before: trimBlankEdges(input.lines.slice(0, start2)),
|
|
19189
|
+
after: trimBlankEdges(input.lines.slice(end + 1))
|
|
19190
|
+
};
|
|
19146
19191
|
}
|
|
19147
|
-
function
|
|
19148
|
-
const
|
|
19149
|
-
|
|
19150
|
-
|
|
19151
|
-
|
|
19152
|
-
|
|
19153
|
-
|
|
19154
|
-
|
|
19155
|
-
|
|
19156
|
-
|
|
19157
|
-
if (!(kindToken in SectionKind)) {
|
|
19158
|
-
throw new Error(`unsupported section kind: ${kindToken}`);
|
|
19159
|
-
}
|
|
19160
|
-
const lineRangeToken = restTokens[0];
|
|
19161
|
-
const hasInlineLineRange = typeof lineRangeToken === "string" && /^L\d+-L?\d+(?:@[a-f0-9]{8,64})?$/iu.test(lineRangeToken);
|
|
19162
|
-
const sourceRefBase = sourceRefToken === "-" ? "" : sourceRefToken;
|
|
19163
|
-
const sourceRef = hasInlineLineRange ? `${sourceRefBase} ${lineRangeToken}`.trim() : sourceRefBase;
|
|
19164
|
-
const attributeTokens = hasInlineLineRange ? restTokens.slice(1) : restTokens;
|
|
19165
|
-
const attributes = new Map;
|
|
19166
|
-
for (const token of attributeTokens) {
|
|
19167
|
-
const splitIndex = token.indexOf("=");
|
|
19168
|
-
if (splitIndex <= 0)
|
|
19169
|
-
continue;
|
|
19170
|
-
attributes.set(token.slice(0, splitIndex), token.slice(splitIndex + 1));
|
|
19192
|
+
function parseSectionBody(lines, sectionId) {
|
|
19193
|
+
const summary = parseOptionalCommentBlock({
|
|
19194
|
+
lines,
|
|
19195
|
+
sectionId,
|
|
19196
|
+
name: "summary",
|
|
19197
|
+
open: SUMMARY_OPEN_RE,
|
|
19198
|
+
close: SUMMARY_CLOSE_RE
|
|
19199
|
+
});
|
|
19200
|
+
if (summary.value !== undefined && summary.before.length > 0) {
|
|
19201
|
+
throw new Error(`section ${sectionId} has content before c4a:summary`);
|
|
19171
19202
|
}
|
|
19172
|
-
|
|
19173
|
-
|
|
19174
|
-
|
|
19175
|
-
|
|
19176
|
-
|
|
19177
|
-
|
|
19178
|
-
|
|
19179
|
-
|
|
19180
|
-
|
|
19181
|
-
|
|
19182
|
-
index += 1;
|
|
19203
|
+
const afterSummary = summary.value !== undefined ? summary.after : summary.before;
|
|
19204
|
+
const raw = parseOptionalCommentBlock({
|
|
19205
|
+
lines: afterSummary,
|
|
19206
|
+
sectionId,
|
|
19207
|
+
name: "raw",
|
|
19208
|
+
open: RAW_OPEN_RE,
|
|
19209
|
+
close: RAW_CLOSE_RE
|
|
19210
|
+
});
|
|
19211
|
+
if (raw.after.length > 0) {
|
|
19212
|
+
throw new Error(`section ${sectionId} has content after /c4a:raw`);
|
|
19183
19213
|
}
|
|
19184
|
-
|
|
19185
|
-
|
|
19186
|
-
|
|
19187
|
-
const quoteLines = [];
|
|
19188
|
-
let index = startIndex;
|
|
19189
|
-
while (index < lines.length) {
|
|
19190
|
-
const line = lines[index] ?? "";
|
|
19191
|
-
if (!line.startsWith(">"))
|
|
19192
|
-
break;
|
|
19193
|
-
quoteLines.push(line);
|
|
19194
|
-
index += 1;
|
|
19214
|
+
const contentLines = trimBlankEdges(raw.before);
|
|
19215
|
+
if (contentLines.length === 0) {
|
|
19216
|
+
throw new Error(`section ${sectionId} is missing content`);
|
|
19195
19217
|
}
|
|
19196
|
-
return {
|
|
19218
|
+
return {
|
|
19219
|
+
...summary.value !== undefined ? { summary: summary.value } : {},
|
|
19220
|
+
content: contentLines.join(`
|
|
19221
|
+
`).trim(),
|
|
19222
|
+
...raw.value !== undefined ? { raw: raw.value } : {}
|
|
19223
|
+
};
|
|
19197
19224
|
}
|
|
19198
19225
|
function sectionFromParts(input) {
|
|
19199
19226
|
const refersToNodes = input.attributes.get("refers_to_nodes");
|
|
@@ -19204,11 +19231,12 @@ function sectionFromParts(input) {
|
|
|
19204
19231
|
id: input.id,
|
|
19205
19232
|
anchor_slug: input.anchorSlug,
|
|
19206
19233
|
kind: input.kind,
|
|
19234
|
+
...input.body.summary !== undefined ? { summary: input.body.summary } : {},
|
|
19207
19235
|
content: input.body.content,
|
|
19236
|
+
...input.body.raw !== undefined ? { raw: input.body.raw } : {},
|
|
19208
19237
|
status: input.attributes.get("status") ?? SectionStatus.active,
|
|
19209
19238
|
confidence: input.attributes.get("confidence") ?? Confidence.confirmed,
|
|
19210
19239
|
source_ref: input.sourceRef,
|
|
19211
|
-
...input.body.detail !== undefined ? { detail: input.body.detail } : {},
|
|
19212
19240
|
...refersToNodes ? { refers_to_nodes: refersToNodes.split(",").filter(Boolean) } : {},
|
|
19213
19241
|
...workspaceId !== undefined ? { workspace_id: workspaceId } : {},
|
|
19214
19242
|
...validFrom !== undefined ? { valid_from: parseScalarAttribute(validFrom) } : {},
|
|
@@ -19219,29 +19247,58 @@ function sectionFromParts(input) {
|
|
|
19219
19247
|
function parseSectionBlock(lines, startIndex, anchorSlug) {
|
|
19220
19248
|
const comment = lines[startIndex]?.trim() ?? "";
|
|
19221
19249
|
const parsed = parseSectionComment(comment);
|
|
19222
|
-
const
|
|
19223
|
-
const
|
|
19224
|
-
|
|
19225
|
-
|
|
19250
|
+
const relations = [];
|
|
19251
|
+
const bodyLines = [];
|
|
19252
|
+
let index = startIndex + 1;
|
|
19253
|
+
let foundClose = false;
|
|
19254
|
+
while (index < lines.length) {
|
|
19255
|
+
const line = lines[index] ?? "";
|
|
19256
|
+
if (SECTION_CLOSE_RE.test(line.trim())) {
|
|
19257
|
+
foundClose = true;
|
|
19258
|
+
index += 1;
|
|
19259
|
+
break;
|
|
19260
|
+
}
|
|
19261
|
+
if (isSectionOpenComment(line)) {
|
|
19262
|
+
throw new Error(`section ${parsed.id} is missing /c4a:section before next section`);
|
|
19263
|
+
}
|
|
19264
|
+
const relation = bodyLines.length === 0 ? parseSectionRelationComment(line) : null;
|
|
19265
|
+
if (relation) {
|
|
19266
|
+
relations.push(relation);
|
|
19267
|
+
} else {
|
|
19268
|
+
bodyLines.push(line);
|
|
19269
|
+
}
|
|
19270
|
+
index += 1;
|
|
19271
|
+
}
|
|
19272
|
+
if (!foundClose) {
|
|
19273
|
+
throw new Error(`section ${parsed.id} is missing /c4a:section`);
|
|
19226
19274
|
}
|
|
19227
19275
|
const section = sectionFromParts({
|
|
19228
19276
|
...parsed,
|
|
19229
19277
|
anchorSlug,
|
|
19230
|
-
relations
|
|
19231
|
-
body:
|
|
19278
|
+
relations,
|
|
19279
|
+
body: parseSectionBody(bodyLines, parsed.id)
|
|
19232
19280
|
});
|
|
19233
19281
|
const issues = validateSection(section);
|
|
19234
19282
|
if (issues.length > 0) {
|
|
19235
19283
|
throw new Error(`invalid section ${parsed.id}: ${issues.join("; ")}`);
|
|
19236
19284
|
}
|
|
19237
|
-
let index = quoteResult.nextIndex;
|
|
19238
19285
|
while (index < lines.length && (lines[index]?.trim() ?? "") === "") {
|
|
19239
19286
|
index += 1;
|
|
19240
19287
|
}
|
|
19241
19288
|
return { section, nextIndex: index };
|
|
19242
19289
|
}
|
|
19290
|
+
var SECTION_OPEN_RE, SECTION_CLOSE_RE, LEGACY_SECTION_OPEN_RE, SUMMARY_OPEN_RE, SUMMARY_CLOSE_RE, RAW_OPEN_RE, RAW_CLOSE_RE, RELATION_RE, ATTR_RE;
|
|
19243
19291
|
var init_nodeParserSections = __esm(() => {
|
|
19244
19292
|
init_knowledge();
|
|
19293
|
+
SECTION_OPEN_RE = /^<!--\s*c4a:section\b([\s\S]*?)\s*-->$/u;
|
|
19294
|
+
SECTION_CLOSE_RE = /^<!--\s*\/c4a:section\s*-->$/u;
|
|
19295
|
+
LEGACY_SECTION_OPEN_RE = /^<!--\s*section-\d+\s+([A-Za-z_][\w-]*)\b[\s\S]*-->$/u;
|
|
19296
|
+
SUMMARY_OPEN_RE = /^<!--\s*c4a:summary\s*-->$/u;
|
|
19297
|
+
SUMMARY_CLOSE_RE = /^<!--\s*\/c4a:summary\s*-->$/u;
|
|
19298
|
+
RAW_OPEN_RE = /^<!--\s*c4a:raw\s*-->$/u;
|
|
19299
|
+
RAW_CLOSE_RE = /^<!--\s*\/c4a:raw\s*-->$/u;
|
|
19300
|
+
RELATION_RE = /^<!--\s*c4a:relation\b([\s\S]*?)\s*-->$/u;
|
|
19301
|
+
ATTR_RE = /([A-Za-z_][\w:-]*)="([^"]*)"/yu;
|
|
19245
19302
|
});
|
|
19246
19303
|
|
|
19247
19304
|
// src/lib/nodeParser.ts
|
|
@@ -19360,7 +19417,8 @@ function parseContainsList(lines, startIndex, rootSlug) {
|
|
|
19360
19417
|
let index = startIndex + 1;
|
|
19361
19418
|
while (index < lines.length) {
|
|
19362
19419
|
const line = lines[index] ?? "";
|
|
19363
|
-
|
|
19420
|
+
assertNoLegacySectionMarker(line);
|
|
19421
|
+
if (isSectionOpenComment(line)) {
|
|
19364
19422
|
break;
|
|
19365
19423
|
}
|
|
19366
19424
|
const nextHeading = /^(#{1,6})\s+/.exec(line);
|
|
@@ -19396,7 +19454,8 @@ function skipDerivedList(lines, startIndex, title) {
|
|
|
19396
19454
|
let index = startIndex + 1;
|
|
19397
19455
|
while (index < lines.length) {
|
|
19398
19456
|
const line = lines[index] ?? "";
|
|
19399
|
-
|
|
19457
|
+
assertNoLegacySectionMarker(line);
|
|
19458
|
+
if (isSectionOpenComment(line))
|
|
19400
19459
|
break;
|
|
19401
19460
|
const nextHeading = /^(#{1,6})\s+/.exec(line);
|
|
19402
19461
|
if (nextHeading && (nextHeading[1]?.length ?? 0) <= level)
|
|
@@ -19407,6 +19466,11 @@ function skipDerivedList(lines, startIndex, title) {
|
|
|
19407
19466
|
index += 1;
|
|
19408
19467
|
return index;
|
|
19409
19468
|
}
|
|
19469
|
+
function assertNoLegacySectionMarker(line) {
|
|
19470
|
+
if (!isLegacySectionOpenComment(line))
|
|
19471
|
+
return;
|
|
19472
|
+
throw new Error('legacy section marker detected; this workspace uses retired section comments. Re-run compile/close with a current CLI or migrate the article to <!-- c4a:section id="..." kind="..." source_ref="..." --> blocks before querying or compiling.');
|
|
19473
|
+
}
|
|
19410
19474
|
function collapseBlankEdges(value) {
|
|
19411
19475
|
return value.replace(/^\n+/, "").replace(/\n+$/, "");
|
|
19412
19476
|
}
|
|
@@ -19476,6 +19540,7 @@ function parseNodeBlock(lines, startIndex, headingLevel) {
|
|
|
19476
19540
|
const childHeadingPattern = new RegExp(`^#{${childLevel}}\\s+.+`);
|
|
19477
19541
|
while (index < lines.length) {
|
|
19478
19542
|
const currentLine = lines[index] ?? "";
|
|
19543
|
+
assertNoLegacySectionMarker(currentLine);
|
|
19479
19544
|
const siblingMatch = /^(#{1,6})\s+/.exec(currentLine);
|
|
19480
19545
|
if (siblingMatch) {
|
|
19481
19546
|
const level = siblingMatch[1]?.length ?? 0;
|
|
@@ -19491,7 +19556,7 @@ function parseNodeBlock(lines, startIndex, headingLevel) {
|
|
|
19491
19556
|
continue;
|
|
19492
19557
|
}
|
|
19493
19558
|
}
|
|
19494
|
-
if (
|
|
19559
|
+
if (isSectionOpenComment(currentLine)) {
|
|
19495
19560
|
const sectionParsed = parseSectionBlock(lines, index, node2.id);
|
|
19496
19561
|
sections.push(sectionParsed.section);
|
|
19497
19562
|
index = sectionParsed.nextIndex;
|
|
@@ -19627,13 +19692,14 @@ function parseRootNodeFrontmatterFirst(normalized) {
|
|
|
19627
19692
|
const childLevel = 2;
|
|
19628
19693
|
while (index < lines.length) {
|
|
19629
19694
|
const currentLine = lines[index] ?? "";
|
|
19695
|
+
assertNoLegacySectionMarker(currentLine);
|
|
19630
19696
|
if (new RegExp(`^#{${childLevel}}\\s+.+`).test(currentLine) && peekIsFrontmatterAfterHeading(lines, index)) {
|
|
19631
19697
|
const childResult = parseNodeBlock(lines, index, childLevel);
|
|
19632
19698
|
children.push(childResult.parsed);
|
|
19633
19699
|
index = childResult.nextIndex;
|
|
19634
19700
|
continue;
|
|
19635
19701
|
}
|
|
19636
|
-
if (
|
|
19702
|
+
if (isSectionOpenComment(currentLine)) {
|
|
19637
19703
|
const sectionParsed = parseSectionBlock(lines, index, node2.id);
|
|
19638
19704
|
sections.push(sectionParsed.section);
|
|
19639
19705
|
index = sectionParsed.nextIndex;
|
|
@@ -19697,62 +19763,6 @@ var init_nodeParser = __esm(() => {
|
|
|
19697
19763
|
import_yaml9 = __toESM(require_dist(), 1);
|
|
19698
19764
|
});
|
|
19699
19765
|
|
|
19700
|
-
// src/lib/sectionDetail.ts
|
|
19701
|
-
function stripEvidenceEchoPrefix(value) {
|
|
19702
|
-
const match = EVIDENCE_ECHO_PREFIX_RE.exec(value);
|
|
19703
|
-
if (match === null)
|
|
19704
|
-
return { text: value };
|
|
19705
|
-
const label = match[1];
|
|
19706
|
-
if (label === undefined)
|
|
19707
|
-
return { text: value };
|
|
19708
|
-
return {
|
|
19709
|
-
text: value.slice(match[0].length),
|
|
19710
|
-
label
|
|
19711
|
-
};
|
|
19712
|
-
}
|
|
19713
|
-
function normalizeDetailEchoText(value) {
|
|
19714
|
-
return value.normalize("NFKC").replace(/[`*~>#\[\]()[\]{},。;!?'"“”‘’、]+/gu, " ").replace(/\s+/gu, " ").trim().toLowerCase();
|
|
19715
|
-
}
|
|
19716
|
-
function isEvidenceEchoDetail(detail, basisTexts = []) {
|
|
19717
|
-
const trimmed = detail.trim();
|
|
19718
|
-
if (trimmed.length === 0)
|
|
19719
|
-
return false;
|
|
19720
|
-
const stripped = stripEvidenceEchoPrefix(trimmed);
|
|
19721
|
-
const normalizedDetail = normalizeDetailEchoText(stripped.text);
|
|
19722
|
-
if (normalizedDetail.length === 0)
|
|
19723
|
-
return false;
|
|
19724
|
-
const normalizedBasis = normalizeDetailEchoText(basisTexts.join(`
|
|
19725
|
-
`));
|
|
19726
|
-
if (normalizedBasis.length > 0 && normalizedDetail === normalizedBasis)
|
|
19727
|
-
return true;
|
|
19728
|
-
return stripped.label !== undefined && PREFIX_ONLY_ECHO_LABEL_RE.test(stripped.label);
|
|
19729
|
-
}
|
|
19730
|
-
function fencedBlocksIn(value) {
|
|
19731
|
-
return [...value.matchAll(FENCED_DETAIL_BLOCK_RE)].map((match) => normalizeMarkdown(match[0]).trim()).filter((block) => block.length > 0);
|
|
19732
|
-
}
|
|
19733
|
-
function basisText(value) {
|
|
19734
|
-
return typeof value === "string" ? value : value.join(`
|
|
19735
|
-
`);
|
|
19736
|
-
}
|
|
19737
|
-
function hasCitedFencedDetail(detail, basisTexts) {
|
|
19738
|
-
const cited = normalizeMarkdown(basisText(basisTexts)).trim();
|
|
19739
|
-
if (cited.length === 0)
|
|
19740
|
-
return false;
|
|
19741
|
-
return fencedBlocksIn(detail).some((block) => cited.includes(block));
|
|
19742
|
-
}
|
|
19743
|
-
function renderableSectionDetail(detail) {
|
|
19744
|
-
if (detail === undefined || detail.trim().length === 0)
|
|
19745
|
-
return;
|
|
19746
|
-
return isEvidenceEchoDetail(detail) ? undefined : detail;
|
|
19747
|
-
}
|
|
19748
|
-
var EVIDENCE_ECHO_PREFIX_RE, PREFIX_ONLY_ECHO_LABEL_RE, FENCED_DETAIL_BLOCK_RE;
|
|
19749
|
-
var init_sectionDetail = __esm(() => {
|
|
19750
|
-
init_normalize();
|
|
19751
|
-
EVIDENCE_ECHO_PREFIX_RE = /^\s*(原文|原始文本|原始引用|引用|证据|source|raw|quote|original)\s*[::]\s*/iu;
|
|
19752
|
-
PREFIX_ONLY_ECHO_LABEL_RE = /^(?:原文|原始文本|原始引用|引用|证据)$/iu;
|
|
19753
|
-
FENCED_DETAIL_BLOCK_RE = /```[^\n`]*\n[\s\S]*?```|~~~[^\n~]*\n[\s\S]*?~~~/gu;
|
|
19754
|
-
});
|
|
19755
|
-
|
|
19756
19766
|
// src/lib/nodeRenderer.ts
|
|
19757
19767
|
function sectionOrdinal(id2) {
|
|
19758
19768
|
const match = /^section-(\d+)$/.exec(id2);
|
|
@@ -19800,48 +19810,51 @@ function renderFrontmatter(node2) {
|
|
|
19800
19810
|
frontmatter.symbol_kind = node2.symbol_kind;
|
|
19801
19811
|
return import_yaml10.default.stringify(frontmatter).trimEnd();
|
|
19802
19812
|
}
|
|
19813
|
+
function encodeAttr(value) {
|
|
19814
|
+
return value.replace(/&/gu, "&").replace(/"/gu, """).replace(/-/gu, (match, offset, full) => full[offset - 1] === "-" || full[offset + 1] === "-" ? "-" : match);
|
|
19815
|
+
}
|
|
19816
|
+
function renderAttrs(attrs) {
|
|
19817
|
+
return attrs.map(([key, value]) => `${key}="${encodeAttr(value)}"`).join(" ");
|
|
19818
|
+
}
|
|
19803
19819
|
function renderSectionComment(section) {
|
|
19804
19820
|
const attrs = [];
|
|
19821
|
+
attrs.push(`id="${encodeAttr(section.id)}"`);
|
|
19822
|
+
attrs.push(`kind="${encodeAttr(section.kind)}"`);
|
|
19823
|
+
attrs.push(`source_ref="${encodeAttr(section.source_ref.length > 0 ? section.source_ref : "-")}"`);
|
|
19805
19824
|
if (section.status !== SectionStatus.active) {
|
|
19806
|
-
attrs.push(`status
|
|
19825
|
+
attrs.push(`status="${encodeAttr(section.status)}"`);
|
|
19807
19826
|
}
|
|
19808
19827
|
if (section.confidence !== Confidence.confirmed) {
|
|
19809
|
-
attrs.push(`confidence
|
|
19828
|
+
attrs.push(`confidence="${encodeAttr(section.confidence)}"`);
|
|
19810
19829
|
}
|
|
19811
19830
|
if (section.refers_to_nodes && section.refers_to_nodes.length > 0) {
|
|
19812
|
-
attrs.push(`refers_to_nodes
|
|
19831
|
+
attrs.push(`refers_to_nodes="${encodeAttr(section.refers_to_nodes.join(","))}"`);
|
|
19813
19832
|
}
|
|
19814
19833
|
if (section.workspace_id !== undefined) {
|
|
19815
|
-
attrs.push(`workspace_id
|
|
19834
|
+
attrs.push(`workspace_id="${encodeAttr(section.workspace_id)}"`);
|
|
19816
19835
|
}
|
|
19817
19836
|
if (section.valid_from !== undefined) {
|
|
19818
|
-
attrs.push(`valid_from
|
|
19837
|
+
attrs.push(`valid_from="${encodeAttr(String(section.valid_from))}"`);
|
|
19819
19838
|
}
|
|
19820
19839
|
if (section.valid_until !== undefined) {
|
|
19821
|
-
attrs.push(`valid_until
|
|
19840
|
+
attrs.push(`valid_until="${encodeAttr(String(section.valid_until))}"`);
|
|
19822
19841
|
}
|
|
19823
|
-
const relationLines = section.relations?.map((relation) => `<!--
|
|
19824
|
-
|
|
19825
|
-
|
|
19842
|
+
const relationLines = section.relations?.map((relation) => `<!-- c4a:relation ${renderAttrs([
|
|
19843
|
+
["target", `${relation.target_slug}/${relation.target_section_id}`],
|
|
19844
|
+
["relation", relation.relation]
|
|
19845
|
+
])} -->`) ?? [];
|
|
19846
|
+
const head = `<!-- c4a:section ${attrs.join(" ")} -->`;
|
|
19826
19847
|
return [head, ...relationLines].join(`
|
|
19827
19848
|
`);
|
|
19828
19849
|
}
|
|
19829
|
-
function
|
|
19830
|
-
|
|
19831
|
-
|
|
19832
|
-
|
|
19833
|
-
|
|
19834
|
-
|
|
19835
|
-
|
|
19836
|
-
|
|
19837
|
-
for (const line of detail.split(`
|
|
19838
|
-
`)) {
|
|
19839
|
-
lines.push(`> ${line}`);
|
|
19840
|
-
}
|
|
19841
|
-
lines.push(">");
|
|
19842
|
-
lines.push("> </details>");
|
|
19843
|
-
}
|
|
19844
|
-
return lines.join(`
|
|
19850
|
+
function renderSectionBody(section) {
|
|
19851
|
+
return [
|
|
19852
|
+
renderSectionComment(section),
|
|
19853
|
+
...section.summary !== undefined ? ["<!-- c4a:summary -->", section.summary.trim(), "<!-- /c4a:summary -->", ""] : [],
|
|
19854
|
+
section.content.trim(),
|
|
19855
|
+
...section.raw !== undefined ? ["", "<!-- c4a:raw -->", section.raw.trim(), "<!-- /c4a:raw -->"] : [],
|
|
19856
|
+
"<!-- /c4a:section -->"
|
|
19857
|
+
].join(`
|
|
19845
19858
|
`);
|
|
19846
19859
|
}
|
|
19847
19860
|
function groupSections(sections) {
|
|
@@ -19862,8 +19875,7 @@ function renderSectionGroups(sections, headingLevel) {
|
|
|
19862
19875
|
const groupSections2 = grouped.get(title) ?? [];
|
|
19863
19876
|
if (groupSections2.length === 0)
|
|
19864
19877
|
continue;
|
|
19865
|
-
const renderedSections = groupSections2.map(
|
|
19866
|
-
`));
|
|
19878
|
+
const renderedSections = groupSections2.map(renderSectionBody);
|
|
19867
19879
|
parts.push([`${hashes} ${title}`, "", renderedSections.join(`
|
|
19868
19880
|
|
|
19869
19881
|
`)].join(`
|
|
@@ -19998,7 +20010,6 @@ var import_yaml10, SECTION_RENDER_ORDER_MAP;
|
|
|
19998
20010
|
var init_nodeRenderer = __esm(() => {
|
|
19999
20011
|
init_knowledge();
|
|
20000
20012
|
init_nodeDisplayGroups();
|
|
20001
|
-
init_sectionDetail();
|
|
20002
20013
|
import_yaml10 = __toESM(require_dist(), 1);
|
|
20003
20014
|
SECTION_RENDER_ORDER_MAP = new Map(SECTION_RENDER_ORDER.map((kind, index) => [kind, index]));
|
|
20004
20015
|
});
|
|
@@ -21258,6 +21269,7 @@ function sectionHitFromNode(nodeSlug, nodeUpdated, section) {
|
|
|
21258
21269
|
node_slug: nodeSlug,
|
|
21259
21270
|
section_id: section.id,
|
|
21260
21271
|
kind: section.kind,
|
|
21272
|
+
...section.summary !== undefined ? { summary: section.summary } : {},
|
|
21261
21273
|
content: section.content,
|
|
21262
21274
|
source_ref: section.source_ref,
|
|
21263
21275
|
updated: nodeUpdated,
|
|
@@ -21505,7 +21517,7 @@ function buildTermIndex(input) {
|
|
|
21505
21517
|
addTextPostings(postings, [node2.slug, node2.title, node2.summary, ...node2.aliases, ...node2.tags].filter((value) => typeof value === "string").join(" "), { node_slug: node2.slug, field: "node" });
|
|
21506
21518
|
}
|
|
21507
21519
|
for (const section of input.sections) {
|
|
21508
|
-
addTextPostings(postings, [section.content, section.detail, section.source_ref].filter((value) => typeof value === "string").join(" "), { node_slug: section.node_slug, section_id: section.section_id, field: "section" });
|
|
21520
|
+
addTextPostings(postings, [section.summary, section.content, section.detail, section.source_ref].filter((value) => typeof value === "string").join(" "), { node_slug: section.node_slug, section_id: section.section_id, field: "section" });
|
|
21509
21521
|
}
|
|
21510
21522
|
for (const source2 of input.sources) {
|
|
21511
21523
|
addTextPostings(postings, [source2.source_id, source2.title, source2.origin, source2.latest_snapshot_file].filter((value) => typeof value === "string").join(" "), { node_slug: source2.source_id, field: "source" });
|
|
@@ -22137,6 +22149,8 @@ function semanticRecordSourceIds(decision, evidence) {
|
|
|
22137
22149
|
function shouldRecordSemanticDecision(decision, evidence) {
|
|
22138
22150
|
if (decision.action !== "omit")
|
|
22139
22151
|
return true;
|
|
22152
|
+
if (decision.decided_by === "cli_reviewed_no_write")
|
|
22153
|
+
return true;
|
|
22140
22154
|
return semanticRecordSourceIds(decision, evidence).some((sourceId) => sourceId.startsWith("note:"));
|
|
22141
22155
|
}
|
|
22142
22156
|
async function recordSemanticDecisions(input) {
|
|
@@ -22403,7 +22417,9 @@ function archiveRecordsFromNode(input) {
|
|
|
22403
22417
|
node_title: input.parsed.node.title,
|
|
22404
22418
|
section_id: section.id,
|
|
22405
22419
|
kind: section.kind,
|
|
22420
|
+
...section.summary !== undefined ? { summary: section.summary } : {},
|
|
22406
22421
|
content: section.content,
|
|
22422
|
+
...section.raw !== undefined ? { raw: section.raw } : {},
|
|
22407
22423
|
...section.detail !== undefined ? { detail: section.detail } : {},
|
|
22408
22424
|
source_ref: section.source_ref,
|
|
22409
22425
|
source_id: input.manifest.source_id,
|
|
@@ -22507,7 +22523,9 @@ async function buildRetrievalIndex(input) {
|
|
|
22507
22523
|
node_title: node2.parsed.node.title,
|
|
22508
22524
|
section_id: section.id,
|
|
22509
22525
|
kind: section.kind,
|
|
22526
|
+
...section.summary !== undefined ? { summary: section.summary } : {},
|
|
22510
22527
|
content: section.content,
|
|
22528
|
+
...section.raw !== undefined ? { raw: section.raw } : {},
|
|
22511
22529
|
...section.detail !== undefined ? { detail: section.detail } : {},
|
|
22512
22530
|
source_ref: section.source_ref,
|
|
22513
22531
|
...sourceId !== undefined ? { source_id: sourceId } : {},
|
|
@@ -22951,6 +22969,112 @@ var init_workspaceCache = __esm(() => {
|
|
|
22951
22969
|
init_inputSummary();
|
|
22952
22970
|
});
|
|
22953
22971
|
|
|
22972
|
+
// src/workflow/currentWorkflowErrors.ts
|
|
22973
|
+
function stateScope(state) {
|
|
22974
|
+
return state.scope_id ?? state.workflow_id;
|
|
22975
|
+
}
|
|
22976
|
+
function legacyWorkflowError(result) {
|
|
22977
|
+
const hint = {
|
|
22978
|
+
code: "workflow-schema-legacy",
|
|
22979
|
+
severity: "warning",
|
|
22980
|
+
message: "Current workflow state uses an unsupported schema version.",
|
|
22981
|
+
next_action: "Run `context workflow status` to inspect it, then rebuild or abandon the legacy workflow before writing.",
|
|
22982
|
+
command: "context workflow abandon --current"
|
|
22983
|
+
};
|
|
22984
|
+
return new ContextError(ExitCode.WorkspaceStateError, "current workflow schema is legacy; rebuild or abandon before writing", {
|
|
22985
|
+
category: ErrorCategory.WorkspaceStateInvalid,
|
|
22986
|
+
path: result.path,
|
|
22987
|
+
schema_version: result.schema_version,
|
|
22988
|
+
agent_hints: [hint]
|
|
22989
|
+
});
|
|
22990
|
+
}
|
|
22991
|
+
function crossFamilyError(active, requested) {
|
|
22992
|
+
const abandonCommand = `context workflow abandon --workflow-id ${active.workflow_id}`;
|
|
22993
|
+
const hint = {
|
|
22994
|
+
code: "workflow-cross-family-rejected",
|
|
22995
|
+
severity: "error",
|
|
22996
|
+
message: `Active ${active.family} workflow is at stage ${active.stage}; cannot start ${requested}.`,
|
|
22997
|
+
next_action: "Inspect and continue the active workflow. Abandon it only when you intentionally want to discard that in-progress work; if you meant another repository, change to that workspace root first.",
|
|
22998
|
+
command: "context workflow status --format json",
|
|
22999
|
+
diagnostics: {
|
|
23000
|
+
discard_command: abandonCommand,
|
|
23001
|
+
requested_family: requested
|
|
23002
|
+
}
|
|
23003
|
+
};
|
|
23004
|
+
return new ContextError(ExitCode.WorkspaceStateError, `active ${active.family} workflow ${active.workflow_id} is at ${active.stage}; cannot run ${requested}`, {
|
|
23005
|
+
category: ErrorCategory.WorkspaceStateInvalid,
|
|
23006
|
+
workflow_id: active.workflow_id,
|
|
23007
|
+
family: active.family,
|
|
23008
|
+
stage: active.stage,
|
|
23009
|
+
requested_family: requested,
|
|
23010
|
+
agent_hints: [hint]
|
|
23011
|
+
});
|
|
23012
|
+
}
|
|
23013
|
+
function rawUpdateBlockedError(active) {
|
|
23014
|
+
const abandonCommand = `context workflow abandon --workflow-id ${active.workflow_id}`;
|
|
23015
|
+
const hint = {
|
|
23016
|
+
code: "workflow-cross-family-rejected",
|
|
23017
|
+
severity: "error",
|
|
23018
|
+
message: `Active ${active.family} workflow is at stage ${active.stage}; cannot change raw sources.`,
|
|
23019
|
+
next_action: "Inspect and continue the active workflow. Capture/raw updates must wait until it is finished; abandon only when you intentionally want to discard that workflow.",
|
|
23020
|
+
command: "context workflow status --format json",
|
|
23021
|
+
diagnostics: {
|
|
23022
|
+
discard_command: abandonCommand,
|
|
23023
|
+
requested_family: "capture"
|
|
23024
|
+
}
|
|
23025
|
+
};
|
|
23026
|
+
return new ContextError(ExitCode.WorkspaceStateError, `active ${active.family} workflow ${active.workflow_id} is at ${active.stage}; cannot capture or update raw sources`, {
|
|
23027
|
+
category: ErrorCategory.WorkspaceStateInvalid,
|
|
23028
|
+
workflow_id: active.workflow_id,
|
|
23029
|
+
family: active.family,
|
|
23030
|
+
stage: active.stage,
|
|
23031
|
+
requested_family: "capture",
|
|
23032
|
+
agent_hints: [hint]
|
|
23033
|
+
});
|
|
23034
|
+
}
|
|
23035
|
+
function activeNodeRunError(active, requestedNodeRun) {
|
|
23036
|
+
const hint = {
|
|
23037
|
+
code: "workflow-active-node-run-rejected",
|
|
23038
|
+
severity: "error",
|
|
23039
|
+
message: `Active compile workflow is locked on ${active.active_node_run ?? "unknown node run"} at stage ${active.stage}.`,
|
|
23040
|
+
next_action: "Finish, close, or abandon the active node run before reviewing or applying another node.",
|
|
23041
|
+
command: "context workflow status"
|
|
23042
|
+
};
|
|
23043
|
+
return new ContextError(ExitCode.WorkspaceStateError, `active compile workflow ${active.workflow_id} is locked on ${active.active_node_run}; cannot switch to ${requestedNodeRun}`, {
|
|
23044
|
+
category: ErrorCategory.WorkspaceStateInvalid,
|
|
23045
|
+
workflow_id: active.workflow_id,
|
|
23046
|
+
family: active.family,
|
|
23047
|
+
stage: active.stage,
|
|
23048
|
+
active_node_run: active.active_node_run,
|
|
23049
|
+
requested_node_run: requestedNodeRun,
|
|
23050
|
+
agent_hints: [hint]
|
|
23051
|
+
});
|
|
23052
|
+
}
|
|
23053
|
+
function scopeConflictError(active, requestedScope) {
|
|
23054
|
+
const activeScope = stateScope(active);
|
|
23055
|
+
const hint = {
|
|
23056
|
+
code: "workflow-scope-conflict",
|
|
23057
|
+
severity: "error",
|
|
23058
|
+
message: `Active ${active.family} workflow is scoped to ${activeScope}; cannot switch to ${requestedScope}.`,
|
|
23059
|
+
next_action: "Continue, close, or abandon the active workflow before starting another scope.",
|
|
23060
|
+
command: "context workflow status"
|
|
23061
|
+
};
|
|
23062
|
+
return new ContextError(ExitCode.WorkspaceStateError, `active ${active.family} workflow ${active.workflow_id} is scoped to ${activeScope}; cannot switch to ${requestedScope}`, {
|
|
23063
|
+
category: ErrorCategory.WorkspaceStateInvalid,
|
|
23064
|
+
workflow_id: active.workflow_id,
|
|
23065
|
+
family: active.family,
|
|
23066
|
+
stage: active.stage,
|
|
23067
|
+
scope_id: activeScope,
|
|
23068
|
+
requested_scope_id: requestedScope,
|
|
23069
|
+
agent_hints: [hint]
|
|
23070
|
+
});
|
|
23071
|
+
}
|
|
23072
|
+
var init_currentWorkflowErrors = __esm(() => {
|
|
23073
|
+
init_cliFeedback();
|
|
23074
|
+
init_errors();
|
|
23075
|
+
init_exitCode();
|
|
23076
|
+
});
|
|
23077
|
+
|
|
22954
23078
|
// src/workflow/currentWorkflow.ts
|
|
22955
23079
|
import { randomBytes } from "node:crypto";
|
|
22956
23080
|
import { mkdir as mkdir10, readFile as readFile18, readdir as readdir6, rm as rm4, writeFile as writeFile7 } from "node:fs/promises";
|
|
@@ -23017,16 +23141,21 @@ function workflowNextAction(state) {
|
|
|
23017
23141
|
function workflowSummaryLine(state) {
|
|
23018
23142
|
if (!state)
|
|
23019
23143
|
return false;
|
|
23020
|
-
|
|
23144
|
+
const mode = state.execution_mode === "delegated" ? ", delegated" : "";
|
|
23145
|
+
return `workflow: ${state.family} at ${state.stage} (scope: ${workflowScope(state)}${mode})`;
|
|
23021
23146
|
}
|
|
23022
23147
|
function workflowMetadata(state) {
|
|
23023
|
-
|
|
23148
|
+
const metadata2 = {
|
|
23024
23149
|
workflow_id: state.workflow_id,
|
|
23025
23150
|
family: state.family,
|
|
23026
23151
|
stage: state.stage,
|
|
23027
23152
|
scope_id: workflowScope(state),
|
|
23028
23153
|
next_action: workflowNextAction(state)
|
|
23029
23154
|
};
|
|
23155
|
+
return state.execution_mode !== undefined ? { ...metadata2, execution_mode: state.execution_mode } : metadata2;
|
|
23156
|
+
}
|
|
23157
|
+
function isDelegatedWorkflow(state) {
|
|
23158
|
+
return state?.execution_mode === "delegated";
|
|
23030
23159
|
}
|
|
23031
23160
|
function isObject3(value) {
|
|
23032
23161
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -23053,6 +23182,13 @@ function parseWorkflowState(raw) {
|
|
|
23053
23182
|
created_at: raw.created_at,
|
|
23054
23183
|
updated_at: raw.updated_at,
|
|
23055
23184
|
review_policy: raw.review_policy === "skipped" ? "skipped" : "required",
|
|
23185
|
+
...raw.execution_mode === "delegated" || raw.execution_mode === "manual" ? { execution_mode: raw.execution_mode } : {},
|
|
23186
|
+
...isObject3(raw.delegated_authority) && raw.delegated_authority.source === "user_conversation" && raw.delegated_authority.scope === "low_risk_review_decisions" ? {
|
|
23187
|
+
delegated_authority: {
|
|
23188
|
+
source: "user_conversation",
|
|
23189
|
+
scope: "low_risk_review_decisions"
|
|
23190
|
+
}
|
|
23191
|
+
} : {},
|
|
23056
23192
|
...typeof raw.scope_id === "string" ? { scope_id: raw.scope_id } : {},
|
|
23057
23193
|
...typeof raw.active_node_run === "string" ? { active_node_run: raw.active_node_run } : {}
|
|
23058
23194
|
};
|
|
@@ -23083,102 +23219,6 @@ async function writeCurrentWorkflow(ctxDir, state) {
|
|
|
23083
23219
|
await mkdir10(dirname9(snapshotPath), { recursive: true });
|
|
23084
23220
|
await writeFile7(snapshotPath, import_yaml15.default.stringify(state), "utf8");
|
|
23085
23221
|
}
|
|
23086
|
-
function legacyWorkflowError(result) {
|
|
23087
|
-
const hint = {
|
|
23088
|
-
code: "workflow-schema-legacy",
|
|
23089
|
-
severity: "warning",
|
|
23090
|
-
message: "Current workflow state uses an unsupported schema version.",
|
|
23091
|
-
next_action: "Run `context workflow status` to inspect it, then rebuild or abandon the legacy workflow before writing.",
|
|
23092
|
-
command: "context workflow abandon --current"
|
|
23093
|
-
};
|
|
23094
|
-
return new ContextError(ExitCode.WorkspaceStateError, "current workflow schema is legacy; rebuild or abandon before writing", {
|
|
23095
|
-
category: ErrorCategory.WorkspaceStateInvalid,
|
|
23096
|
-
path: result.path,
|
|
23097
|
-
schema_version: result.schema_version,
|
|
23098
|
-
agent_hints: [hint]
|
|
23099
|
-
});
|
|
23100
|
-
}
|
|
23101
|
-
function crossFamilyError(active, requested) {
|
|
23102
|
-
const abandonCommand = `context workflow abandon --workflow-id ${active.workflow_id}`;
|
|
23103
|
-
const hint = {
|
|
23104
|
-
code: "workflow-cross-family-rejected",
|
|
23105
|
-
severity: "error",
|
|
23106
|
-
message: `Active ${active.family} workflow is at stage ${active.stage}; cannot start ${requested}.`,
|
|
23107
|
-
next_action: "Inspect and continue the active workflow. Abandon it only when you intentionally want to discard that in-progress work; if you meant another repository, change to that workspace root first.",
|
|
23108
|
-
command: "context workflow status --format json",
|
|
23109
|
-
diagnostics: {
|
|
23110
|
-
discard_command: abandonCommand,
|
|
23111
|
-
requested_family: requested
|
|
23112
|
-
}
|
|
23113
|
-
};
|
|
23114
|
-
return new ContextError(ExitCode.WorkspaceStateError, `active ${active.family} workflow ${active.workflow_id} is at ${active.stage}; cannot run ${requested}`, {
|
|
23115
|
-
category: ErrorCategory.WorkspaceStateInvalid,
|
|
23116
|
-
workflow_id: active.workflow_id,
|
|
23117
|
-
family: active.family,
|
|
23118
|
-
stage: active.stage,
|
|
23119
|
-
requested_family: requested,
|
|
23120
|
-
agent_hints: [hint]
|
|
23121
|
-
});
|
|
23122
|
-
}
|
|
23123
|
-
function rawUpdateBlockedError(active) {
|
|
23124
|
-
const abandonCommand = `context workflow abandon --workflow-id ${active.workflow_id}`;
|
|
23125
|
-
const hint = {
|
|
23126
|
-
code: "workflow-cross-family-rejected",
|
|
23127
|
-
severity: "error",
|
|
23128
|
-
message: `Active ${active.family} workflow is at stage ${active.stage}; cannot change raw sources.`,
|
|
23129
|
-
next_action: "Inspect and continue the active workflow. Capture/raw updates must wait until it is finished; abandon only when you intentionally want to discard that workflow.",
|
|
23130
|
-
command: "context workflow status --format json",
|
|
23131
|
-
diagnostics: {
|
|
23132
|
-
discard_command: abandonCommand,
|
|
23133
|
-
requested_family: "capture"
|
|
23134
|
-
}
|
|
23135
|
-
};
|
|
23136
|
-
return new ContextError(ExitCode.WorkspaceStateError, `active ${active.family} workflow ${active.workflow_id} is at ${active.stage}; cannot capture or update raw sources`, {
|
|
23137
|
-
category: ErrorCategory.WorkspaceStateInvalid,
|
|
23138
|
-
workflow_id: active.workflow_id,
|
|
23139
|
-
family: active.family,
|
|
23140
|
-
stage: active.stage,
|
|
23141
|
-
requested_family: "capture",
|
|
23142
|
-
agent_hints: [hint]
|
|
23143
|
-
});
|
|
23144
|
-
}
|
|
23145
|
-
function activeNodeRunError(active, requestedNodeRun) {
|
|
23146
|
-
const hint = {
|
|
23147
|
-
code: "workflow-active-node-run-rejected",
|
|
23148
|
-
severity: "error",
|
|
23149
|
-
message: `Active compile workflow is locked on ${active.active_node_run ?? "unknown node run"} at stage ${active.stage}.`,
|
|
23150
|
-
next_action: "Finish, close, or abandon the active node run before reviewing or applying another node.",
|
|
23151
|
-
command: "context workflow status"
|
|
23152
|
-
};
|
|
23153
|
-
return new ContextError(ExitCode.WorkspaceStateError, `active compile workflow ${active.workflow_id} is locked on ${active.active_node_run}; cannot switch to ${requestedNodeRun}`, {
|
|
23154
|
-
category: ErrorCategory.WorkspaceStateInvalid,
|
|
23155
|
-
workflow_id: active.workflow_id,
|
|
23156
|
-
family: active.family,
|
|
23157
|
-
stage: active.stage,
|
|
23158
|
-
active_node_run: active.active_node_run,
|
|
23159
|
-
requested_node_run: requestedNodeRun,
|
|
23160
|
-
agent_hints: [hint]
|
|
23161
|
-
});
|
|
23162
|
-
}
|
|
23163
|
-
function scopeConflictError(active, requestedScope) {
|
|
23164
|
-
const activeScope = workflowScope(active);
|
|
23165
|
-
const hint = {
|
|
23166
|
-
code: "workflow-scope-conflict",
|
|
23167
|
-
severity: "error",
|
|
23168
|
-
message: `Active ${active.family} workflow is scoped to ${activeScope}; cannot switch to ${requestedScope}.`,
|
|
23169
|
-
next_action: "Continue, close, or abandon the active workflow before starting another scope.",
|
|
23170
|
-
command: "context workflow status"
|
|
23171
|
-
};
|
|
23172
|
-
return new ContextError(ExitCode.WorkspaceStateError, `active ${active.family} workflow ${active.workflow_id} is scoped to ${activeScope}; cannot switch to ${requestedScope}`, {
|
|
23173
|
-
category: ErrorCategory.WorkspaceStateInvalid,
|
|
23174
|
-
workflow_id: active.workflow_id,
|
|
23175
|
-
family: active.family,
|
|
23176
|
-
stage: active.stage,
|
|
23177
|
-
scope_id: activeScope,
|
|
23178
|
-
requested_scope_id: requestedScope,
|
|
23179
|
-
agent_hints: [hint]
|
|
23180
|
-
});
|
|
23181
|
-
}
|
|
23182
23222
|
function createState(input, now) {
|
|
23183
23223
|
const workflowId = createWorkflowId(input.family, now);
|
|
23184
23224
|
const timestamp = now.toISOString();
|
|
@@ -23191,12 +23231,14 @@ function createState(input, now) {
|
|
|
23191
23231
|
created_at: timestamp,
|
|
23192
23232
|
updated_at: timestamp,
|
|
23193
23233
|
review_policy: input.reviewPolicy ?? "required",
|
|
23234
|
+
...input.executionMode !== undefined ? { execution_mode: input.executionMode } : {},
|
|
23235
|
+
...input.delegatedAuthority !== undefined ? { delegated_authority: input.delegatedAuthority } : {},
|
|
23194
23236
|
...input.scopeId !== undefined ? { scope_id: input.scopeId } : {},
|
|
23195
23237
|
...input.activeNodeRun !== undefined ? { active_node_run: input.activeNodeRun } : {}
|
|
23196
23238
|
};
|
|
23197
23239
|
}
|
|
23198
23240
|
function updateState(state, input, now) {
|
|
23199
|
-
|
|
23241
|
+
const next = {
|
|
23200
23242
|
...state,
|
|
23201
23243
|
stage: input.stage ?? state.stage,
|
|
23202
23244
|
input_digests: { ...state.input_digests, ...input.inputDigests ?? {} },
|
|
@@ -23205,11 +23247,32 @@ function updateState(state, input, now) {
|
|
|
23205
23247
|
...input.scopeId !== undefined ? { scope_id: input.scopeId } : {},
|
|
23206
23248
|
...input.activeNodeRun !== undefined ? { active_node_run: input.activeNodeRun } : {}
|
|
23207
23249
|
};
|
|
23250
|
+
if (input.executionMode !== undefined)
|
|
23251
|
+
next.execution_mode = input.executionMode;
|
|
23252
|
+
if (input.delegatedAuthority !== undefined)
|
|
23253
|
+
next.delegated_authority = input.delegatedAuthority;
|
|
23254
|
+
return next;
|
|
23208
23255
|
}
|
|
23209
23256
|
async function ensureCurrentWorkflow(input) {
|
|
23210
23257
|
const now = input.now ?? new Date;
|
|
23211
23258
|
const current = await assertWorkflowWritable(input);
|
|
23212
23259
|
if (current.status === "ready" && !isTerminalWorkflowStage(current.state.stage)) {
|
|
23260
|
+
if (input.executionMode === "delegated" && current.state.execution_mode !== "delegated") {
|
|
23261
|
+
throw new ContextError(ExitCode.WorkspaceStateError, "cannot enable delegated mode after workflow creation", {
|
|
23262
|
+
category: ErrorCategory.WorkspaceStateInvalid,
|
|
23263
|
+
workflow_id: current.state.workflow_id,
|
|
23264
|
+
family: current.state.family,
|
|
23265
|
+
stage: current.state.stage,
|
|
23266
|
+
requested_execution_mode: "delegated",
|
|
23267
|
+
agent_hints: [{
|
|
23268
|
+
code: "workflow-delegated-mode-creation-only",
|
|
23269
|
+
severity: "error",
|
|
23270
|
+
message: "Delegated mode is a workflow creation-time authorization and cannot be enabled mid-workflow.",
|
|
23271
|
+
next_action: "Finish or abandon the current workflow. Start a new compile workflow with --delegated only if the user explicitly authorized delegated mode at the start of the conversation.",
|
|
23272
|
+
command: "context workflow status --format json"
|
|
23273
|
+
}]
|
|
23274
|
+
});
|
|
23275
|
+
}
|
|
23213
23276
|
const updated = updateState(current.state, input, now);
|
|
23214
23277
|
await writeCurrentWorkflow(input.ctxDir, updated);
|
|
23215
23278
|
return updated;
|
|
@@ -23358,6 +23421,7 @@ var init_currentWorkflow = __esm(() => {
|
|
|
23358
23421
|
init_errors();
|
|
23359
23422
|
init_cliFeedback();
|
|
23360
23423
|
init_exitCode();
|
|
23424
|
+
init_currentWorkflowErrors();
|
|
23361
23425
|
import_yaml15 = __toESM(require_dist(), 1);
|
|
23362
23426
|
TERMINAL_STAGES = new Set(["finalized", "closed", "abandoned"]);
|
|
23363
23427
|
ACTIVE_NODE_LOCK_STAGES = new Set(["node_prepared", "node_review_ready"]);
|
|
@@ -27622,12 +27686,12 @@ function workspaceGenerationPolicy(config) {
|
|
|
27622
27686
|
language,
|
|
27623
27687
|
source: source2,
|
|
27624
27688
|
applies_to: APPLIES_TO,
|
|
27625
|
-
instruction: `Generate knowledge titles, summaries, and user-facing reports in ${language}; keep node.summary concise (target <15 tokens, never >30 tokens); for source-bound Section content
|
|
27689
|
+
instruction: `Generate knowledge titles, node summaries, Section summaries, and user-facing reports in ${language}; keep node.summary concise (target <15 tokens, never >30 tokens); for source-bound Section content, prefer the cited source language when it differs from ${language}; preserve product names, code identifiers, CLI flags, block_id/source_ref tokens, slugs, and quoted evidence exactly when needed.`
|
|
27626
27690
|
};
|
|
27627
27691
|
}
|
|
27628
27692
|
var APPLIES_TO;
|
|
27629
27693
|
var init_generationPolicy = __esm(() => {
|
|
27630
|
-
APPLIES_TO = ["node.title", "node.summary", "section.
|
|
27694
|
+
APPLIES_TO = ["node.title", "node.summary", "section.summary", "section.content", "user_facing_report"];
|
|
27631
27695
|
});
|
|
27632
27696
|
|
|
27633
27697
|
// src/mdrive/verifyLanguage.ts
|
|
@@ -27724,9 +27788,6 @@ function findUnclosedFence(value) {
|
|
|
27724
27788
|
}
|
|
27725
27789
|
return fence ? { marker: fence.marker.repeat(fence.length), line: fence.line } : null;
|
|
27726
27790
|
}
|
|
27727
|
-
function contentStartsWithFence(value) {
|
|
27728
|
-
return openingFence(value) !== null;
|
|
27729
|
-
}
|
|
27730
27791
|
function pushNodeIssues(issues, file, node2, options = { experimentalChecks: false }) {
|
|
27731
27792
|
for (const issue of validateKnowledgeNode(node2.node)) {
|
|
27732
27793
|
issues.push({
|
|
@@ -27769,11 +27830,12 @@ function pushNodeIssues(issues, file, node2, options = { experimentalChecks: fal
|
|
|
27769
27830
|
sectionId: section.id
|
|
27770
27831
|
});
|
|
27771
27832
|
}
|
|
27772
|
-
|
|
27833
|
+
const contentFence = findUnclosedFence(section.content);
|
|
27834
|
+
if (contentFence) {
|
|
27773
27835
|
issues.push({
|
|
27774
27836
|
severity: "error",
|
|
27775
|
-
code: "section-content-
|
|
27776
|
-
message:
|
|
27837
|
+
code: "section-content-unclosed-fence",
|
|
27838
|
+
message: `section content opens fenced code block ${contentFence.marker} at content line ${contentFence.line} but does not close it`,
|
|
27777
27839
|
path: file.relativePath,
|
|
27778
27840
|
slug: node2.node.id,
|
|
27779
27841
|
sectionId: section.id
|
|
@@ -28829,6 +28891,26 @@ var init_verify = __esm(() => {
|
|
|
28829
28891
|
init_verifyWorkspaceReader();
|
|
28830
28892
|
});
|
|
28831
28893
|
|
|
28894
|
+
// src/lib/sectionDetail.ts
|
|
28895
|
+
function fencedBlocksIn(value) {
|
|
28896
|
+
return [...value.matchAll(FENCED_DETAIL_BLOCK_RE)].map((match) => normalizeMarkdown(match[0]).trim()).filter((block) => block.length > 0);
|
|
28897
|
+
}
|
|
28898
|
+
function basisText(value) {
|
|
28899
|
+
return typeof value === "string" ? value : value.join(`
|
|
28900
|
+
`);
|
|
28901
|
+
}
|
|
28902
|
+
function hasCitedFencedDetail(detail, basisTexts) {
|
|
28903
|
+
const cited = normalizeMarkdown(basisText(basisTexts)).trim();
|
|
28904
|
+
if (cited.length === 0)
|
|
28905
|
+
return false;
|
|
28906
|
+
return fencedBlocksIn(detail).some((block) => cited.includes(block));
|
|
28907
|
+
}
|
|
28908
|
+
var FENCED_DETAIL_BLOCK_RE;
|
|
28909
|
+
var init_sectionDetail = __esm(() => {
|
|
28910
|
+
init_normalize();
|
|
28911
|
+
FENCED_DETAIL_BLOCK_RE = /```[^\n`]*\n[\s\S]*?```|~~~[^\n~]*\n[\s\S]*?~~~/gu;
|
|
28912
|
+
});
|
|
28913
|
+
|
|
28832
28914
|
// src/reconcile/sourceSupport.ts
|
|
28833
28915
|
function numbersIn(text) {
|
|
28834
28916
|
return text.match(/\b\d+(?:\.\d+)*\b/gu) ?? [];
|
|
@@ -28897,7 +28979,8 @@ function hasUrlReferenceLabel(text) {
|
|
|
28897
28979
|
return regexMatches(EN_URL_REFERENCE_LABEL_RE, text) || regexMatches(CJK_URL_REFERENCE_LABEL_RE, text);
|
|
28898
28980
|
}
|
|
28899
28981
|
function diagnoseUrlReferencePreservation(input) {
|
|
28900
|
-
const proposedText = `${input.
|
|
28982
|
+
const proposedText = `${input.summary ?? ""}
|
|
28983
|
+
${input.content}
|
|
28901
28984
|
${input.detail ?? ""}`;
|
|
28902
28985
|
const citedUrls = evidenceUrlsIn(input.citedText);
|
|
28903
28986
|
const proposedUrls = evidenceUrlsIn(proposedText);
|
|
@@ -29044,14 +29127,17 @@ function sourceTextSupportDiagnostic(content, citedText, thresholds = DEFAULT_TH
|
|
|
29044
29127
|
};
|
|
29045
29128
|
}
|
|
29046
29129
|
function sourceSectionSupportDiagnostic(input) {
|
|
29130
|
+
const summary = typeof input.summary === "string" ? input.summary.trim() : "";
|
|
29047
29131
|
const detail = typeof input.detail === "string" ? input.detail.trim() : "";
|
|
29132
|
+
const content = summary.length > 0 ? `${summary}
|
|
29133
|
+
${input.content}` : input.content;
|
|
29048
29134
|
if (detail.length === 0) {
|
|
29049
|
-
return sourceTextSupportDiagnostic(
|
|
29135
|
+
return sourceTextSupportDiagnostic(content, input.citedText, thresholdsForKind(input.kind));
|
|
29050
29136
|
}
|
|
29051
29137
|
const thresholds = thresholdsForKind(input.kind);
|
|
29052
|
-
const contentDiagnostic = sourceTextSupportDiagnostic(
|
|
29138
|
+
const contentDiagnostic = sourceTextSupportDiagnostic(content, input.citedText, thresholds);
|
|
29053
29139
|
const detailDiagnostic = sourceTextSupportDiagnostic(detail, input.citedText, thresholds);
|
|
29054
|
-
const combined = sourceTextSupportDiagnostic(`${
|
|
29140
|
+
const combined = sourceTextSupportDiagnostic(`${content}
|
|
29055
29141
|
${detail}`, input.citedText, thresholds);
|
|
29056
29142
|
const detailAware = {
|
|
29057
29143
|
...combined,
|
|
@@ -29140,6 +29226,7 @@ async function findAutoNarrowedSourceRefs(input) {
|
|
|
29140
29226
|
continue;
|
|
29141
29227
|
const diagnostic = sourceSectionSupportDiagnostic({
|
|
29142
29228
|
kind: input.section.kind,
|
|
29229
|
+
summary: input.section.summary,
|
|
29143
29230
|
content: input.section.content,
|
|
29144
29231
|
detail: input.section.detail,
|
|
29145
29232
|
citedText: resolved.cited_text
|
|
@@ -29192,6 +29279,7 @@ async function rankEvidenceBlockCandidates(input) {
|
|
|
29192
29279
|
const citedText = sourceRefRangeText(input.raw, block.line_start, block.line_end);
|
|
29193
29280
|
const diagnostic = sourceSectionSupportDiagnostic({
|
|
29194
29281
|
kind: input.section.kind,
|
|
29282
|
+
summary: input.section.summary,
|
|
29195
29283
|
content: input.section.content,
|
|
29196
29284
|
detail: input.section.detail,
|
|
29197
29285
|
citedText
|
|
@@ -29241,6 +29329,7 @@ async function diagnoseSectionSourceSupport(input) {
|
|
|
29241
29329
|
};
|
|
29242
29330
|
const diagnostic = sourceSectionSupportDiagnostic({
|
|
29243
29331
|
kind: input.section.kind,
|
|
29332
|
+
summary: input.section.summary,
|
|
29244
29333
|
content: input.section.content,
|
|
29245
29334
|
detail: input.section.detail,
|
|
29246
29335
|
citedText
|
|
@@ -29265,12 +29354,12 @@ async function diagnoseSectionSourceSupport(input) {
|
|
|
29265
29354
|
}
|
|
29266
29355
|
async function validateSectionSourceSupport(input) {
|
|
29267
29356
|
const { sourceRef, diagnostic } = await diagnoseSectionSourceSupport(input);
|
|
29268
|
-
input.section.source_ref = sourceRef;
|
|
29269
29357
|
const strictFailure = input.strict === true && !isStrictlySupported(diagnostic);
|
|
29270
29358
|
if (diagnostic.verdict === "unsupported" || diagnostic.verdict === "weak" && input.allowWeak !== true || strictFailure) {
|
|
29271
29359
|
const weakGuidance = weakSourceSupportGuidance(input.action, diagnostic.verdict);
|
|
29272
29360
|
throw new Error(`${input.action} final section content is not supported by a single source_ref "${input.section.source_ref}": ` + `${formatSupportDiagnostic(diagnostic)}; choose source_ref/source_refs copied from prepared evidence that cover the exact supporting text, ` + `or use context source resolve-ref --node <slug> --text "<quote>" only when a short exact quote can locate the evidence, ` + `or choose a semantic action that matches the evidence boundary: split_then_reanchor for separable supported parts, ` + `keep_separate for an independently supported claim, or ask_user when human confirmation is required.${weakGuidance}`);
|
|
29273
29361
|
}
|
|
29362
|
+
return { sourceRef, diagnostic };
|
|
29274
29363
|
}
|
|
29275
29364
|
function weakSourceSupportGuidance(action, verdict) {
|
|
29276
29365
|
if (verdict !== "weak")
|
|
@@ -32660,7 +32749,9 @@ function candidateFromSection(section, reason, score) {
|
|
|
32660
32749
|
kind: section.kind,
|
|
32661
32750
|
score,
|
|
32662
32751
|
reasons: [reason],
|
|
32752
|
+
...section.summary !== undefined ? { summary: section.summary } : {},
|
|
32663
32753
|
content: section.content,
|
|
32754
|
+
...section.raw !== undefined ? { raw: section.raw } : {},
|
|
32664
32755
|
...section.detail !== undefined ? { detail: section.detail } : {},
|
|
32665
32756
|
confidence: section.confidence,
|
|
32666
32757
|
source_ref: section.source_ref,
|
|
@@ -32895,15 +32986,17 @@ function nearDuplicateCandidates(sections, text) {
|
|
|
32895
32986
|
return [];
|
|
32896
32987
|
const out2 = [];
|
|
32897
32988
|
for (const section of sections) {
|
|
32898
|
-
const
|
|
32899
|
-
${section.
|
|
32989
|
+
const activeText = `${section.summary ?? ""}
|
|
32990
|
+
${section.content}
|
|
32991
|
+
${section.detail ?? ""}`;
|
|
32992
|
+
const similarity = duplicateSimilarity(text, activeText);
|
|
32900
32993
|
if (similarity < 0.45)
|
|
32901
32994
|
continue;
|
|
32902
32995
|
out2.push(candidateFromSection(section, {
|
|
32903
32996
|
type: "near-duplicate",
|
|
32904
32997
|
reason: "shingle_jaccard",
|
|
32905
32998
|
score: Number(similarity.toFixed(6)),
|
|
32906
|
-
terms: overlappingTerms(text,
|
|
32999
|
+
terms: overlappingTerms(text, activeText).slice(0, 12)
|
|
32907
33000
|
}, Number(similarity.toFixed(6))));
|
|
32908
33001
|
}
|
|
32909
33002
|
return out2;
|
|
@@ -32963,6 +33056,7 @@ function archiveCandidates(input) {
|
|
|
32963
33056
|
record.source_id,
|
|
32964
33057
|
record.source_ref,
|
|
32965
33058
|
record.archive_path,
|
|
33059
|
+
record.summary,
|
|
32966
33060
|
record.content,
|
|
32967
33061
|
record.detail
|
|
32968
33062
|
].filter((value) => typeof value === "string" && value.length > 0).join(`
|
|
@@ -33114,13 +33208,16 @@ function urlsIn(text) {
|
|
|
33114
33208
|
}
|
|
33115
33209
|
function proposedTextForAction(action) {
|
|
33116
33210
|
if (action.op === "add")
|
|
33117
|
-
return `${action.
|
|
33211
|
+
return `${action.summary ?? ""}
|
|
33212
|
+
${action.content}
|
|
33118
33213
|
${action.detail ?? ""}`;
|
|
33119
33214
|
if (action.op === "update")
|
|
33120
|
-
return `${action.
|
|
33215
|
+
return `${action.summary ?? ""}
|
|
33216
|
+
${action.content ?? ""}
|
|
33121
33217
|
${action.detail ?? ""}`;
|
|
33122
33218
|
if (action.op === "supersede")
|
|
33123
|
-
return `${action.new.
|
|
33219
|
+
return `${action.new.summary ?? ""}
|
|
33220
|
+
${action.new.content}
|
|
33124
33221
|
${action.new.detail ?? ""}`;
|
|
33125
33222
|
return "";
|
|
33126
33223
|
}
|
|
@@ -33483,7 +33580,9 @@ function createSection(nodeSlug, input, sectionId, nodeType) {
|
|
|
33483
33580
|
id: sectionId,
|
|
33484
33581
|
anchor_slug: nodeSlug,
|
|
33485
33582
|
kind: input.kind,
|
|
33583
|
+
...input.summary !== undefined ? { summary: input.summary } : {},
|
|
33486
33584
|
content: input.content,
|
|
33585
|
+
...input.raw !== undefined ? { raw: input.raw } : {},
|
|
33487
33586
|
source_ref: input.source_ref,
|
|
33488
33587
|
confidence: input.confidence ?? Confidence.confirmed,
|
|
33489
33588
|
status: input.status ?? SectionStatus.active,
|
|
@@ -33504,12 +33603,12 @@ function reassignSections(node2, sections) {
|
|
|
33504
33603
|
node2.sections = sortSectionsByPriority(sections);
|
|
33505
33604
|
}
|
|
33506
33605
|
function sectionText(section) {
|
|
33507
|
-
return [section.content, section.detail].filter((value) => typeof value === "string").join(`
|
|
33606
|
+
return [section.summary, section.content, section.detail].filter((value) => typeof value === "string").join(`
|
|
33508
33607
|
`);
|
|
33509
33608
|
}
|
|
33510
33609
|
async function withInferredRefersToNodes(ctxDir, nodeSlug, input) {
|
|
33511
33610
|
const inferred = inferRefersToNodes({
|
|
33512
|
-
text: [input.content, input.detail].filter((value) => typeof value === "string").join(`
|
|
33611
|
+
text: [input.summary, input.content, input.detail].filter((value) => typeof value === "string").join(`
|
|
33513
33612
|
`),
|
|
33514
33613
|
currentNodeSlug: nodeSlug,
|
|
33515
33614
|
knownNodes: await collectKnownRefersToNodes(ctxDir),
|
|
@@ -33531,6 +33630,13 @@ async function mdriveSectionUpdate(input) {
|
|
|
33531
33630
|
}
|
|
33532
33631
|
const located = await locateNode(input.ctxDir, input.nodeSlug);
|
|
33533
33632
|
const section = findSection(input.nodeSlug, located.parsed, input.sectionId);
|
|
33633
|
+
if (input.patch.summary !== undefined) {
|
|
33634
|
+
if (input.patch.summary === null) {
|
|
33635
|
+
delete section.summary;
|
|
33636
|
+
} else {
|
|
33637
|
+
section.summary = input.patch.summary;
|
|
33638
|
+
}
|
|
33639
|
+
}
|
|
33534
33640
|
if (input.patch.detail !== undefined) {
|
|
33535
33641
|
if (input.patch.detail === null) {
|
|
33536
33642
|
delete section.detail;
|
|
@@ -33541,6 +33647,13 @@ async function mdriveSectionUpdate(input) {
|
|
|
33541
33647
|
if (input.patch.content !== undefined) {
|
|
33542
33648
|
section.content = input.patch.content;
|
|
33543
33649
|
}
|
|
33650
|
+
if (input.patch.raw !== undefined) {
|
|
33651
|
+
if (input.patch.raw === null) {
|
|
33652
|
+
delete section.raw;
|
|
33653
|
+
} else {
|
|
33654
|
+
section.raw = input.patch.raw;
|
|
33655
|
+
}
|
|
33656
|
+
}
|
|
33544
33657
|
if (input.patch.confidence !== undefined) {
|
|
33545
33658
|
section.confidence = input.patch.confidence;
|
|
33546
33659
|
}
|
|
@@ -33728,6 +33841,9 @@ var init_section = __esm(() => {
|
|
|
33728
33841
|
});
|
|
33729
33842
|
|
|
33730
33843
|
// src/workflow/compileNode.ts
|
|
33844
|
+
function uniqueSorted2(values) {
|
|
33845
|
+
return [...new Set(values.filter((value) => value.length > 0).map(sourceIdWithoutVersion))].sort((left, right) => left.localeCompare(right));
|
|
33846
|
+
}
|
|
33731
33847
|
function compileContextNodeInput(context) {
|
|
33732
33848
|
return {
|
|
33733
33849
|
node: {
|
|
@@ -33751,6 +33867,21 @@ function compileContextNodeInput(context) {
|
|
|
33751
33867
|
children: []
|
|
33752
33868
|
};
|
|
33753
33869
|
}
|
|
33870
|
+
function compileContextNoWriteNodeInput(context) {
|
|
33871
|
+
const input = compileContextNodeInput(context);
|
|
33872
|
+
const contextSources = uniqueSorted2([
|
|
33873
|
+
...context.node.context_sources ?? [],
|
|
33874
|
+
...context.node.sources ?? []
|
|
33875
|
+
]);
|
|
33876
|
+
return {
|
|
33877
|
+
...input,
|
|
33878
|
+
node: {
|
|
33879
|
+
...input.node,
|
|
33880
|
+
sources: [],
|
|
33881
|
+
...contextSources.length > 0 ? { context_sources: contextSources } : {}
|
|
33882
|
+
}
|
|
33883
|
+
};
|
|
33884
|
+
}
|
|
33754
33885
|
function compileContextLocatedNode(ctxDir, context) {
|
|
33755
33886
|
const input = compileContextNodeInput(context);
|
|
33756
33887
|
const parsed = parseNodeMarkdown(renderNodeMarkdown(input));
|
|
@@ -33772,9 +33903,18 @@ async function ensureCompileNodeExists(ctxDir, context) {
|
|
|
33772
33903
|
input: compileContextNodeInput(context)
|
|
33773
33904
|
});
|
|
33774
33905
|
}
|
|
33906
|
+
async function ensureCompileNoWriteNodeExists(ctxDir, context) {
|
|
33907
|
+
if (context.existing)
|
|
33908
|
+
return;
|
|
33909
|
+
await mdriveNodeCreate({
|
|
33910
|
+
ctxDir,
|
|
33911
|
+
input: compileContextNoWriteNodeInput(context)
|
|
33912
|
+
});
|
|
33913
|
+
}
|
|
33775
33914
|
var init_compileNode = __esm(() => {
|
|
33776
33915
|
init_nodeParser();
|
|
33777
33916
|
init_nodeRenderer();
|
|
33917
|
+
init_sources();
|
|
33778
33918
|
init_node2();
|
|
33779
33919
|
init_shared();
|
|
33780
33920
|
});
|
|
@@ -34849,6 +34989,38 @@ function assertCitationEligibleSourceRefs(sourceRefs, slug, context, label) {
|
|
|
34849
34989
|
});
|
|
34850
34990
|
}
|
|
34851
34991
|
}
|
|
34992
|
+
function lineRangeFromSourceRef(sourceRef) {
|
|
34993
|
+
const match = /\sL(\d+)-L?(\d+)@/u.exec(sourceRef);
|
|
34994
|
+
if (!match?.[1] || !match[2])
|
|
34995
|
+
return null;
|
|
34996
|
+
return { start: Number(match[1]), end: Number(match[2]) };
|
|
34997
|
+
}
|
|
34998
|
+
function lineDistance(left, right) {
|
|
34999
|
+
if (left.end < right.start)
|
|
35000
|
+
return right.start - left.end;
|
|
35001
|
+
if (right.end < left.start)
|
|
35002
|
+
return left.start - right.end;
|
|
35003
|
+
return 0;
|
|
35004
|
+
}
|
|
35005
|
+
function nearbyCitationEligibleSourceRefs(input) {
|
|
35006
|
+
const unresolvedRanges = input.unresolvedSourceRefs.map(lineRangeFromSourceRef).filter((range) => range !== null);
|
|
35007
|
+
if (unresolvedRanges.length === 0)
|
|
35008
|
+
return [];
|
|
35009
|
+
const refs = input.context.raw_snippets.filter((snippet) => typeof snippet.source_ref === "string" && snippet.source_ref.length > 0 && snippet.citation_eligible !== false && snippet.context_only !== true).map((snippet) => snippet.source_ref).filter((sourceRef, index, all) => all.indexOf(sourceRef) === index).map((sourceRef) => ({ sourceRef, range: lineRangeFromSourceRef(sourceRef) })).filter((item) => item.range !== null).map((item) => ({
|
|
35010
|
+
...item,
|
|
35011
|
+
distance: Math.min(...unresolvedRanges.map((range) => lineDistance(range, item.range)))
|
|
35012
|
+
})).filter((item) => item.distance <= 3).sort((left, right) => left.distance - right.distance || left.range.start - right.range.start);
|
|
35013
|
+
return refs.slice(0, 8).map((item) => item.sourceRef);
|
|
35014
|
+
}
|
|
35015
|
+
function normalizedForRawCompare(value) {
|
|
35016
|
+
return normalizeMarkdown(value).trim();
|
|
35017
|
+
}
|
|
35018
|
+
function rawDebugForContent(content, citedText) {
|
|
35019
|
+
const raw = citedText.trim();
|
|
35020
|
+
if (raw.length === 0)
|
|
35021
|
+
return;
|
|
35022
|
+
return normalizedForRawCompare(content) === normalizedForRawCompare(raw) ? undefined : raw;
|
|
35023
|
+
}
|
|
34852
35024
|
async function assertResolvedSourceRefs(ctxDir, sourceRefs, slug, context, label = "source_refs") {
|
|
34853
35025
|
assertCitationEligibleSourceRefs(sourceRefs, slug, context, label);
|
|
34854
35026
|
const resolved = await resolveSourceRefsToSourceRef({
|
|
@@ -34863,10 +35035,16 @@ async function assertResolvedSourceRefs(ctxDir, sourceRefs, slug, context, label
|
|
|
34863
35035
|
nodeSources: context.node.sources ?? []
|
|
34864
35036
|
});
|
|
34865
35037
|
if (diagnostics.reason === "unresolved-source-ref") {
|
|
34866
|
-
|
|
35038
|
+
const unresolvedSourceRefs = "unresolved_source_refs" in diagnostics && Array.isArray(diagnostics.unresolved_source_refs) ? diagnostics.unresolved_source_refs.filter((ref) => typeof ref === "string") : sourceRefs;
|
|
35039
|
+
const nearby = nearbyCitationEligibleSourceRefs({ unresolvedSourceRefs, context });
|
|
35040
|
+
throw draftError(slug, context, `${label} contains a source_ref that does not match a citation-eligible evidence block. Copy the exact source_ref from the source-refs view; if the intended lines span multiple blocks, use the listed block source_refs or split the action.`, {
|
|
34867
35041
|
path: label,
|
|
34868
35042
|
reasonCode: "source-ref-unknown-hash",
|
|
34869
|
-
diagnostics
|
|
35043
|
+
diagnostics: {
|
|
35044
|
+
...diagnostics,
|
|
35045
|
+
reason_hint: "The requested line range/hash is not one of this Node's citation-eligible evidence blocks; it may cross block boundaries, include context-only/ignored material, or use a stale hash.",
|
|
35046
|
+
...nearby.length > 0 ? { nearby_citation_eligible_source_refs: nearby } : {}
|
|
35047
|
+
}
|
|
34870
35048
|
});
|
|
34871
35049
|
}
|
|
34872
35050
|
throw draftError(slug, context, `${label} could not be resolved to one contiguous source_ref; split the action or include every intervening citation-eligible source_ref`, {
|
|
@@ -34878,15 +35056,28 @@ async function assertResolvedSourceRefs(ctxDir, sourceRefs, slug, context, label
|
|
|
34878
35056
|
}
|
|
34879
35057
|
async function resolveSectionInput(ctxDir, slug, context, action, options = {}) {
|
|
34880
35058
|
const sourceRef = await resolveActionSourceRef(ctxDir, slug, context, action, options);
|
|
35059
|
+
const raw = await resolveActionRawDebug(ctxDir, context, action, sourceRef);
|
|
34881
35060
|
return {
|
|
34882
35061
|
kind: action.kind,
|
|
35062
|
+
...action.summary !== undefined ? { summary: action.summary } : {},
|
|
34883
35063
|
content: action.content,
|
|
35064
|
+
...raw !== undefined ? { raw } : {},
|
|
34884
35065
|
source_ref: sourceRef,
|
|
34885
35066
|
confidence: action.confidence ?? Confidence.confirmed,
|
|
34886
35067
|
...typeof action.detail === "string" ? { detail: action.detail } : {},
|
|
34887
35068
|
...action.refers_to_nodes !== undefined ? { refers_to_nodes: action.refers_to_nodes } : {}
|
|
34888
35069
|
};
|
|
34889
35070
|
}
|
|
35071
|
+
async function resolveActionRawDebug(ctxDir, context, action, sourceRef) {
|
|
35072
|
+
if (typeof action.raw === "string" && action.raw.trim().length > 0)
|
|
35073
|
+
return action.raw.trim();
|
|
35074
|
+
const resolved = await resolveSourceRefsToEvidence({
|
|
35075
|
+
ctxDir,
|
|
35076
|
+
sourceRefs: [sourceRef],
|
|
35077
|
+
nodeSources: context.node.sources ?? []
|
|
35078
|
+
});
|
|
35079
|
+
return resolved === null ? undefined : rawDebugForContent(action.content, resolved.cited_text);
|
|
35080
|
+
}
|
|
34890
35081
|
async function resolveActionSourceRef(ctxDir, slug, context, action, options = {}) {
|
|
34891
35082
|
if (action.source_refs !== undefined) {
|
|
34892
35083
|
assertCitationEligibleSourceRefs(action.source_refs, slug, context, "source_refs");
|
|
@@ -34898,6 +35089,7 @@ async function resolveActionSourceRef(ctxDir, slug, context, action, options = {
|
|
|
34898
35089
|
section: {
|
|
34899
35090
|
content: action.content,
|
|
34900
35091
|
...action.kind !== undefined ? { kind: action.kind } : {},
|
|
35092
|
+
...action.summary !== undefined ? { summary: action.summary } : {},
|
|
34901
35093
|
...action.detail !== undefined ? { detail: action.detail } : {}
|
|
34902
35094
|
}
|
|
34903
35095
|
});
|
|
@@ -34930,6 +35122,8 @@ async function resolveUpdatePatch(ctxDir, slug, context, action) {
|
|
|
34930
35122
|
const patch = {};
|
|
34931
35123
|
if (action.content !== undefined)
|
|
34932
35124
|
patch.content = action.content;
|
|
35125
|
+
if (action.summary !== undefined)
|
|
35126
|
+
patch.summary = action.summary;
|
|
34933
35127
|
if (action.detail !== undefined)
|
|
34934
35128
|
patch.detail = action.detail;
|
|
34935
35129
|
if (action.confidence !== undefined)
|
|
@@ -34945,6 +35139,12 @@ async function resolveUpdatePatch(ctxDir, slug, context, action) {
|
|
|
34945
35139
|
});
|
|
34946
35140
|
if (resolved !== null)
|
|
34947
35141
|
patch.source_ref = resolved;
|
|
35142
|
+
if (action.content !== undefined && resolved !== null) {
|
|
35143
|
+
const raw = await resolveActionRawDebug(ctxDir, context, {
|
|
35144
|
+
content: action.content
|
|
35145
|
+
}, resolved);
|
|
35146
|
+
patch.raw = raw ?? null;
|
|
35147
|
+
}
|
|
34948
35148
|
}
|
|
34949
35149
|
return patch;
|
|
34950
35150
|
}
|
|
@@ -34958,7 +35158,9 @@ function mergeUpdateCandidate(context, sectionId, patch) {
|
|
|
34958
35158
|
}
|
|
34959
35159
|
return {
|
|
34960
35160
|
kind: current.kind,
|
|
35161
|
+
...patch.summary !== undefined ? patch.summary === null ? {} : { summary: patch.summary } : current.summary !== undefined ? { summary: current.summary } : {},
|
|
34961
35162
|
content: patch.content ?? current.content,
|
|
35163
|
+
...patch.raw !== undefined ? patch.raw === null ? {} : { raw: patch.raw } : current.raw !== undefined ? { raw: current.raw } : {},
|
|
34962
35164
|
source_ref: patch.source_ref ?? current.source_ref,
|
|
34963
35165
|
confidence: patch.confidence ?? current.confidence,
|
|
34964
35166
|
...patch.detail !== undefined ? patch.detail === null ? {} : { detail: patch.detail } : current.detail !== undefined ? { detail: current.detail } : {},
|
|
@@ -34970,6 +35172,7 @@ var init_compileDraftSourceRefs = __esm(() => {
|
|
|
34970
35172
|
init_cliFeedback();
|
|
34971
35173
|
init_sourceRef();
|
|
34972
35174
|
init_ref();
|
|
35175
|
+
init_normalize();
|
|
34973
35176
|
init_exitCode();
|
|
34974
35177
|
init_knowledge();
|
|
34975
35178
|
init_compileErrors();
|
|
@@ -34980,13 +35183,13 @@ var init_compileDraftSourceRefs = __esm(() => {
|
|
|
34980
35183
|
// src/workflow/compileDraftReferenceHints.ts
|
|
34981
35184
|
function actionText(action) {
|
|
34982
35185
|
if (action.op === "add")
|
|
34983
|
-
return [action.content, action.detail].filter(Boolean).join(`
|
|
35186
|
+
return [action.summary, action.content, action.detail].filter(Boolean).join(`
|
|
34984
35187
|
`);
|
|
34985
35188
|
if (action.op === "update")
|
|
34986
|
-
return [action.content, action.detail].filter(Boolean).join(`
|
|
35189
|
+
return [action.summary, action.content, action.detail].filter(Boolean).join(`
|
|
34987
35190
|
`);
|
|
34988
35191
|
if (action.op === "supersede")
|
|
34989
|
-
return [action.new.content, action.new.detail].filter(Boolean).join(`
|
|
35192
|
+
return [action.new.summary, action.new.content, action.new.detail].filter(Boolean).join(`
|
|
34990
35193
|
`);
|
|
34991
35194
|
return "";
|
|
34992
35195
|
}
|
|
@@ -35406,33 +35609,103 @@ function assertDraftContent(value, slug, context, label, optional = false) {
|
|
|
35406
35609
|
if (value === undefined && optional)
|
|
35407
35610
|
return;
|
|
35408
35611
|
assertDraftString(value, slug, context, label);
|
|
35409
|
-
|
|
35410
|
-
|
|
35411
|
-
|
|
35412
|
-
|
|
35612
|
+
}
|
|
35613
|
+
function assertOptionalDraftString(value, slug, context, label) {
|
|
35614
|
+
if (value !== undefined && typeof value !== "string") {
|
|
35615
|
+
throw draftError(slug, context, `${label} must be a string when present`, { path: label, reasonCode: "invalid-string" });
|
|
35616
|
+
}
|
|
35617
|
+
}
|
|
35618
|
+
function summaryTargetLength(content) {
|
|
35619
|
+
return Math.min(SUMMARY_TARGET_MAX_CHARS, Math.max(SUMMARY_TARGET_MIN_CHARS, Math.round(content.length / 10)));
|
|
35620
|
+
}
|
|
35621
|
+
function pushSummaryWarnings(input) {
|
|
35622
|
+
const content = input.content;
|
|
35623
|
+
if (content === undefined)
|
|
35624
|
+
return;
|
|
35625
|
+
const target = summaryTargetLength(content);
|
|
35626
|
+
const summary = typeof input.summary === "string" ? input.summary : undefined;
|
|
35627
|
+
if (content.length > SUMMARY_REQUIRED_CONTENT_CHARS && summary === undefined) {
|
|
35628
|
+
input.state.warnings.push({
|
|
35629
|
+
code: "compile-section-summary-missing",
|
|
35630
|
+
severity: "warning",
|
|
35631
|
+
message: `${input.label}.content is ${content.length} characters; provide a one-paragraph summary before semantic review.`,
|
|
35632
|
+
next_action: `Add ${input.label}.summary around ${target} characters (minimum ${SUMMARY_TARGET_MIN_CHARS}, recommended maximum ${SUMMARY_TARGET_MAX_CHARS}) and keep content faithful to the cited raw.`,
|
|
35633
|
+
path: `${input.label}.summary`,
|
|
35413
35634
|
diagnostics: {
|
|
35414
|
-
content_length:
|
|
35415
|
-
|
|
35416
|
-
|
|
35635
|
+
content_length: content.length,
|
|
35636
|
+
target_summary_length: target,
|
|
35637
|
+
min_summary_length: SUMMARY_TARGET_MIN_CHARS,
|
|
35638
|
+
recommended_max_summary_length: SUMMARY_TARGET_MAX_CHARS
|
|
35417
35639
|
}
|
|
35418
35640
|
});
|
|
35641
|
+
return;
|
|
35419
35642
|
}
|
|
35420
|
-
if (
|
|
35421
|
-
|
|
35422
|
-
|
|
35423
|
-
|
|
35643
|
+
if (content.length > SUMMARY_RECOMMENDED_CONTENT_CHARS && summary === undefined) {
|
|
35644
|
+
input.state.warnings.push({
|
|
35645
|
+
code: "compile-section-summary-recommended",
|
|
35646
|
+
severity: "warning",
|
|
35647
|
+
message: `${input.label}.content is ${content.length} characters; a short summary will improve query and reader UX.`,
|
|
35648
|
+
next_action: `Prefer ${input.label}.summary around ${target} characters when content is longer than ${SUMMARY_RECOMMENDED_CONTENT_CHARS} characters.`,
|
|
35649
|
+
path: `${input.label}.summary`,
|
|
35650
|
+
diagnostics: {
|
|
35651
|
+
content_length: content.length,
|
|
35652
|
+
target_summary_length: target
|
|
35653
|
+
}
|
|
35424
35654
|
});
|
|
35655
|
+
return;
|
|
35425
35656
|
}
|
|
35426
|
-
if (
|
|
35427
|
-
|
|
35428
|
-
|
|
35429
|
-
|
|
35657
|
+
if (summary === undefined)
|
|
35658
|
+
return;
|
|
35659
|
+
if (/\r|\n/u.test(summary) || /```|~~~|^#{1,6}\s|^\s*[-*+]\s/mu.test(summary)) {
|
|
35660
|
+
input.state.warnings.push({
|
|
35661
|
+
code: "compile-section-summary-format",
|
|
35662
|
+
severity: "warning",
|
|
35663
|
+
message: `${input.label}.summary should be one plain paragraph without Markdown formatting.`,
|
|
35664
|
+
next_action: "Rewrite summary as one short sentence or paragraph; keep lists, headings, and fenced code in content.",
|
|
35665
|
+
path: `${input.label}.summary`
|
|
35666
|
+
});
|
|
35667
|
+
}
|
|
35668
|
+
const lower = Math.max(1, Math.floor(target * 0.5));
|
|
35669
|
+
const upper = Math.ceil(target * 1.5);
|
|
35670
|
+
if (content.length > SUMMARY_REQUIRED_CONTENT_CHARS && (summary.length < lower || summary.length > upper)) {
|
|
35671
|
+
input.state.warnings.push({
|
|
35672
|
+
code: "compile-section-summary-length",
|
|
35673
|
+
severity: "warning",
|
|
35674
|
+
message: `${input.label}.summary is ${summary.length} characters; target is about ${target} for ${content.length}-character content.`,
|
|
35675
|
+
next_action: `Adjust summary toward ${target} characters; lenient accepted range is ${lower}-${upper}.`,
|
|
35676
|
+
path: `${input.label}.summary`,
|
|
35677
|
+
diagnostics: {
|
|
35678
|
+
content_length: content.length,
|
|
35679
|
+
summary_length: summary.length,
|
|
35680
|
+
target_summary_length: target,
|
|
35681
|
+
lenient_min_summary_length: lower,
|
|
35682
|
+
lenient_max_summary_length: upper
|
|
35683
|
+
}
|
|
35684
|
+
});
|
|
35685
|
+
} else if (summary.length > SUMMARY_LENIENT_MAX_CHARS) {
|
|
35686
|
+
input.state.warnings.push({
|
|
35687
|
+
code: "compile-section-summary-too-long",
|
|
35688
|
+
severity: "warning",
|
|
35689
|
+
message: `${input.label}.summary is ${summary.length} characters; keep summaries compact for query output.`,
|
|
35690
|
+
next_action: `Shorten summary to at most ${SUMMARY_LENIENT_MAX_CHARS} characters; preferred maximum is ${SUMMARY_TARGET_MAX_CHARS}.`,
|
|
35691
|
+
path: `${input.label}.summary`,
|
|
35692
|
+
diagnostics: {
|
|
35693
|
+
summary_length: summary.length,
|
|
35694
|
+
lenient_max_summary_length: SUMMARY_LENIENT_MAX_CHARS,
|
|
35695
|
+
recommended_max_summary_length: SUMMARY_TARGET_MAX_CHARS
|
|
35696
|
+
}
|
|
35430
35697
|
});
|
|
35431
35698
|
}
|
|
35432
35699
|
}
|
|
35433
|
-
function
|
|
35434
|
-
|
|
35435
|
-
|
|
35700
|
+
function collectDraftSummaryWarnings(output, state) {
|
|
35701
|
+
for (const [index, action] of output.actions.entries()) {
|
|
35702
|
+
if (action.op === "add") {
|
|
35703
|
+
pushSummaryWarnings({ state, content: action.content, summary: action.summary, label: `actions[${index}]` });
|
|
35704
|
+
} else if (action.op === "update") {
|
|
35705
|
+
pushSummaryWarnings({ state, content: action.content, summary: action.summary, label: `actions[${index}]` });
|
|
35706
|
+
} else if (action.op === "supersede") {
|
|
35707
|
+
pushSummaryWarnings({ state, content: action.new.content, summary: action.new.summary, label: `actions[${index}].new` });
|
|
35708
|
+
}
|
|
35436
35709
|
}
|
|
35437
35710
|
}
|
|
35438
35711
|
function assertOptionalConfidence(value, slug, context) {
|
|
@@ -35485,35 +35758,7 @@ function assertSourceRefs(value, slug, context, label) {
|
|
|
35485
35758
|
}
|
|
35486
35759
|
});
|
|
35487
35760
|
}
|
|
35488
|
-
function
|
|
35489
|
-
const body2 = value.trim();
|
|
35490
|
-
const compact2 = body2.replace(/^\s*(?:```|~~~)[^\n]*\n?/gmu, " ").replace(/^\s*(?:```|~~~)\s*$/gmu, " ").replace(/\s+/gu, " ").trim();
|
|
35491
|
-
const content = compact2.length <= MAX_DRAFT_CONTENT_CHARS ? compact2 : `${compact2.slice(0, MAX_DRAFT_CONTENT_CHARS - 3)}...`;
|
|
35492
|
-
if (body2 === content)
|
|
35493
|
-
return { content };
|
|
35494
|
-
return { content, detail: body2 };
|
|
35495
|
-
}
|
|
35496
|
-
function normalizeDraftAction(action) {
|
|
35497
|
-
if (!isRecord15(action))
|
|
35498
|
-
return action;
|
|
35499
|
-
if (action.op === "supersede" && isRecord15(action.new)) {
|
|
35500
|
-
return {
|
|
35501
|
-
...action,
|
|
35502
|
-
new: normalizeDraftAction(action.new)
|
|
35503
|
-
};
|
|
35504
|
-
}
|
|
35505
|
-
if (typeof action.body !== "string")
|
|
35506
|
-
return action;
|
|
35507
|
-
const split = bodyContent(action.body);
|
|
35508
|
-
const normalized = {
|
|
35509
|
-
...action,
|
|
35510
|
-
content: split.content,
|
|
35511
|
-
...split.detail !== undefined ? { detail: split.detail } : {}
|
|
35512
|
-
};
|
|
35513
|
-
delete normalized.body;
|
|
35514
|
-
return normalized;
|
|
35515
|
-
}
|
|
35516
|
-
function retiredFieldIssuesForRecord(record, path8, includeContentDetail) {
|
|
35761
|
+
function retiredFieldIssuesForRecord(record, path8, includeWriteFields) {
|
|
35517
35762
|
const issues = [];
|
|
35518
35763
|
for (const field of RETIRED_EXTRACTIVE_FIELDS) {
|
|
35519
35764
|
if (record[field] === undefined)
|
|
@@ -35521,27 +35766,27 @@ function retiredFieldIssuesForRecord(record, path8, includeContentDetail) {
|
|
|
35521
35766
|
issues.push({
|
|
35522
35767
|
path: `${path8}.${field}`,
|
|
35523
35768
|
reason_code: "retired-draft-field",
|
|
35524
|
-
message: `${path8}.${field} was removed in ${COMPILE_DRAFT_SCHEMA_VERSION}; emit
|
|
35769
|
+
message: `${path8}.${field} was removed in ${COMPILE_DRAFT_SCHEMA_VERSION}; emit content, optional summary, and source_refs[] only`
|
|
35525
35770
|
});
|
|
35526
35771
|
}
|
|
35527
|
-
if (
|
|
35528
|
-
for (const field of
|
|
35772
|
+
if (includeWriteFields) {
|
|
35773
|
+
for (const field of RETIRED_DRAFT_WRITE_FIELDS) {
|
|
35529
35774
|
if (record[field] === undefined)
|
|
35530
35775
|
continue;
|
|
35531
35776
|
issues.push({
|
|
35532
35777
|
path: `${path8}.${field}`,
|
|
35533
35778
|
reason_code: "retired-draft-field",
|
|
35534
|
-
message: `${path8}.${field} is
|
|
35779
|
+
message: `${path8}.${field} is not part of the compile draft write contract; emit content, optional summary, and source_refs[]`
|
|
35535
35780
|
});
|
|
35536
35781
|
}
|
|
35537
35782
|
}
|
|
35538
35783
|
return issues;
|
|
35539
35784
|
}
|
|
35540
|
-
function
|
|
35785
|
+
function contentRequiredIssue(path8) {
|
|
35541
35786
|
return {
|
|
35542
|
-
path: `${path8}.
|
|
35543
|
-
reason_code: "
|
|
35544
|
-
message: `${path8}.
|
|
35787
|
+
path: `${path8}.content`,
|
|
35788
|
+
reason_code: "content-required",
|
|
35789
|
+
message: `${path8}.content is required for Section write actions in ${COMPILE_DRAFT_SCHEMA_VERSION}`
|
|
35545
35790
|
};
|
|
35546
35791
|
}
|
|
35547
35792
|
function retiredIssuesForAction(action, path8) {
|
|
@@ -35549,14 +35794,14 @@ function retiredIssuesForAction(action, path8) {
|
|
|
35549
35794
|
return [];
|
|
35550
35795
|
const op = action.op;
|
|
35551
35796
|
const issues = retiredFieldIssuesForRecord(action, path8, op === "add" || op === "update");
|
|
35552
|
-
if (op === "add" && action.
|
|
35553
|
-
issues.push(
|
|
35797
|
+
if (op === "add" && action.content === undefined) {
|
|
35798
|
+
issues.push(contentRequiredIssue(path8));
|
|
35554
35799
|
}
|
|
35555
35800
|
if (op === "supersede") {
|
|
35556
35801
|
if (isRecord15(action.new)) {
|
|
35557
35802
|
issues.push(...retiredFieldIssuesForRecord(action.new, `${path8}.new`, true));
|
|
35558
|
-
if (action.new.
|
|
35559
|
-
issues.push(
|
|
35803
|
+
if (action.new.content === undefined) {
|
|
35804
|
+
issues.push(contentRequiredIssue(`${path8}.new`));
|
|
35560
35805
|
}
|
|
35561
35806
|
}
|
|
35562
35807
|
}
|
|
@@ -35590,10 +35835,7 @@ function rejectRetiredAgentInputFields(input, slug, context) {
|
|
|
35590
35835
|
function normalizeCompileDraftInput(input) {
|
|
35591
35836
|
if (!isRecord15(input))
|
|
35592
35837
|
return input;
|
|
35593
|
-
return
|
|
35594
|
-
...input,
|
|
35595
|
-
actions: Array.isArray(input.actions) ? input.actions.map((action) => normalizeDraftAction(action)) : input.actions
|
|
35596
|
-
};
|
|
35838
|
+
return input;
|
|
35597
35839
|
}
|
|
35598
35840
|
function rejectSingularSourceRef(action, slug, context, label) {
|
|
35599
35841
|
if (action.source_ref === undefined)
|
|
@@ -35619,12 +35861,7 @@ function rejectUnsupportedEvidenceFields(action, slug, context, label) {
|
|
|
35619
35861
|
function validateAddLikeActionShape(action, slug, context, knownSlugs, label) {
|
|
35620
35862
|
assertSectionKind(action.kind, slug, context.raw_snippets[0]?.line ?? null, context);
|
|
35621
35863
|
assertDraftContent(action.content, slug, context, `${label}.content`);
|
|
35622
|
-
|
|
35623
|
-
throw draftError(slug, context, `${label}.detail must be a string or null when present`, {
|
|
35624
|
-
path: `${label}.detail`,
|
|
35625
|
-
reasonCode: "invalid-detail"
|
|
35626
|
-
});
|
|
35627
|
-
}
|
|
35864
|
+
assertOptionalDraftString(action.summary, slug, context, `${label}.summary`);
|
|
35628
35865
|
assertOptionalConfidence(action.confidence, slug, context);
|
|
35629
35866
|
rejectUnsupportedEvidenceFields(action, slug, context, label);
|
|
35630
35867
|
rejectSingularSourceRef(action, slug, context, label);
|
|
@@ -35677,12 +35914,8 @@ function validateDraftShape(output, slug, context, knownSlugs) {
|
|
|
35677
35914
|
if (action.op === "update") {
|
|
35678
35915
|
assertDraftString(action.target_section_id, slug, context, `actions[${index}].target_section_id`);
|
|
35679
35916
|
assertDraftContent(action.content, slug, context, `actions[${index}].content`, true);
|
|
35680
|
-
if (action.
|
|
35681
|
-
|
|
35682
|
-
path: `actions[${index}].detail`,
|
|
35683
|
-
reasonCode: "invalid-detail"
|
|
35684
|
-
});
|
|
35685
|
-
}
|
|
35917
|
+
if (action.summary !== null)
|
|
35918
|
+
assertOptionalDraftString(action.summary, slug, context, `actions[${index}].summary`);
|
|
35686
35919
|
assertOptionalConfidence(action.confidence, slug, context);
|
|
35687
35920
|
rejectUnsupportedEvidenceFields(action, slug, context, `actions[${index}]`);
|
|
35688
35921
|
rejectSingularSourceRef(action, slug, context, `actions[${index}]`);
|
|
@@ -35729,7 +35962,7 @@ function validateDraftShape(output, slug, context, knownSlugs) {
|
|
|
35729
35962
|
}
|
|
35730
35963
|
}
|
|
35731
35964
|
function updateWritesEvidence(action) {
|
|
35732
|
-
return action.content !== undefined || action.
|
|
35965
|
+
return action.content !== undefined || action.summary !== undefined || action.source_ref !== undefined || action.source_refs !== undefined;
|
|
35733
35966
|
}
|
|
35734
35967
|
function hasNoWriteContextSupport(context) {
|
|
35735
35968
|
if (context.node.planned_sections === undefined || context.node.planned_sections.length > 0)
|
|
@@ -35796,6 +36029,7 @@ async function validateDraft(ctxDir, output, slug, context, options = {}) {
|
|
|
35796
36029
|
}
|
|
35797
36030
|
output = normalizeCompileDraftInput(output);
|
|
35798
36031
|
validateDraftShape(output, slug, context, knownSlugs);
|
|
36032
|
+
collectDraftSummaryWarnings(output, state);
|
|
35799
36033
|
if (output.target_node !== slug) {
|
|
35800
36034
|
throw new ContextError(ExitCode.WorkspaceStateError, `compile draft target_node "${output.target_node}" does not match requested slug "${slug}"`, { category: ErrorCategory.SchemaInvalid });
|
|
35801
36035
|
}
|
|
@@ -35832,7 +36066,7 @@ async function validateDraft(ctxDir, output, slug, context, options = {}) {
|
|
|
35832
36066
|
}
|
|
35833
36067
|
return state.warnings;
|
|
35834
36068
|
}
|
|
35835
|
-
var
|
|
36069
|
+
var SUMMARY_RECOMMENDED_CONTENT_CHARS = 160, SUMMARY_REQUIRED_CONTENT_CHARS = 200, SUMMARY_TARGET_MIN_CHARS = 10, SUMMARY_TARGET_MAX_CHARS = 120, SUMMARY_LENIENT_MAX_CHARS = 180, RETIRED_EXTRACTIVE_FIELDS, RETIRED_DRAFT_WRITE_FIELDS;
|
|
35836
36070
|
var init_compileDraftValidation = __esm(() => {
|
|
35837
36071
|
init_errors();
|
|
35838
36072
|
init_cliFeedback();
|
|
@@ -35845,6 +36079,7 @@ var init_compileDraftValidation = __esm(() => {
|
|
|
35845
36079
|
init_compileDraftChallenges();
|
|
35846
36080
|
init_compileDraftSourceRefs();
|
|
35847
36081
|
RETIRED_EXTRACTIVE_FIELDS = ["content_mode", "paraphrase_reason", "basis_spans"];
|
|
36082
|
+
RETIRED_DRAFT_WRITE_FIELDS = ["body", "detail", "raw", "rewrite"];
|
|
35848
36083
|
});
|
|
35849
36084
|
|
|
35850
36085
|
// src/lib/agentHintRegistry.ts
|
|
@@ -35885,6 +36120,7 @@ var init_agentHintRegistry = __esm(() => {
|
|
|
35885
36120
|
"compile-cover-uncovered-only-context-required",
|
|
35886
36121
|
"compile-challenges-recorded",
|
|
35887
36122
|
"compile-challenges-recorded-no-reconcile-items",
|
|
36123
|
+
"compile-delegated-workflow-entry-only",
|
|
35888
36124
|
"compile-changes-baseline-unknown",
|
|
35889
36125
|
"compile-changes-content-update-skip-align",
|
|
35890
36126
|
"compile-changes-draft-nodes",
|
|
@@ -35914,6 +36150,7 @@ var init_agentHintRegistry = __esm(() => {
|
|
|
35914
36150
|
"compile-scan-changes-required",
|
|
35915
36151
|
"compile-section-kind-guidance",
|
|
35916
36152
|
"compile-source-refs-auto-narrowed",
|
|
36153
|
+
"compile-source-refs-planned-section-groups",
|
|
35917
36154
|
"compile-source-finalize-published",
|
|
35918
36155
|
"compile-unsupported-evidence-field-rejected",
|
|
35919
36156
|
"coverage-disposition-context-inferred",
|
|
@@ -35936,7 +36173,7 @@ var init_agentHintRegistry = __esm(() => {
|
|
|
35936
36173
|
"drop-workflow-mode-required",
|
|
35937
36174
|
"evidence-manifest-schema-mismatch",
|
|
35938
36175
|
"evidence-policy-invalid",
|
|
35939
|
-
"example-
|
|
36176
|
+
"example-content-preservation",
|
|
35940
36177
|
"finalized-ownership-missing",
|
|
35941
36178
|
"init-environment-language-detected",
|
|
35942
36179
|
"init-residual-workflow-detected",
|
|
@@ -35947,7 +36184,9 @@ var init_agentHintRegistry = __esm(() => {
|
|
|
35947
36184
|
"no-reconcile-items",
|
|
35948
36185
|
"node-cycle-apply-failed-review-ready",
|
|
35949
36186
|
"node-cycle-partial-apply-failed",
|
|
36187
|
+
"node-cycle-partial-applied-review-required",
|
|
35950
36188
|
"node-cycle-review-required",
|
|
36189
|
+
"node-cycle-review-required-source-support",
|
|
35951
36190
|
"ownership-challenge-invalid",
|
|
35952
36191
|
"prefer-extract-for-short-evidence",
|
|
35953
36192
|
"query-miss-no-local-evidence",
|
|
@@ -35962,7 +36201,7 @@ var init_agentHintRegistry = __esm(() => {
|
|
|
35962
36201
|
"refresh-note-pending-compile",
|
|
35963
36202
|
"refers-to-nodes-target-unknown",
|
|
35964
36203
|
"review-errors-block-apply",
|
|
35965
|
-
"review-content-
|
|
36204
|
+
"review-content-shape",
|
|
35966
36205
|
"review-safe-defaults-partial",
|
|
35967
36206
|
"review-unknown-input-items",
|
|
35968
36207
|
"schema-errors-empty-apply-document",
|
|
@@ -36002,6 +36241,7 @@ var init_agentHintRegistry = __esm(() => {
|
|
|
36002
36241
|
"workflow-coverage-invalid",
|
|
36003
36242
|
"workflow-coverage-summary",
|
|
36004
36243
|
"workflow-cross-family-rejected",
|
|
36244
|
+
"workflow-delegated-mode-creation-only",
|
|
36005
36245
|
"workflow-finalize-locked",
|
|
36006
36246
|
"workflow-finalize-published-only",
|
|
36007
36247
|
"workflow-history-listed",
|
|
@@ -36464,7 +36704,13 @@ function hasFinalizedGraphLink2(ownership, node2) {
|
|
|
36464
36704
|
return (ownership.edges ?? []).some((edge2) => edge2.from === node2.slug || edge2.to === node2.slug);
|
|
36465
36705
|
}
|
|
36466
36706
|
function hasNoWritePlaceholderSupport(ownership, node2) {
|
|
36467
|
-
return (node2.context_sources?.length ?? 0) > 0 || hasFinalizedGraphLink2(ownership, node2);
|
|
36707
|
+
return node2.sources.length > 0 || (node2.context_sources?.length ?? 0) > 0 || hasFinalizedGraphLink2(ownership, node2);
|
|
36708
|
+
}
|
|
36709
|
+
function noWriteContextSources(node2) {
|
|
36710
|
+
return [...new Set([
|
|
36711
|
+
...node2.context_sources ?? [],
|
|
36712
|
+
...node2.sources
|
|
36713
|
+
].filter((sourceId) => sourceId.length > 0))].sort((left, right) => left.localeCompare(right));
|
|
36468
36714
|
}
|
|
36469
36715
|
async function ensureFinalizedContainerDomains(ctxDir, now) {
|
|
36470
36716
|
const ownership = await readCurrentSourceOwnership(ctxDir);
|
|
@@ -36513,13 +36759,12 @@ async function ensureFinalizedNoWritePlaceholders(ctxDir, now) {
|
|
|
36513
36759
|
for (const node2 of nodes) {
|
|
36514
36760
|
if (!isExplicitNoWriteNode(node2))
|
|
36515
36761
|
continue;
|
|
36516
|
-
if (node2.sources.length > 0)
|
|
36517
|
-
continue;
|
|
36518
36762
|
if (!hasNoWritePlaceholderSupport(ownership, node2))
|
|
36519
36763
|
continue;
|
|
36520
36764
|
if (existsSync43(finalizedNodePath(ctxDir, node2)))
|
|
36521
36765
|
continue;
|
|
36522
36766
|
const children = finalizedContainerChildren(nodes, node2);
|
|
36767
|
+
const contextSources = noWriteContextSources(node2);
|
|
36523
36768
|
await mdriveNodeCreate({
|
|
36524
36769
|
ctxDir,
|
|
36525
36770
|
input: {
|
|
@@ -36530,7 +36775,7 @@ async function ensureFinalizedNoWritePlaceholders(ctxDir, now) {
|
|
|
36530
36775
|
tags: [...node2.tags],
|
|
36531
36776
|
sources: [],
|
|
36532
36777
|
updated: now.toISOString().slice(0, 10),
|
|
36533
|
-
...
|
|
36778
|
+
...contextSources.length > 0 ? { context_sources: contextSources } : {},
|
|
36534
36779
|
...node2.summary !== undefined ? { summary: node2.summary } : {},
|
|
36535
36780
|
...node2.language !== undefined ? { language: node2.language } : {}
|
|
36536
36781
|
},
|
|
@@ -36752,10 +36997,17 @@ async function assertFinalizedKnowledgeNodesMaterialized(ctxDir) {
|
|
|
36752
36997
|
agent_hints: [{
|
|
36753
36998
|
code: "compile-close-finalized-node-missing-knowledge",
|
|
36754
36999
|
severity: "error",
|
|
36755
|
-
message: hasMatchingChallenge ? "
|
|
36756
|
-
next_action: hasMatchingChallenge ? "
|
|
37000
|
+
message: hasMatchingChallenge ? "Close cannot project a finalized Node that is neither a written knowledge article nor an explicit no-write placeholder. Recorded challenge debt documents the gap but does not unblock close." : "Close requires each finalized Node to materialize as a written knowledge article, or as an explicit no-write placeholder declared by align with planned_sections: [] and source/context/graph support.",
|
|
37001
|
+
next_action: hasMatchingChallenge ? "Resolve the recorded challenge by revising align ownership/structure or compiling the affected Node, then rerun close." : "If the Node has real citation evidence, compile it. If it is intentionally navigation-only or placeholder-only, rerun align so the Node has planned_sections: [] and its relation/placeholder blocks are context_only or ignored. If align split it incorrectly, revise/remove the Node through align.",
|
|
36757
37002
|
command: hasMatchingChallenge ? "context schema align-structure-decision" : `context compile --context ${missing[0]?.slug ?? "<node-slug>"}`,
|
|
36758
|
-
available_node_slugs: missing.map((node2) => node2.slug)
|
|
37003
|
+
available_node_slugs: missing.map((node2) => node2.slug),
|
|
37004
|
+
diagnostics: {
|
|
37005
|
+
materialized_knowledge: {
|
|
37006
|
+
article: "A CLI-written knowledge article exists for the finalized Node.",
|
|
37007
|
+
no_write_placeholder: "The finalized Node has planned_sections: [] plus source/context/graph support; close may materialize an empty placeholder.",
|
|
37008
|
+
skip_only: "A compile skip action records reviewed evidence but does not by itself materialize an arbitrary finalized Node."
|
|
37009
|
+
}
|
|
37010
|
+
}
|
|
36759
37011
|
}]
|
|
36760
37012
|
});
|
|
36761
37013
|
}
|
|
@@ -37355,11 +37607,11 @@ function actionKind(action) {
|
|
|
37355
37607
|
}
|
|
37356
37608
|
function actionContent(action) {
|
|
37357
37609
|
if (action.op === "add")
|
|
37358
|
-
return action.
|
|
37610
|
+
return action.summary ?? action.content;
|
|
37359
37611
|
if (action.op === "update")
|
|
37360
|
-
return action.
|
|
37612
|
+
return action.summary ?? action.content;
|
|
37361
37613
|
if (action.op === "supersede")
|
|
37362
|
-
return action.new.
|
|
37614
|
+
return action.new.summary ?? action.new.content;
|
|
37363
37615
|
return;
|
|
37364
37616
|
}
|
|
37365
37617
|
function actionTargetSection(action) {
|
|
@@ -37395,8 +37647,8 @@ function compileDraftAutoNarrowHint(event) {
|
|
|
37395
37647
|
return {
|
|
37396
37648
|
code: "compile-source-refs-auto-narrowed",
|
|
37397
37649
|
severity: "warning",
|
|
37398
|
-
message: `Draft ${event.path} cited ${event.original_source_refs.length} source_refs, but the Section
|
|
37399
|
-
next_action: "Keep the narrowed citation if the removed refs are unrelated, duplicate, or intentionally uncovered. If those refs contain distinct knowledge, add separate actions or expand this
|
|
37650
|
+
message: `Draft ${event.path} cited ${event.original_source_refs.length} source_refs, but the Section content is fully supported by ` + `${event.narrowed_source_refs.length}; the CLI narrowed the citation boundary.`,
|
|
37651
|
+
next_action: "Keep the narrowed citation if the removed refs are unrelated, duplicate, or intentionally uncovered. If those refs contain distinct knowledge, add separate actions or expand this content so the cited refs are actually consumed.",
|
|
37400
37652
|
op: event.op,
|
|
37401
37653
|
op_index: event.op_index,
|
|
37402
37654
|
path: event.path,
|
|
@@ -37634,6 +37886,23 @@ function assertCitationEligibleSourceRefs2(input) {
|
|
|
37634
37886
|
throw new Error(`${input.label} for node "${input.node}" contains non-citable source_ref "${sourceRef}"${role}; ` + "use pending_ownership_challenge or structure_challenge before citing this evidence");
|
|
37635
37887
|
}
|
|
37636
37888
|
}
|
|
37889
|
+
function normalizedForRawCompare2(value) {
|
|
37890
|
+
return normalizeMarkdown(value).trim();
|
|
37891
|
+
}
|
|
37892
|
+
async function rawDebugPatch(input) {
|
|
37893
|
+
if (typeof input.raw === "string" && input.raw.trim().length > 0) {
|
|
37894
|
+
return { raw: input.raw.trim() };
|
|
37895
|
+
}
|
|
37896
|
+
const resolved = await resolveSourceRefsToEvidence({
|
|
37897
|
+
ctxDir: input.ctxDir,
|
|
37898
|
+
sourceRefs: [input.sourceRef],
|
|
37899
|
+
nodeSources: input.nodeSources
|
|
37900
|
+
});
|
|
37901
|
+
const citedText = resolved?.cited_text.trim() ?? "";
|
|
37902
|
+
if (citedText.length === 0)
|
|
37903
|
+
return {};
|
|
37904
|
+
return normalizedForRawCompare2(input.content) === normalizedForRawCompare2(citedText) ? {} : { raw: citedText };
|
|
37905
|
+
}
|
|
37637
37906
|
async function resolveDraftActionSourceRef(input) {
|
|
37638
37907
|
const nodeSources = sourceRefNodeSources({
|
|
37639
37908
|
sources: input.nodeSources,
|
|
@@ -37657,6 +37926,7 @@ async function resolveDraftActionSourceRef(input) {
|
|
|
37657
37926
|
section: {
|
|
37658
37927
|
content: input.action.content,
|
|
37659
37928
|
...input.action.kind !== undefined ? { kind: input.action.kind } : {},
|
|
37929
|
+
...input.action.summary !== undefined ? { summary: input.action.summary } : {},
|
|
37660
37930
|
...input.action.detail !== undefined ? { detail: input.action.detail } : {}
|
|
37661
37931
|
}
|
|
37662
37932
|
});
|
|
@@ -37669,7 +37939,14 @@ async function resolveDraftActionSourceRef(input) {
|
|
|
37669
37939
|
});
|
|
37670
37940
|
return {
|
|
37671
37941
|
source_ref: narrowed.source_ref,
|
|
37672
|
-
source_refs: narrowed.narrowed_source_refs
|
|
37942
|
+
source_refs: narrowed.narrowed_source_refs,
|
|
37943
|
+
...await rawDebugPatch({
|
|
37944
|
+
ctxDir: input.ctxDir,
|
|
37945
|
+
nodeSources,
|
|
37946
|
+
sourceRef: narrowed.source_ref,
|
|
37947
|
+
content: input.action.content,
|
|
37948
|
+
raw: input.action.raw
|
|
37949
|
+
})
|
|
37673
37950
|
};
|
|
37674
37951
|
}
|
|
37675
37952
|
}
|
|
@@ -37682,7 +37959,14 @@ async function resolveDraftActionSourceRef(input) {
|
|
|
37682
37959
|
throw new Error(`source_refs for node "${input.node}" do not resolve to one contiguous source_ref`);
|
|
37683
37960
|
return {
|
|
37684
37961
|
source_ref: resolved,
|
|
37685
|
-
source_refs: input.action.source_refs
|
|
37962
|
+
source_refs: input.action.source_refs,
|
|
37963
|
+
...input.action.content !== undefined ? await rawDebugPatch({
|
|
37964
|
+
ctxDir: input.ctxDir,
|
|
37965
|
+
nodeSources,
|
|
37966
|
+
sourceRef: resolved,
|
|
37967
|
+
content: input.action.content,
|
|
37968
|
+
raw: input.action.raw
|
|
37969
|
+
}) : {}
|
|
37686
37970
|
};
|
|
37687
37971
|
}
|
|
37688
37972
|
if (input.action.source_ref !== undefined) {
|
|
@@ -37694,13 +37978,21 @@ async function resolveDraftActionSourceRef(input) {
|
|
|
37694
37978
|
...input.context !== undefined ? { context: input.context } : {}
|
|
37695
37979
|
});
|
|
37696
37980
|
}
|
|
37981
|
+
const resolved = await canonicalizeExplicitSourceRef({
|
|
37982
|
+
ctxDir: input.ctxDir,
|
|
37983
|
+
node: input.node,
|
|
37984
|
+
nodeSources,
|
|
37985
|
+
sourceRef: input.action.source_ref
|
|
37986
|
+
});
|
|
37697
37987
|
return {
|
|
37698
|
-
source_ref:
|
|
37988
|
+
source_ref: resolved,
|
|
37989
|
+
...input.action.content !== undefined ? await rawDebugPatch({
|
|
37699
37990
|
ctxDir: input.ctxDir,
|
|
37700
|
-
node: input.node,
|
|
37701
37991
|
nodeSources,
|
|
37702
|
-
sourceRef:
|
|
37703
|
-
|
|
37992
|
+
sourceRef: resolved,
|
|
37993
|
+
content: input.action.content,
|
|
37994
|
+
raw: input.action.raw
|
|
37995
|
+
}) : {}
|
|
37704
37996
|
};
|
|
37705
37997
|
}
|
|
37706
37998
|
return;
|
|
@@ -37741,7 +38033,7 @@ async function canonicalizeDraftSourceRefs(input) {
|
|
|
37741
38033
|
path: `actions[${actionIndex}].source_refs`,
|
|
37742
38034
|
onAutoNarrow: input.onAutoNarrow
|
|
37743
38035
|
});
|
|
37744
|
-
actions.push(sourceRef !== undefined ? { ...action, source_ref: sourceRef.source_ref, ...sourceRef.source_refs !== undefined ? { source_refs: sourceRef.source_refs } : {} } : action);
|
|
38036
|
+
actions.push(sourceRef !== undefined ? { ...action, source_ref: sourceRef.source_ref, ...sourceRef.source_refs !== undefined ? { source_refs: sourceRef.source_refs } : {}, ...sourceRef.raw !== undefined ? { raw: sourceRef.raw } : {} } : action);
|
|
37745
38037
|
continue;
|
|
37746
38038
|
}
|
|
37747
38039
|
if (action.op === "update") {
|
|
@@ -37757,7 +38049,7 @@ async function canonicalizeDraftSourceRefs(input) {
|
|
|
37757
38049
|
path: `actions[${actionIndex}].source_refs`,
|
|
37758
38050
|
onAutoNarrow: input.onAutoNarrow
|
|
37759
38051
|
});
|
|
37760
|
-
actions.push(sourceRef !== undefined ? { ...action, source_ref: sourceRef.source_ref, ...sourceRef.source_refs !== undefined ? { source_refs: sourceRef.source_refs } : {} } : action);
|
|
38052
|
+
actions.push(sourceRef !== undefined ? { ...action, source_ref: sourceRef.source_ref, ...sourceRef.source_refs !== undefined ? { source_refs: sourceRef.source_refs } : {}, ...sourceRef.raw !== undefined ? { raw: sourceRef.raw } : {} } : action);
|
|
37761
38053
|
continue;
|
|
37762
38054
|
}
|
|
37763
38055
|
if (action.op === "supersede") {
|
|
@@ -37775,7 +38067,7 @@ async function canonicalizeDraftSourceRefs(input) {
|
|
|
37775
38067
|
});
|
|
37776
38068
|
actions.push({
|
|
37777
38069
|
...action,
|
|
37778
|
-
new: sourceRef !== undefined ? { ...action.new, source_ref: sourceRef.source_ref, ...sourceRef.source_refs !== undefined ? { source_refs: sourceRef.source_refs } : {} } : action.new
|
|
38070
|
+
new: sourceRef !== undefined ? { ...action.new, source_ref: sourceRef.source_ref, ...sourceRef.source_refs !== undefined ? { source_refs: sourceRef.source_refs } : {}, ...sourceRef.raw !== undefined ? { raw: sourceRef.raw } : {} } : action.new
|
|
37779
38071
|
});
|
|
37780
38072
|
continue;
|
|
37781
38073
|
}
|
|
@@ -37803,6 +38095,7 @@ async function canonicalizeDraftSourceRefs(input) {
|
|
|
37803
38095
|
var init_prepareCompileSourceRefs = __esm(() => {
|
|
37804
38096
|
init_sourceRef();
|
|
37805
38097
|
init_ref();
|
|
38098
|
+
init_normalize();
|
|
37806
38099
|
init_sourceRefEligibility();
|
|
37807
38100
|
init_sourceSupport();
|
|
37808
38101
|
});
|
|
@@ -37905,7 +38198,9 @@ function compileDraftActionProposed(action) {
|
|
|
37905
38198
|
return {
|
|
37906
38199
|
op: "add",
|
|
37907
38200
|
kind: action.kind,
|
|
38201
|
+
...action.summary !== undefined ? { summary: action.summary } : {},
|
|
37908
38202
|
content: action.content,
|
|
38203
|
+
...action.raw !== undefined ? { raw: action.raw } : {},
|
|
37909
38204
|
...action.detail !== undefined ? { detail: action.detail } : {},
|
|
37910
38205
|
...action.confidence !== undefined ? { confidence: action.confidence } : {},
|
|
37911
38206
|
...action.refers_to_nodes !== undefined ? { refers_to_nodes: action.refers_to_nodes } : {},
|
|
@@ -37936,7 +38231,9 @@ function proposedPatchFromAddLike(action) {
|
|
|
37936
38231
|
return;
|
|
37937
38232
|
return {
|
|
37938
38233
|
kind: action.kind,
|
|
38234
|
+
...action.summary !== undefined ? { summary: action.summary } : {},
|
|
37939
38235
|
content: action.content,
|
|
38236
|
+
...action.raw !== undefined ? { raw: action.raw } : {},
|
|
37940
38237
|
...action.detail !== undefined ? { detail: action.detail } : {},
|
|
37941
38238
|
...action.confidence !== undefined ? { confidence: action.confidence } : {},
|
|
37942
38239
|
source_ref: sourceRef,
|
|
@@ -37948,7 +38245,9 @@ function proposedPatchFromUpdate(action) {
|
|
|
37948
38245
|
if (action.content === undefined || sourceRef === undefined)
|
|
37949
38246
|
return;
|
|
37950
38247
|
return {
|
|
38248
|
+
...action.summary !== undefined ? { summary: action.summary } : {},
|
|
37951
38249
|
content: action.content,
|
|
38250
|
+
...action.raw !== undefined ? { raw: action.raw } : {},
|
|
37952
38251
|
...action.detail !== undefined ? { detail: action.detail } : {},
|
|
37953
38252
|
...action.confidence !== undefined ? { confidence: action.confidence } : {},
|
|
37954
38253
|
source_ref: sourceRef,
|
|
@@ -38405,6 +38704,7 @@ async function compileSourceSupport(input) {
|
|
|
38405
38704
|
action: `compile ${input.action.op}`,
|
|
38406
38705
|
section: {
|
|
38407
38706
|
kind: candidate.section.kind,
|
|
38707
|
+
...candidate.section.summary !== undefined ? { summary: candidate.section.summary } : {},
|
|
38408
38708
|
content: candidate.section.content,
|
|
38409
38709
|
...candidate.section.detail !== undefined ? { detail: candidate.section.detail } : {},
|
|
38410
38710
|
source_ref: candidate.section.source_ref
|
|
@@ -38471,27 +38771,13 @@ function assertString(value, path8, node2) {
|
|
|
38471
38771
|
function assertContent(value, path8, node2, optional = false) {
|
|
38472
38772
|
if (value === undefined && optional)
|
|
38473
38773
|
return;
|
|
38474
|
-
|
|
38475
|
-
if (content.length > MAX_DRAFT_CONTENT_CHARS2) {
|
|
38476
|
-
throw compileDraftPrepareError(node2, path8, `compile draft ${path8} must be ${MAX_DRAFT_CONTENT_CHARS2} characters or fewer; move long-form prose into detail`, "content-too-long");
|
|
38477
|
-
}
|
|
38478
|
-
if (/\r|\n/u.test(content)) {
|
|
38479
|
-
throw compileDraftPrepareError(node2, path8, `compile draft ${path8} must be a single-line claim; move multi-line prose or code into detail`, "content-must-be-single-line");
|
|
38480
|
-
}
|
|
38481
|
-
if (/```|~~~/u.test(content)) {
|
|
38482
|
-
throw compileDraftPrepareError(node2, path8, `compile draft ${path8} must not contain fenced code; put code blocks in detail`, "content-fenced-code");
|
|
38483
|
-
}
|
|
38774
|
+
assertString(value, path8, node2);
|
|
38484
38775
|
}
|
|
38485
38776
|
function assertOptionalString(value, path8, node2) {
|
|
38486
38777
|
if (value !== undefined && typeof value !== "string") {
|
|
38487
38778
|
throw compileDraftPrepareError(node2, path8, `compile draft ${path8} must be a string when present`, "invalid-string");
|
|
38488
38779
|
}
|
|
38489
38780
|
}
|
|
38490
|
-
function assertOptionalDetail(value, path8, node2) {
|
|
38491
|
-
if (value !== undefined && value !== null && typeof value !== "string") {
|
|
38492
|
-
throw compileDraftPrepareError(node2, path8, `compile draft ${path8} must be a string or null when present`, "invalid-detail");
|
|
38493
|
-
}
|
|
38494
|
-
}
|
|
38495
38781
|
function assertOptionalRefs(value, path8, node2, allowNull = false) {
|
|
38496
38782
|
if (value === undefined || allowNull && value === null)
|
|
38497
38783
|
return;
|
|
@@ -38500,6 +38786,9 @@ function assertOptionalRefs(value, path8, node2, allowNull = false) {
|
|
|
38500
38786
|
}
|
|
38501
38787
|
}
|
|
38502
38788
|
function rejectUnsupportedEvidenceFields2(value, path8, node2) {
|
|
38789
|
+
if (value.body !== undefined || value.detail !== undefined || value.raw !== undefined) {
|
|
38790
|
+
throw compileDraftPrepareError(node2, path8, `compile draft ${path8} must use content plus optional summary; body/detail/raw are not accepted`, "retired-draft-field");
|
|
38791
|
+
}
|
|
38503
38792
|
if (value.source_ref !== undefined) {
|
|
38504
38793
|
throw compileDraftPrepareError(node2, `${path8}.source_ref`, `compile draft ${path8}.source_ref is retired; use source_refs: ["src-N#..."]`, "singular-source-ref-rejected");
|
|
38505
38794
|
}
|
|
@@ -38511,7 +38800,7 @@ function validateAddLikeAction2(value, path8, node2) {
|
|
|
38511
38800
|
rejectUnsupportedEvidenceFields2(value, path8, node2);
|
|
38512
38801
|
assertString(value.kind, `${path8}.kind`, node2);
|
|
38513
38802
|
assertContent(value.content, `${path8}.content`, node2);
|
|
38514
|
-
|
|
38803
|
+
assertOptionalString(value.summary, `${path8}.summary`, node2);
|
|
38515
38804
|
assertOptionalString(value.confidence, `${path8}.confidence`, node2);
|
|
38516
38805
|
assertOptionalRefs(value.source_refs, `${path8}.source_refs`, node2);
|
|
38517
38806
|
assertOptionalRefs(value.refers_to_nodes, `${path8}.refers_to_nodes`, node2);
|
|
@@ -38546,7 +38835,8 @@ function validateCompileDraft(value, node2) {
|
|
|
38546
38835
|
if (op === "update") {
|
|
38547
38836
|
assertString(rawAction.target_section_id, `${path8}.target_section_id`, node2);
|
|
38548
38837
|
assertContent(rawAction.content, `${path8}.content`, node2, true);
|
|
38549
|
-
|
|
38838
|
+
if (rawAction.summary !== null)
|
|
38839
|
+
assertOptionalString(rawAction.summary, `${path8}.summary`, node2);
|
|
38550
38840
|
assertOptionalString(rawAction.confidence, `${path8}.confidence`, node2);
|
|
38551
38841
|
assertOptionalRefs(rawAction.source_refs, `${path8}.source_refs`, node2);
|
|
38552
38842
|
assertOptionalRefs(rawAction.refers_to_nodes, `${path8}.refers_to_nodes`, node2, true);
|
|
@@ -38721,8 +39011,8 @@ function compileSourceRefAutoNarrowHints(events) {
|
|
|
38721
39011
|
return events.map((event) => ({
|
|
38722
39012
|
code: "compile-source-refs-auto-narrowed",
|
|
38723
39013
|
severity: "warning",
|
|
38724
|
-
message: `Draft ${event.path} cited ${event.original_source_refs.length} source_refs, but the Section
|
|
38725
|
-
next_action: "Keep the narrowed citation if the removed refs are unrelated, duplicate, or intentionally uncovered. If those refs contain distinct knowledge, add separate actions or expand this
|
|
39014
|
+
message: `Draft ${event.path} cited ${event.original_source_refs.length} source_refs, but the Section content is fully supported by ` + `${event.narrowed_source_refs.length}; the CLI narrowed the citation boundary.`,
|
|
39015
|
+
next_action: "Keep the narrowed citation if the removed refs are unrelated, duplicate, or intentionally uncovered. If those refs contain distinct knowledge, add separate actions or expand this content so the cited refs are actually consumed.",
|
|
38726
39016
|
op: event.op,
|
|
38727
39017
|
op_index: event.action_index,
|
|
38728
39018
|
path: event.path,
|
|
@@ -38748,7 +39038,9 @@ function draftSkipCandidate(node2, action) {
|
|
|
38748
39038
|
op: "add",
|
|
38749
39039
|
section: {
|
|
38750
39040
|
kind: action.kind,
|
|
39041
|
+
...action.summary !== undefined ? { summary: action.summary } : {},
|
|
38751
39042
|
content: action.content,
|
|
39043
|
+
...action.raw !== undefined ? { raw: action.raw } : {},
|
|
38752
39044
|
...action.detail !== undefined ? { detail: action.detail } : {},
|
|
38753
39045
|
...action.confidence !== undefined ? { confidence: action.confidence } : {},
|
|
38754
39046
|
...action.refers_to_nodes !== undefined ? { refers_to_nodes: action.refers_to_nodes } : {},
|
|
@@ -38764,7 +39056,9 @@ function draftSkipCandidate(node2, action) {
|
|
|
38764
39056
|
target_section_id: action.target_section_id,
|
|
38765
39057
|
section: {
|
|
38766
39058
|
kind: action.new.kind,
|
|
39059
|
+
...action.new.summary !== undefined ? { summary: action.new.summary } : {},
|
|
38767
39060
|
content: action.new.content,
|
|
39061
|
+
...action.new.raw !== undefined ? { raw: action.new.raw } : {},
|
|
38768
39062
|
...action.new.detail !== undefined ? { detail: action.new.detail } : {},
|
|
38769
39063
|
...action.new.confidence !== undefined ? { confidence: action.new.confidence } : {},
|
|
38770
39064
|
...action.new.refers_to_nodes !== undefined ? { refers_to_nodes: action.new.refers_to_nodes } : {},
|
|
@@ -38781,7 +39075,9 @@ function draftSkipCandidate(node2, action) {
|
|
|
38781
39075
|
target_section_id: action.target_section_id,
|
|
38782
39076
|
section: {
|
|
38783
39077
|
kind: current.kind,
|
|
39078
|
+
...action.summary !== undefined ? action.summary === null ? {} : { summary: action.summary } : current.summary !== undefined ? { summary: current.summary } : {},
|
|
38784
39079
|
content: action.content ?? current.content,
|
|
39080
|
+
...action.raw !== undefined ? action.raw === null ? {} : { raw: action.raw } : current.raw !== undefined ? { raw: current.raw } : {},
|
|
38785
39081
|
...action.detail !== undefined ? { detail: action.detail } : current.detail !== undefined ? { detail: current.detail } : {},
|
|
38786
39082
|
...action.confidence !== undefined ? { confidence: action.confidence } : { confidence: current.confidence },
|
|
38787
39083
|
...action.refers_to_nodes !== undefined ? action.refers_to_nodes === null ? {} : { refers_to_nodes: action.refers_to_nodes } : current.refers_to_nodes !== undefined ? { refers_to_nodes: current.refers_to_nodes } : {},
|
|
@@ -38972,7 +39268,7 @@ async function prepareCompileReconcileContext(input) {
|
|
|
38972
39268
|
agent_hints: [...context.agent_hints ?? [], ...judgeHint !== null ? [judgeHint] : []]
|
|
38973
39269
|
};
|
|
38974
39270
|
}
|
|
38975
|
-
var import_yaml28
|
|
39271
|
+
var import_yaml28;
|
|
38976
39272
|
var init_prepareCompile = __esm(() => {
|
|
38977
39273
|
init_compile();
|
|
38978
39274
|
init_compileDraftValidation();
|
|
@@ -39587,7 +39883,7 @@ This directory is the C4A data root for a knowledge workspace.
|
|
|
39587
39883
|
## Agent Rules
|
|
39588
39884
|
|
|
39589
39885
|
- Treat this data root as CLI-owned by default. Agents and users should not directly edit managed files unless a command or skill explicitly asks for a structured input file.
|
|
39590
|
-
- Generated knowledge titles, summaries, and user-facing workflow reports follow this workspace language unless a CLI payload returns a more specific \`generation_policy\`. Keep \`node.summary\` concise: target under 15 tokens and never over 30 tokens. Source-bound Section content
|
|
39886
|
+
- Generated knowledge titles, summaries, and user-facing workflow reports follow this workspace language unless a CLI payload returns a more specific \`generation_policy\`. Keep \`node.summary\` concise: target under 15 tokens and never over 30 tokens. Source-bound Section content should stay close to the cited source language when it differs from the workspace language; add \`section.summary\` for long content as one plain paragraph. Preserve product names, code identifiers, command flags, slugs, \`block_id\` / \`source_ref\` tokens, and exact quoted evidence as printed when it is active user-facing knowledge.
|
|
39591
39887
|
- Keep Agent prompts and handoff payloads stable: fixed protocol/schema rules first, existing knowledge lookup second, source-shared context third, and the current task-specific candidate/Node/question last. Do not add current timestamps, random ids, scratch paths, host absolute paths, or reordered JSON fields to Agent-authored payloads or reports unless a \`context\` command explicitly returned them as semantic workspace facts.
|
|
39592
39888
|
- Existing \`knowledge/\` Nodes are the lookup registry. Use \`context mdrive glossary list|match\`, \`context mdrive node list\`, \`context mdrive query\`, or \`context query\` to reuse term, service, system, action, and domain handles. Do not create a separate dynamic registry file, and do not read \`knowledge/**\` directly just to decide whether a name already exists. When \`context mdrive glossary match <name>\` returns \`match.kind\`, \`match.matched\`, and \`match.rank\`, treat those as stable lookup hints; exact title/slug/alias hits should usually reuse the existing Node.
|
|
39593
39889
|
- Naming surfaces are separate: \`/context:*\` names user slash commands, \`context ...\` names CLI primitives, and \`context:skill-*\` names packaged skills/procedures invoked by slash workflows. Do not invent \`/context:compile-draft\`, \`/context:skill-*\`, or call a packaged skill a user command.
|
|
@@ -39608,7 +39904,7 @@ This directory is the C4A data root for a knowledge workspace.
|
|
|
39608
39904
|
- Use \`/context:align\` for structural planning. Read the current align workflow schemas, inspect \`align-segments\` through compact \`context workflow show --view ... --unwrap\` views, build candidate ledger outputs, and finalize with \`context align --finalize -\`. Align workflow payload submissions must go through stdin; do not write scratch YAML/JSON files for coarse-read, candidate ops, or structure decision. Finalize consumes only the structure-decision payload and finalized block ownership; it does not read raw directly or accept old patch inputs.
|
|
39609
39905
|
- Use \`/context:compile\` for synthesis into \`knowledge/\`. Prepare NodeContext with \`context compile --context <slug> --format json\`, then inspect citation handles with \`context compile --source-refs <slug> --format json\` or \`context workflow show --payload node-context --view source-refs --unwrap --format json\` before reading the full payload. Read full NodeContext with \`context workflow show --payload node-context --unwrap --format json\` only when passing its \`.value\` into the draft procedure; the payload returns \`full-context\` when the incremental baseline is unsafe. Pass drafts to \`context compile --draft <slug> --input - --plan --prepare\`; the CLI stores workflow payloads for review/apply. Use \`--save-input\` only when an explicit draft debug copy is needed. For precise manual knowledge edits, use \`context mdrive ...\`; do not bypass the CLI for article markdown, indexes, or changelog entries.
|
|
39610
39906
|
- \`/context:compile\` may process a workset, but each Node must complete its own context → draft → prepare → review → apply loop before the agent applies another Node. Do not run multiple Node reconcile/apply chains in parallel, hide several Node failures inside one batch command, or move to the next Node while the current Node has unresolved review questions, schema errors, unsupported evidence, or coverage warnings.
|
|
39611
|
-
- Treat compile \`source_support\` as a lexical diagnostic, not a target to game. Do not copy raw text
|
|
39907
|
+
- Treat compile \`source_support\` as a lexical diagnostic, not a target to game. Do not copy raw text merely to raise matched-term counts or show evidence; \`source_ref\` already provides traceability. Keep Section \`content\` as the user-facing wording, preserving cited raw prose when it is already clear and only cleaning formatting, typos, casing, entity names, aliases, or grammar without changing meaning.
|
|
39612
39908
|
- When \`context compile --draft <slug> --plan\` or \`context reconcile prepare --mode compile\` returns \`compact-source-low-coverage\` or \`dense-source-low-coverage\`, treat it as a required coverage progress warning. Check \`coverage is <covered>/<total>\` and \`remaining <N> snippet(s)\`, then return to the same draft and add actions for uncovered, source-backed, orthogonal facts before review/apply. If \`context verify\` or \`context doctor\` reports \`compact-source-evidence-undercovered\` or \`dense-source-evidence-undercovered\`, review the reported uncovered raw blocks before declaring the source complete. CLI success for one action only proves that action is supported; it does not prove the Node is complete.
|
|
39613
39909
|
- Users may intentionally edit \`config.yaml\` and \`aspects/*/prompt.md\`; after doing so, run \`context doctor\` or \`context status\`.
|
|
39614
39910
|
- Use \`context doctor\`, \`context verify\`, and \`context status\` to inspect workspace health instead of inferring state from partial files.
|
|
@@ -49530,7 +49826,7 @@ init_errors();
|
|
|
49530
49826
|
init_knowledge();
|
|
49531
49827
|
init_exitCode();
|
|
49532
49828
|
var QUERY_FORMATS = ["json", "md", "table"];
|
|
49533
|
-
var QUERY_INTENTS = ["orientation", "
|
|
49829
|
+
var QUERY_INTENTS = ["orientation", "node_lookup", "node_view", "section_search", "impact_analysis", "recall"];
|
|
49534
49830
|
var QUERY_PROFILES = ["answer", "recall", "reconcile-dedupe", "reconcile-support", "reconcile-refresh"];
|
|
49535
49831
|
var QUERY_OPTION_FLAG_LABELS = {
|
|
49536
49832
|
format: "--format",
|
|
@@ -49571,7 +49867,7 @@ function normalizeContainsTree(value) {
|
|
|
49571
49867
|
function hasStructuredFilter(options) {
|
|
49572
49868
|
return options.node !== undefined || options.kind !== undefined || options.refersTo !== undefined || options.tag !== undefined || options.domain !== undefined || options.containsTree !== undefined || options.entityView !== undefined || options.scope !== undefined;
|
|
49573
49869
|
}
|
|
49574
|
-
function
|
|
49870
|
+
function hasNodeViewFilter(options) {
|
|
49575
49871
|
return options.node !== undefined || options.kind !== undefined || options.refersTo !== undefined || options.tag !== undefined || options.domain !== undefined || options.containsTree !== undefined || options.entityView !== undefined;
|
|
49576
49872
|
}
|
|
49577
49873
|
function hasExclusiveScopeTarget(options) {
|
|
@@ -49583,58 +49879,105 @@ function hasImpactAnchor(options) {
|
|
|
49583
49879
|
function findImpactAnchor(options) {
|
|
49584
49880
|
return options.scope ?? options.node ?? options.domain ?? options.entityView;
|
|
49585
49881
|
}
|
|
49586
|
-
function
|
|
49882
|
+
function structuredQueryNeedsRetrieval(options) {
|
|
49587
49883
|
return options.scope !== undefined || options.node !== undefined || options.domain !== undefined || options.containsTree !== undefined || options.entityView !== undefined || options.refersTo !== undefined || !hasStructuredFilter(options) && options.query !== undefined;
|
|
49588
49884
|
}
|
|
49589
49885
|
function presentFlags(options, flags2) {
|
|
49590
49886
|
return flags2.filter((flag) => options[flag] !== undefined).map((flag) => QUERY_OPTION_FLAG_LABELS[flag]).filter((label) => label !== undefined);
|
|
49591
49887
|
}
|
|
49592
|
-
function
|
|
49593
|
-
|
|
49594
|
-
|
|
49595
|
-
|
|
49596
|
-
|
|
49597
|
-
|
|
49598
|
-
|
|
49599
|
-
|
|
49600
|
-
|
|
49601
|
-
|
|
49602
|
-
|
|
49603
|
-
|
|
49604
|
-
|
|
49605
|
-
}
|
|
49606
|
-
return;
|
|
49888
|
+
function assertOrientationOptions(options, hasExplicitProfile) {
|
|
49889
|
+
if (options.intent !== "orientation")
|
|
49890
|
+
return false;
|
|
49891
|
+
const unexpectedFlags = presentFlags(options, ["query", "node", "containsTree", "entityView", "kind", "refersTo", "scope"]);
|
|
49892
|
+
if (unexpectedFlags.length > 0 || hasExplicitProfile) {
|
|
49893
|
+
throw new ContextError(ExitCode.UserError, "context query --intent orientation accepts only --tag, --domain, and --format; it does not accept query text, node filters, section filters, or --profile", {
|
|
49894
|
+
category: ErrorCategory.UserInputInvalid,
|
|
49895
|
+
flag: "--intent",
|
|
49896
|
+
unexpected_flags: [
|
|
49897
|
+
...unexpectedFlags,
|
|
49898
|
+
...hasExplicitProfile ? ["--profile"] : []
|
|
49899
|
+
]
|
|
49900
|
+
});
|
|
49607
49901
|
}
|
|
49608
|
-
|
|
49609
|
-
|
|
49610
|
-
|
|
49902
|
+
return true;
|
|
49903
|
+
}
|
|
49904
|
+
function assertNodeLookupOptions(options) {
|
|
49905
|
+
if (options.query === undefined) {
|
|
49906
|
+
throw new ContextError(ExitCode.UserError, "context query --intent node_lookup requires --query or a positional query", {
|
|
49907
|
+
category: ErrorCategory.UserInputInvalid,
|
|
49908
|
+
flag: "--query"
|
|
49909
|
+
});
|
|
49910
|
+
}
|
|
49911
|
+
if (hasStructuredFilter(options)) {
|
|
49912
|
+
const unexpectedFlags = presentFlags(options, ["node", "domain", "containsTree", "entityView", "tag", "kind", "refersTo", "scope"]);
|
|
49913
|
+
throw new ContextError(ExitCode.UserError, "node_lookup only resolves Node candidates from query text; use node_view for --scope, --node, --domain, --contains-tree, --entity-view, --tag, --kind, or --refers-to", {
|
|
49914
|
+
category: ErrorCategory.UserInputInvalid,
|
|
49915
|
+
flag: "--intent",
|
|
49916
|
+
unexpected_flags: unexpectedFlags
|
|
49611
49917
|
});
|
|
49612
49918
|
}
|
|
49613
|
-
|
|
49614
|
-
|
|
49919
|
+
}
|
|
49920
|
+
function assertNodeViewOptions(options) {
|
|
49921
|
+
const hasViewInput = options.scope !== undefined || hasNodeViewFilter(options);
|
|
49922
|
+
if (!hasViewInput) {
|
|
49923
|
+
throw new ContextError(ExitCode.UserError, "context query --intent node_view requires --scope, --node, --domain, --contains-tree, --entity-view, --tag, --kind, or --refers-to", {
|
|
49615
49924
|
category: ErrorCategory.UserInputInvalid
|
|
49616
49925
|
});
|
|
49617
49926
|
}
|
|
49618
|
-
if (
|
|
49619
|
-
|
|
49620
|
-
const hint = `to use ${unexpectedFlags.join(", ")}, switch to --intent node_search; use --scope to narrow ${options.intent}`;
|
|
49621
|
-
throw new ContextError(ExitCode.UserError, `${options.intent} uses --scope for narrowing; --node, --domain, --contains-tree, --entity-view, --tag, --kind, and --refers-to are node_search filters; hint: ${hint}`, {
|
|
49927
|
+
if (options.query !== undefined) {
|
|
49928
|
+
throw new ContextError(ExitCode.UserError, "node_view opens an already-known structure target; use node_lookup to resolve query text or section_search to search Section content", {
|
|
49622
49929
|
category: ErrorCategory.UserInputInvalid,
|
|
49623
|
-
flag: "--
|
|
49624
|
-
expected_flag: "--scope",
|
|
49625
|
-
unexpected_flags: unexpectedFlags,
|
|
49626
|
-
hint
|
|
49930
|
+
flag: "--query"
|
|
49627
49931
|
});
|
|
49628
49932
|
}
|
|
49629
|
-
|
|
49630
|
-
|
|
49631
|
-
|
|
49933
|
+
}
|
|
49934
|
+
function assertSectionOrRecallFilters(options) {
|
|
49935
|
+
if (options.intent !== "section_search" && options.intent !== "recall" || !hasNodeViewFilter(options))
|
|
49936
|
+
return;
|
|
49937
|
+
const unexpectedFlags = presentFlags(options, ["node", "domain", "containsTree", "entityView", "tag", "kind", "refersTo"]);
|
|
49938
|
+
const hint = `to use ${unexpectedFlags.join(", ")}, switch to --intent node_view; use --scope to narrow ${options.intent}`;
|
|
49939
|
+
throw new ContextError(ExitCode.UserError, `${options.intent} uses --scope for narrowing; --node, --domain, --contains-tree, --entity-view, --tag, --kind, and --refers-to are node_view filters; hint: ${hint}`, {
|
|
49940
|
+
category: ErrorCategory.UserInputInvalid,
|
|
49941
|
+
flag: "--scope",
|
|
49942
|
+
expected_flag: "--scope",
|
|
49943
|
+
unexpected_flags: unexpectedFlags,
|
|
49944
|
+
hint
|
|
49945
|
+
});
|
|
49946
|
+
}
|
|
49947
|
+
function assertImpactFilters(options) {
|
|
49948
|
+
if (options.intent !== "impact_analysis" || options.tag === undefined && options.kind === undefined && options.refersTo === undefined && options.containsTree === undefined)
|
|
49949
|
+
return;
|
|
49950
|
+
const unexpectedFlags = presentFlags(options, ["tag", "kind", "refersTo", "containsTree"]);
|
|
49951
|
+
throw new ContextError(ExitCode.UserError, "impact_analysis uses --scope, --node, --domain, or --entity-view as an impact anchor; --tag, --kind, --refers-to, and --contains-tree are node_view filters", {
|
|
49952
|
+
category: ErrorCategory.UserInputInvalid,
|
|
49953
|
+
flag: "--scope",
|
|
49954
|
+
expected_flag: "--scope",
|
|
49955
|
+
unexpected_flags: unexpectedFlags
|
|
49956
|
+
});
|
|
49957
|
+
}
|
|
49958
|
+
function assertParsedQueryOptions(options, hasExplicitProfile) {
|
|
49959
|
+
const hasSearchInput = options.query !== undefined || options.scope !== undefined || hasNodeViewFilter(options);
|
|
49960
|
+
if (assertOrientationOptions(options, hasExplicitProfile))
|
|
49961
|
+
return;
|
|
49962
|
+
if (options.intent === undefined && !hasSearchInput) {
|
|
49963
|
+
throw new ContextError(ExitCode.UserError, "context query requires --intent, --query, --scope, or a node_view filter", {
|
|
49964
|
+
category: ErrorCategory.UserInputInvalid
|
|
49965
|
+
});
|
|
49966
|
+
}
|
|
49967
|
+
if (options.intent === "node_lookup") {
|
|
49968
|
+
assertNodeLookupOptions(options);
|
|
49969
|
+
}
|
|
49970
|
+
if (options.intent === "node_view") {
|
|
49971
|
+
assertNodeViewOptions(options);
|
|
49972
|
+
}
|
|
49973
|
+
assertSectionOrRecallFilters(options);
|
|
49974
|
+
if (options.intent === "section_search" && options.query === undefined) {
|
|
49975
|
+
throw new ContextError(ExitCode.UserError, "context query --intent section_search requires --query or a positional query", {
|
|
49632
49976
|
category: ErrorCategory.UserInputInvalid,
|
|
49633
|
-
flag: "--
|
|
49634
|
-
expected_flag: "--scope",
|
|
49635
|
-
unexpected_flags: unexpectedFlags
|
|
49977
|
+
flag: "--query"
|
|
49636
49978
|
});
|
|
49637
49979
|
}
|
|
49980
|
+
assertImpactFilters(options);
|
|
49638
49981
|
if (hasExplicitProfile && options.intent !== "recall") {
|
|
49639
49982
|
throw new ContextError(ExitCode.UserError, "--profile is only supported with --intent recall", {
|
|
49640
49983
|
category: ErrorCategory.UserInputInvalid,
|
|
@@ -49647,12 +49990,6 @@ function assertParsedQueryOptions(options, hasExplicitProfile) {
|
|
|
49647
49990
|
flag: "--query"
|
|
49648
49991
|
});
|
|
49649
49992
|
}
|
|
49650
|
-
if (options.intent === "description_search" && options.query === undefined) {
|
|
49651
|
-
throw new ContextError(ExitCode.UserError, "context query --intent description_search requires --query or a positional query", {
|
|
49652
|
-
category: ErrorCategory.UserInputInvalid,
|
|
49653
|
-
flag: "--query"
|
|
49654
|
-
});
|
|
49655
|
-
}
|
|
49656
49993
|
if (options.scope !== undefined && hasExclusiveScopeTarget(options)) {
|
|
49657
49994
|
throw new ContextError(ExitCode.UserError, "--scope is mutually exclusive with --node, --domain, --contains-tree, and --entity-view", { category: ErrorCategory.UserInputInvalid, flag: "--scope" });
|
|
49658
49995
|
}
|
|
@@ -49670,7 +50007,8 @@ function parseQueryOptions(queryArg, options) {
|
|
|
49670
50007
|
const domain = optionalString(options.domain);
|
|
49671
50008
|
const entityView = optionalString(options.entityView);
|
|
49672
50009
|
const scope = optionalString(options.scope);
|
|
49673
|
-
const
|
|
50010
|
+
const hasStructuredInput = node2 !== undefined || options.kind !== undefined || refersTo !== undefined || tag !== undefined || domain !== undefined || containsTree !== undefined || entityView !== undefined || scope !== undefined;
|
|
50011
|
+
const hasAnySearchInput = query !== undefined || hasStructuredInput;
|
|
49674
50012
|
const effectiveIntent = intent ?? (hasAnySearchInput ? undefined : "orientation");
|
|
49675
50013
|
const parsed = {
|
|
49676
50014
|
format,
|
|
@@ -49805,6 +50143,7 @@ function sectionEntries(result) {
|
|
|
49805
50143
|
node: section.node_slug,
|
|
49806
50144
|
section: section.section_id,
|
|
49807
50145
|
kind: section.kind,
|
|
50146
|
+
...section.summary !== undefined ? { summary: section.summary } : {},
|
|
49808
50147
|
content: section.content,
|
|
49809
50148
|
...section.refers_to_nodes.length > 0 ? { refers_to_nodes: section.refers_to_nodes } : {}
|
|
49810
50149
|
}));
|
|
@@ -49834,6 +50173,17 @@ function edgeEntries(result) {
|
|
|
49834
50173
|
function structuredData(result, options) {
|
|
49835
50174
|
const sections = sectionEntries(result);
|
|
49836
50175
|
const entries = result.sections.length > 0 ? sections : result.nodes.length > 0 ? nodeEntries(result) : edgeEntries(result);
|
|
50176
|
+
const nodeVisibility = result.fullNode === undefined ? undefined : {
|
|
50177
|
+
scope: "node",
|
|
50178
|
+
node: result.fullNode.slug,
|
|
50179
|
+
shown_sections: sections.length,
|
|
50180
|
+
total_sections: result.fullNode.sections.length,
|
|
50181
|
+
filtered: options.kind !== undefined || options.refersTo !== undefined,
|
|
50182
|
+
truncated: false,
|
|
50183
|
+
has_more: false,
|
|
50184
|
+
complete: true,
|
|
50185
|
+
next_action: "Answer from these visible Sections; run section_search only to narrow or rank evidence inside this Node."
|
|
50186
|
+
};
|
|
49837
50187
|
const data = {
|
|
49838
50188
|
...options.query !== undefined ? { query: options.query } : {},
|
|
49839
50189
|
...options.scope !== undefined ? { scope: options.scope } : {},
|
|
@@ -49842,6 +50192,7 @@ function structuredData(result, options) {
|
|
|
49842
50192
|
sections,
|
|
49843
50193
|
edges: result.edges,
|
|
49844
50194
|
...result.fullNode !== undefined ? { fullNode: result.fullNode } : {},
|
|
50195
|
+
...nodeVisibility !== undefined ? { visibility: nodeVisibility } : {},
|
|
49845
50196
|
...result.stats !== undefined ? { stats: result.stats } : {}
|
|
49846
50197
|
};
|
|
49847
50198
|
if (entries.length === 0) {
|
|
@@ -49887,6 +50238,25 @@ ${rows.map((row) => renderRow(headers.map((header) => stringifyCell(row[header])
|
|
|
49887
50238
|
`)}
|
|
49888
50239
|
`;
|
|
49889
50240
|
}
|
|
50241
|
+
function renderVisibilityFooter(response) {
|
|
50242
|
+
const visibility = response.data.visibility;
|
|
50243
|
+
if (!visibility || typeof visibility !== "object" || Array.isArray(visibility))
|
|
50244
|
+
return "";
|
|
50245
|
+
const record = visibility;
|
|
50246
|
+
const scope = typeof record.scope === "string" ? record.scope : "scope";
|
|
50247
|
+
const slug = typeof record.node === "string" ? record.node : typeof record.slug === "string" ? record.slug : scope;
|
|
50248
|
+
const shown = typeof record.shown_sections === "number" ? record.shown_sections : undefined;
|
|
50249
|
+
const total = typeof record.total_sections === "number" ? record.total_sections : undefined;
|
|
50250
|
+
const filtered = record.filtered === true;
|
|
50251
|
+
const complete = record.complete === true && record.has_more !== true && record.truncated !== true;
|
|
50252
|
+
const visible = complete ? "complete" : "partial";
|
|
50253
|
+
const count = shown !== undefined && total !== undefined ? filtered ? ` — ${shown} matching sections shown for ${scope} ${slug} (${total} active sections total)` : ` — ${shown}/${total} sections shown for ${scope} ${slug}` : "";
|
|
50254
|
+
const next = typeof record.next_action === "string" ? `next: ${record.next_action}
|
|
50255
|
+
` : "";
|
|
50256
|
+
return `
|
|
50257
|
+
visible: ${visible}${count}; ${complete ? "no pagination." : "more evidence may be hidden."}
|
|
50258
|
+
${next}`;
|
|
50259
|
+
}
|
|
49890
50260
|
function rowsForResponse(response) {
|
|
49891
50261
|
if (response.state === "select")
|
|
49892
50262
|
return rowsFromValue(response.data.candidates ?? []);
|
|
@@ -49926,6 +50296,9 @@ function renderMarkdown(response) {
|
|
|
49926
50296
|
`;
|
|
49927
50297
|
}
|
|
49928
50298
|
lines.push("## Entries", "", renderTable(rowsForResponse(response)).trimEnd());
|
|
50299
|
+
const footer = renderVisibilityFooter(response).trimEnd();
|
|
50300
|
+
if (footer.length > 0)
|
|
50301
|
+
lines.push("", footer);
|
|
49929
50302
|
return `${lines.join(`
|
|
49930
50303
|
`)}
|
|
49931
50304
|
`;
|
|
@@ -49937,7 +50310,11 @@ function writeQueryResult(response, format) {
|
|
|
49937
50310
|
`);
|
|
49938
50311
|
return;
|
|
49939
50312
|
}
|
|
49940
|
-
|
|
50313
|
+
if (format === "md") {
|
|
50314
|
+
process.stdout.write(renderMarkdown(agentResponse));
|
|
50315
|
+
return;
|
|
50316
|
+
}
|
|
50317
|
+
process.stdout.write(renderTable(rowsForResponse(agentResponse)) + renderVisibilityFooter(agentResponse));
|
|
49941
50318
|
}
|
|
49942
50319
|
|
|
49943
50320
|
// src/commands/queryScope.ts
|
|
@@ -50022,7 +50399,7 @@ init_normalize();
|
|
|
50022
50399
|
var QUERY_TEMPLATE = 'context query --scope <slug> --query "<question>"';
|
|
50023
50400
|
var EXAMPLE_QUERY = "What does this node cover?";
|
|
50024
50401
|
var TEXT_TOKEN_BUDGET = 2000;
|
|
50025
|
-
var SUMMARY_TRUNCATION_NOTE = 'More: output was limited to about 2000 tokens. Deep map layers are folded first, then Summary entries are truncated. Drill down with scoped queries; there is no page-token pagination. Use: context query --intent
|
|
50402
|
+
var SUMMARY_TRUNCATION_NOTE = 'More: output was limited to about 2000 tokens. Deep map layers are folded first, then Summary entries are truncated. Drill down with scoped queries; there is no page-token pagination. Use: context query --intent node_view --scope <slug> or context query --intent section_search --scope <slug> --query "<question>".';
|
|
50026
50403
|
var GROUPS = [
|
|
50027
50404
|
{ label: "Domains", classes: ["domain"] },
|
|
50028
50405
|
{ label: "Entities", classes: ["concrete_entity", "entity"] },
|
|
@@ -50188,8 +50565,8 @@ function renderOrientationText(output) {
|
|
|
50188
50565
|
` ${output.query_template}`,
|
|
50189
50566
|
"",
|
|
50190
50567
|
"Drill down:",
|
|
50191
|
-
" context query --intent
|
|
50192
|
-
' context query --intent
|
|
50568
|
+
" context query --intent node_view --scope <slug>",
|
|
50569
|
+
' context query --intent section_search --scope <slug> --query "<question>"',
|
|
50193
50570
|
"",
|
|
50194
50571
|
"This structure is for choosing the next scope, not direct answer evidence."
|
|
50195
50572
|
];
|
|
@@ -50237,7 +50614,7 @@ function writeQueryOrientation(index, format, filters) {
|
|
|
50237
50614
|
|
|
50238
50615
|
// src/commands/query.ts
|
|
50239
50616
|
function searchPathForIntent(intent) {
|
|
50240
|
-
if (intent === "
|
|
50617
|
+
if (intent === "section_search")
|
|
50241
50618
|
return "section_search";
|
|
50242
50619
|
if (intent === "impact_analysis")
|
|
50243
50620
|
return "impact_graph";
|
|
@@ -50247,7 +50624,7 @@ function searchPathForIntent(intent) {
|
|
|
50247
50624
|
}
|
|
50248
50625
|
function chooseFallbackIntent(index, query) {
|
|
50249
50626
|
const exact = findExactNodeMatches(index, query);
|
|
50250
|
-
return exact.length > 0 ? "
|
|
50627
|
+
return exact.length > 0 ? "node_view" : "section_search";
|
|
50251
50628
|
}
|
|
50252
50629
|
function naturalLanguageFallback(index, options) {
|
|
50253
50630
|
if (options.intent !== undefined || options.query === undefined || hasStructuredFilter(options))
|
|
@@ -50256,7 +50633,7 @@ function naturalLanguageFallback(index, options) {
|
|
|
50256
50633
|
const anchors = mentionedQueryNodes(index, options.query);
|
|
50257
50634
|
const onlyAnchor = anchors[0];
|
|
50258
50635
|
if (shape === "definition" && anchors.length === 1 && onlyAnchor !== undefined) {
|
|
50259
|
-
return { intent: "
|
|
50636
|
+
return { intent: "node_view", options: { ...options, node: onlyAnchor.slug } };
|
|
50260
50637
|
}
|
|
50261
50638
|
return;
|
|
50262
50639
|
}
|
|
@@ -50283,11 +50660,12 @@ function quoteCliArg(value) {
|
|
|
50283
50660
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
50284
50661
|
}
|
|
50285
50662
|
function suggestedQuery(intent, options, scope) {
|
|
50286
|
-
const
|
|
50287
|
-
|
|
50663
|
+
const targetIntent = intent === "node_lookup" ? "node_view" : intent;
|
|
50664
|
+
const parts = [`context query --intent ${targetIntent}`, `--scope ${quoteCliArg(scope)}`];
|
|
50665
|
+
if (targetIntent === "recall") {
|
|
50288
50666
|
parts.push(`--profile ${options.profile}`);
|
|
50289
50667
|
}
|
|
50290
|
-
if ((
|
|
50668
|
+
if ((targetIntent === "section_search" || targetIntent === "recall") && options.query !== undefined) {
|
|
50291
50669
|
parts.push(`--query ${quoteCliArg(options.query)}`);
|
|
50292
50670
|
}
|
|
50293
50671
|
return parts.join(" ");
|
|
@@ -50330,6 +50708,7 @@ function candidateEntry(candidate) {
|
|
|
50330
50708
|
node: candidate.node_slug,
|
|
50331
50709
|
section: candidate.section_id,
|
|
50332
50710
|
kind: candidate.kind,
|
|
50711
|
+
...candidate.summary !== undefined ? { summary: candidate.summary } : {},
|
|
50333
50712
|
content: candidate.content,
|
|
50334
50713
|
...candidate.refers_to_nodes.length > 0 ? { refers_to_nodes: candidate.refers_to_nodes } : {}
|
|
50335
50714
|
};
|
|
@@ -50340,6 +50719,7 @@ function candidateEvidenceText(candidate) {
|
|
|
50340
50719
|
candidate.node_title,
|
|
50341
50720
|
candidate.section_id,
|
|
50342
50721
|
candidate.kind,
|
|
50722
|
+
candidate.summary,
|
|
50343
50723
|
candidate.content,
|
|
50344
50724
|
candidate.detail,
|
|
50345
50725
|
candidate.source_ref,
|
|
@@ -50428,7 +50808,7 @@ async function resolveStructuredNodeFilters(input) {
|
|
|
50428
50808
|
if (references.length === 0)
|
|
50429
50809
|
return { status: "ok", options: scoped };
|
|
50430
50810
|
if (!input.index) {
|
|
50431
|
-
throw new ContextError(ExitCode.WorkspaceStateError, "
|
|
50811
|
+
throw new ContextError(ExitCode.WorkspaceStateError, "node_view filter resolution requires retrieval index", {
|
|
50432
50812
|
category: ErrorCategory.Unknown
|
|
50433
50813
|
});
|
|
50434
50814
|
}
|
|
@@ -50450,7 +50830,7 @@ async function resolveStructuredNodeFilters(input) {
|
|
|
50450
50830
|
}
|
|
50451
50831
|
return { status: "ok", options: scoped };
|
|
50452
50832
|
}
|
|
50453
|
-
async function
|
|
50833
|
+
async function runNodeStructuredQuery(ctxDir, getIndex, options, intent, startedAt) {
|
|
50454
50834
|
let scoped = options;
|
|
50455
50835
|
if (options.scope === undefined && hasStructuredFilter(scoped)) {
|
|
50456
50836
|
const exact = await mdriveQuery(structuredInput(ctxDir, scoped));
|
|
@@ -50467,7 +50847,7 @@ async function runNodeSearch(ctxDir, getIndex, options, intent, startedAt) {
|
|
|
50467
50847
|
const scopeValue = scoped.scope ?? (!hasStructuredFilter(scoped) ? scoped.query : undefined);
|
|
50468
50848
|
if (scopeValue !== undefined) {
|
|
50469
50849
|
if (!index) {
|
|
50470
|
-
throw new ContextError(ExitCode.WorkspaceStateError, "
|
|
50850
|
+
throw new ContextError(ExitCode.WorkspaceStateError, "node_view scope resolution requires retrieval index", {
|
|
50471
50851
|
category: ErrorCategory.Unknown
|
|
50472
50852
|
});
|
|
50473
50853
|
}
|
|
@@ -50534,7 +50914,7 @@ async function runRecallLikeSearch(index, options, intent, startedAt) {
|
|
|
50534
50914
|
...allowedNodeSlugs !== undefined ? { allowedNodeSlugs } : {},
|
|
50535
50915
|
text: options.query
|
|
50536
50916
|
});
|
|
50537
|
-
const rawAssist = intent === "
|
|
50917
|
+
const rawAssist = intent === "section_search" ? rawAssistedRecall({
|
|
50538
50918
|
index,
|
|
50539
50919
|
text: options.query,
|
|
50540
50920
|
...allowedNodeSlugs !== undefined ? { allowedNodeSlugs } : {}
|
|
@@ -50547,7 +50927,7 @@ async function runRecallLikeSearch(index, options, intent, startedAt) {
|
|
|
50547
50927
|
const queryTerms = options.query === undefined ? [] : tokenizeKnowledgeText(options.query);
|
|
50548
50928
|
const mentionedNodesForQuery = mentionedQueryNodes(index, options.query);
|
|
50549
50929
|
const support = evidenceTermCoverage({ queryTerms, candidates: mergedCandidates });
|
|
50550
|
-
const unsupportedUnanchoredDescriptionHit = intent === "
|
|
50930
|
+
const unsupportedUnanchoredDescriptionHit = intent === "section_search" && options.query !== undefined && options.scope === undefined && mentionedNodesForQuery.length === 0 && queryTerms.length > 0 && mergedCandidates.length > 0 && support.missing.length > 0;
|
|
50551
50931
|
const candidates = mergedCandidates.map(candidateEntry);
|
|
50552
50932
|
const data = {
|
|
50553
50933
|
query: options.query,
|
|
@@ -50574,7 +50954,7 @@ async function runImpactSearch(ctxDir, index, options, intent, startedAt) {
|
|
|
50574
50954
|
category: ErrorCategory.UserInputInvalid,
|
|
50575
50955
|
flag: "--scope",
|
|
50576
50956
|
expected_flag: "--scope",
|
|
50577
|
-
hint: "Use context query --intent impact_analysis --scope <node_slug>, or use
|
|
50957
|
+
hint: "Use context query --intent impact_analysis --scope <node_slug>, or use section_search for natural-language search."
|
|
50578
50958
|
});
|
|
50579
50959
|
}
|
|
50580
50960
|
const scopeValue = findImpactAnchor(options);
|
|
@@ -50614,7 +50994,7 @@ async function cmdQuery(ctxDir, options) {
|
|
|
50614
50994
|
};
|
|
50615
50995
|
const fallback = options.intent === undefined && options.query !== undefined ? naturalLanguageFallback(await getIndex(), options) : undefined;
|
|
50616
50996
|
const scopedOptions = fallback?.options ?? options;
|
|
50617
|
-
const intent = fallback?.intent ?? (options.intent !== undefined ? options.intent : hasStructuredFilter(options) || options.query === undefined ? "
|
|
50997
|
+
const intent = fallback?.intent ?? (options.intent !== undefined ? options.intent : options.query !== undefined && options.scope !== undefined && !hasNodeViewFilter(options) ? "section_search" : hasStructuredFilter(options) || options.query === undefined ? "node_view" : chooseFallbackIntent(await getIndex(), options.query));
|
|
50618
50998
|
if (intent === "orientation") {
|
|
50619
50999
|
writeQueryOrientation(await getIndex(), options.format, {
|
|
50620
51000
|
...options.tag !== undefined ? { tag: options.tag } : {},
|
|
@@ -50622,11 +51002,11 @@ async function cmdQuery(ctxDir, options) {
|
|
|
50622
51002
|
});
|
|
50623
51003
|
return;
|
|
50624
51004
|
}
|
|
50625
|
-
const response = intent === "
|
|
51005
|
+
const response = intent === "node_lookup" || intent === "node_view" ? await runNodeStructuredQuery(ctxDir, structuredQueryNeedsRetrieval(scopedOptions) ? getIndex : undefined, scopedOptions, intent, startedAt) : intent === "impact_analysis" ? await runImpactSearch(ctxDir, hasImpactAnchor(scopedOptions) ? await getIndex() : undefined, scopedOptions, intent, startedAt) : await runRecallLikeSearch(await getIndex(), scopedOptions, intent, startedAt);
|
|
50626
51006
|
writeQueryResult(response, options.format);
|
|
50627
51007
|
}
|
|
50628
51008
|
function registerQueryCommand(program2) {
|
|
50629
|
-
program2.command("query [query]").description("Query local knowledge with a hit/miss/select protocol").option("--intent <intent>", "query intent: orientation |
|
|
51009
|
+
program2.command("query [query]").description("Query local knowledge with a hit/miss/select protocol").option("--intent <intent>", "query intent: orientation | node_lookup | node_view | section_search | impact_analysis | recall").option("--query <query>", "query text").option("--profile <profile>", "recall profile; only valid with --intent recall").option("--node <slug>", "single Node scope").option("--kind <kind>", "Section kind filter").option("--refers-to <slug>", "reverse Section reference lookup").option("--tag <tag>", "Node tag filter").option("--domain <slug>", "Domain subtree filter").option("--contains-tree [slug]", "contains tree filter").option("--entity-view <slug>", "aggregate view for one entity").option("--scope <slug>", "Node, title, alias, or Domain scope").option("--format <format>", "output format: json | md | table", "table").action(async (query, options) => {
|
|
50630
51010
|
const parsed = parseQueryOptions(query, options);
|
|
50631
51011
|
await runWithPrelude({
|
|
50632
51012
|
name: "query",
|
|
@@ -50755,10 +51135,10 @@ function reviewAgentHints(input) {
|
|
|
50755
51135
|
const contentShapeIssueCount = input.issues.filter((issue2) => issue2.severity === "error" && issue2.path.includes(".proposed") && issue2.path.endsWith(".content") && issue2.message.startsWith("content must")).length;
|
|
50756
51136
|
if (contentShapeIssueCount > 0) {
|
|
50757
51137
|
hints.push({
|
|
50758
|
-
code: "review-content-
|
|
51138
|
+
code: "review-content-shape",
|
|
50759
51139
|
severity: "error",
|
|
50760
51140
|
message: `${contentShapeIssueCount} proposed content field(s) contain long, multi-line, or code-block material.`,
|
|
50761
|
-
next_action: "
|
|
51141
|
+
next_action: "Use proposed.content for the active Section text and add proposed.summary for long content; rerun review with the current semantic-decisions schema.",
|
|
50762
51142
|
schema: "context schema semantic-decisions --format yaml"
|
|
50763
51143
|
});
|
|
50764
51144
|
}
|
|
@@ -50839,13 +51219,13 @@ function reviewAgentHints(input) {
|
|
|
50839
51219
|
next_action: "Proceed only if the weak summary/compression is acceptable for this workflow; otherwise narrow content or choose/split source_ref/source_refs."
|
|
50840
51220
|
});
|
|
50841
51221
|
}
|
|
50842
|
-
const exampleDetailQuestionCount = input.questions.filter((question) => question.type === "
|
|
51222
|
+
const exampleDetailQuestionCount = input.questions.filter((question) => question.type === "example_content_preservation").length;
|
|
50843
51223
|
if (exampleDetailQuestionCount > 0) {
|
|
50844
51224
|
hints.push({
|
|
50845
|
-
code: "example-
|
|
51225
|
+
code: "example-content-preservation",
|
|
50846
51226
|
severity: "warning",
|
|
50847
|
-
message: `${exampleDetailQuestionCount} example decision(s) cite code/config/command evidence without preserving it in
|
|
50848
|
-
next_action: "Move the relevant fenced block into proposed.
|
|
51227
|
+
message: `${exampleDetailQuestionCount} example decision(s) cite code/config/command evidence without preserving it in content.`,
|
|
51228
|
+
next_action: "Move the relevant fenced block into proposed.content and rerun review, or ask the user to confirm prose-only summary is acceptable. Auto mode or general permission to continue is not confirmation."
|
|
50849
51229
|
});
|
|
50850
51230
|
}
|
|
50851
51231
|
const urlReferenceQuestionCount = input.questions.filter((question) => question.type === "url_reference_preservation").length;
|
|
@@ -50854,7 +51234,7 @@ function reviewAgentHints(input) {
|
|
|
50854
51234
|
code: "url-reference-preservation",
|
|
50855
51235
|
severity: "warning",
|
|
50856
51236
|
message: `${urlReferenceQuestionCount} decision(s) cite URL evidence without preserving the referenced link.`,
|
|
50857
|
-
next_action: "Append each question's
|
|
51237
|
+
next_action: "Append each question's suggested_content_append to proposed.content and rerun review, or ask the user to confirm the link may be omitted. Auto mode or general permission to continue is not confirmation."
|
|
50858
51238
|
});
|
|
50859
51239
|
}
|
|
50860
51240
|
const unresolvedQuestionCount = input.questions.length;
|
|
@@ -50916,7 +51296,7 @@ function urlReferencePreservationQuestion(input) {
|
|
|
50916
51296
|
detail: input.decision.proposed?.detail,
|
|
50917
51297
|
citedText: citedTextForDecision(input.decision, input.item)
|
|
50918
51298
|
});
|
|
50919
|
-
const
|
|
51299
|
+
const suggestedContentAppend = diagnostic.missingUrls.map((url) => `- ${url}`).join(`
|
|
50920
51300
|
`);
|
|
50921
51301
|
return {
|
|
50922
51302
|
question_id: `q-${String(input.questionIndex + 1).padStart(3, "0")}`,
|
|
@@ -50927,11 +51307,11 @@ function urlReferencePreservationQuestion(input) {
|
|
|
50927
51307
|
cited_urls: diagnostic.citedUrls,
|
|
50928
51308
|
missing_urls: diagnostic.missingUrls,
|
|
50929
51309
|
repair_options: [
|
|
50930
|
-
"Append
|
|
51310
|
+
"Append suggested_content_append to proposed.content and rerun review.",
|
|
50931
51311
|
"Ask the user only if the URL should intentionally be omitted; auto mode is not confirmation."
|
|
50932
51312
|
],
|
|
50933
|
-
|
|
50934
|
-
prompt: "The cited raw evidence includes URL(s), but this document/link/reference claim does not preserve them in proposed
|
|
51313
|
+
suggested_content_append: suggestedContentAppend,
|
|
51314
|
+
prompt: "The cited raw evidence includes URL(s), but this document/link/reference claim does not preserve them in proposed.content. " + "Append suggested_content_append to proposed.content and rerun review, or ask the user to confirm that omitting the link is acceptable and mark the decision decided_by: user. Auto mode or general permission to continue is not confirmation."
|
|
50935
51315
|
};
|
|
50936
51316
|
}
|
|
50937
51317
|
function urlReferencePreservationQuestions(input) {
|
|
@@ -51197,7 +51577,195 @@ function semanticDecisionSchemaErrorReview(input) {
|
|
|
51197
51577
|
|
|
51198
51578
|
// src/reconcile/review.ts
|
|
51199
51579
|
init_compileJudge();
|
|
51200
|
-
|
|
51580
|
+
|
|
51581
|
+
// src/reconcile/delegatedDecisions.ts
|
|
51582
|
+
var DELEGATED_DECIDED_BY = "delegated_agent";
|
|
51583
|
+
function isDelegatedWeakDefault(item) {
|
|
51584
|
+
const support = item.source_support;
|
|
51585
|
+
return support?.verdict === "weak" && (support.missing_hard_terms?.length ?? 0) === 0;
|
|
51586
|
+
}
|
|
51587
|
+
function allowsWeakSourceSupport(input) {
|
|
51588
|
+
return input.decision.decided_by === "user" || input.allowDelegatedDecisions === true && input.decision.decided_by === DELEGATED_DECIDED_BY;
|
|
51589
|
+
}
|
|
51590
|
+
function delegatedDecisionModeIssues(input) {
|
|
51591
|
+
if (input.allowDelegatedDecisions === true)
|
|
51592
|
+
return [];
|
|
51593
|
+
return input.decisions.filter((decision) => decision.decided_by === DELEGATED_DECIDED_BY).map((decision) => ({
|
|
51594
|
+
path: `${decision.item_id}.decided_by`,
|
|
51595
|
+
item_id: decision.item_id,
|
|
51596
|
+
severity: "error",
|
|
51597
|
+
code: "delegated-decision-without-workflow-mode",
|
|
51598
|
+
message: "delegated_agent decisions require a delegated compile workflow created with --delegated",
|
|
51599
|
+
next_action: "Do not mark decisions as delegated_agent manually. Restart the compile workflow with --delegated only when the user explicitly authorized delegated mode at the start of the conversation."
|
|
51600
|
+
}));
|
|
51601
|
+
}
|
|
51602
|
+
function assertDelegatedDecisionsAllowed(input) {
|
|
51603
|
+
if (input.allowDelegatedDecisions === true)
|
|
51604
|
+
return;
|
|
51605
|
+
if (input.decisions.some((decision) => decision.decided_by === DELEGATED_DECIDED_BY)) {
|
|
51606
|
+
throw new Error("delegated_agent decisions require a delegated workflow created with --delegated");
|
|
51607
|
+
}
|
|
51608
|
+
}
|
|
51609
|
+
|
|
51610
|
+
// src/reconcile/reviewSourceSupport.ts
|
|
51611
|
+
init_sourceSupport();
|
|
51612
|
+
var FENCED_CODE_RE = /(^|\n)\s*(```|~~~)/u;
|
|
51613
|
+
function preparedSupportContentMatches(input) {
|
|
51614
|
+
return typeof input.item?.proposed?.content === "string" && input.item.proposed.content === input.content || typeof input.item?.default_decision?.proposed?.content === "string" && input.item.default_decision.proposed.content === input.content;
|
|
51615
|
+
}
|
|
51616
|
+
function actionNeedsSourceSupport2(action) {
|
|
51617
|
+
return action === "keep_separate" || actionRequiresStrictSourceSupport(action);
|
|
51618
|
+
}
|
|
51619
|
+
function actionRequiresStrictSourceSupport(action) {
|
|
51620
|
+
return action === "merge_update" || action === "supersede" || action === "reanchor" || action === "split_then_reanchor";
|
|
51621
|
+
}
|
|
51622
|
+
function sourceRefChangedFromPreparedSupport(input) {
|
|
51623
|
+
const proposedSourceRef = input.decision.proposed?.source_ref;
|
|
51624
|
+
const preparedSourceRef = input.item?.source_support?.source_ref;
|
|
51625
|
+
return typeof proposedSourceRef === "string" && typeof preparedSourceRef === "string" && proposedSourceRef !== preparedSourceRef;
|
|
51626
|
+
}
|
|
51627
|
+
function supportKind(decision, item) {
|
|
51628
|
+
if (typeof decision.proposed?.kind === "string")
|
|
51629
|
+
return decision.proposed.kind;
|
|
51630
|
+
const target = decision.target ?? item?.target;
|
|
51631
|
+
if (target?.section_id !== undefined) {
|
|
51632
|
+
const targetCandidate = item?.candidates.find((candidate) => candidate.node === target.node && candidate.section_id === target.section_id);
|
|
51633
|
+
if (targetCandidate !== undefined)
|
|
51634
|
+
return targetCandidate.kind;
|
|
51635
|
+
}
|
|
51636
|
+
return typeof item?.proposed?.kind === "string" ? item.proposed.kind : undefined;
|
|
51637
|
+
}
|
|
51638
|
+
function supportDiagnosticFromItem(input) {
|
|
51639
|
+
if (input.decision.user_confirmation?.required === true)
|
|
51640
|
+
return null;
|
|
51641
|
+
if (input.decision.action === "ask_user")
|
|
51642
|
+
return null;
|
|
51643
|
+
if (!actionNeedsSourceSupport2(input.decision.action))
|
|
51644
|
+
return null;
|
|
51645
|
+
if (input.decision.judge_support_verdict !== undefined) {
|
|
51646
|
+
return {
|
|
51647
|
+
verdict: input.decision.judge_support_verdict,
|
|
51648
|
+
contentTermCount: 1,
|
|
51649
|
+
matchedTermCount: input.decision.judge_support_verdict === "unsupported" ? 0 : 1,
|
|
51650
|
+
requiredTermCount: 1,
|
|
51651
|
+
overlapRatio: input.decision.judge_support_verdict === "unsupported" ? 0 : 1,
|
|
51652
|
+
missingContentTerms: [],
|
|
51653
|
+
missingHardTerms: []
|
|
51654
|
+
};
|
|
51655
|
+
}
|
|
51656
|
+
const content = input.decision.proposed?.content;
|
|
51657
|
+
const sourceRef = input.decision.proposed?.source_ref;
|
|
51658
|
+
if (typeof content !== "string" || typeof sourceRef !== "string")
|
|
51659
|
+
return null;
|
|
51660
|
+
const kind = supportKind(input.decision, input.item);
|
|
51661
|
+
const detail = input.decision.proposed?.detail === null || typeof input.decision.proposed?.detail === "string" ? input.decision.proposed.detail : undefined;
|
|
51662
|
+
const itemSupport = input.item?.source_support;
|
|
51663
|
+
if (itemSupport !== undefined && itemSupport.source_ref === sourceRef && typeof itemSupport.cited_text === "string") {
|
|
51664
|
+
return sourceSectionSupportDiagnostic({ kind, content, detail, citedText: itemSupport.cited_text });
|
|
51665
|
+
}
|
|
51666
|
+
if (itemSupport !== undefined && itemSupport.source_ref === sourceRef && preparedSupportContentMatches({ content, item: input.item })) {
|
|
51667
|
+
return {
|
|
51668
|
+
verdict: itemSupport.verdict,
|
|
51669
|
+
contentTermCount: itemSupport.content_term_count,
|
|
51670
|
+
matchedTermCount: itemSupport.matched_term_count,
|
|
51671
|
+
requiredTermCount: itemSupport.required_term_count,
|
|
51672
|
+
overlapRatio: itemSupport.overlap_ratio,
|
|
51673
|
+
missingContentTerms: itemSupport.missing_content_terms,
|
|
51674
|
+
missingHardTerms: itemSupport.missing_hard_terms
|
|
51675
|
+
};
|
|
51676
|
+
}
|
|
51677
|
+
const citedText = (input.item?.evidence ?? []).filter((span) => span.source_ref === undefined || span.source_ref === sourceRef).map((span) => span.quote).filter((quote) => typeof quote === "string" && quote.trim().length > 0).join(`
|
|
51678
|
+
`);
|
|
51679
|
+
return citedText.length > 0 ? sourceSectionSupportDiagnostic({ kind, content, detail, citedText }) : null;
|
|
51680
|
+
}
|
|
51681
|
+
function sourceSupportIssue(input) {
|
|
51682
|
+
const action = input.decision.action;
|
|
51683
|
+
const strict = actionRequiresStrictSourceSupport(action);
|
|
51684
|
+
const splitCandidates = input.support?.evidence_block_candidates?.slice(0, 6).map((candidate) => `${candidate.source_ref} (${candidate.block_locator_id})`).join("; ");
|
|
51685
|
+
const repairHint = strict ? "Use source_ref/source_refs copied from prepared evidence that fully covers the rewritten/reanchored content, split separable claims, or ask the user before choosing a different final action." : "Use source_ref/source_refs copied from prepared evidence that covers every sentence, split the summary into separately supported claims, or ask the user to confirm a weak summary only after the evidence boundary is correct.";
|
|
51686
|
+
const splitHint = splitCandidates !== undefined && splitCandidates.length > 0 ? ` Candidate evidence blocks for split decisions: ${splitCandidates}.` : "";
|
|
51687
|
+
const splitCandidateCount = input.support?.evidence_block_candidates?.length ?? 0;
|
|
51688
|
+
return {
|
|
51689
|
+
path: `${input.decision.item_id}.proposed.source_ref`,
|
|
51690
|
+
message: strict ? `${action} requires direct support from cited evidence before apply: ${formatSupportDiagnostic(input.diagnostic)}. ${repairHint}${splitHint}` : `proposed keep_separate is not supported by its cited raw text: ${formatSupportDiagnostic(input.diagnostic)}. ${repairHint}${splitHint}`,
|
|
51691
|
+
severity: "error",
|
|
51692
|
+
...splitCandidateCount > 1 ? { code: "source-support-split-by-evidence-blocks" } : {}
|
|
51693
|
+
};
|
|
51694
|
+
}
|
|
51695
|
+
function weakSupportWarning(input) {
|
|
51696
|
+
return {
|
|
51697
|
+
path: `${input.decision.item_id}.proposed.source_ref`,
|
|
51698
|
+
item_id: input.decision.item_id,
|
|
51699
|
+
severity: "warning",
|
|
51700
|
+
code: "weak-source-support",
|
|
51701
|
+
message: `proposed keep_separate is weakly supported by its cited raw text: ${formatSupportDiagnostic(input.diagnostic)}.`,
|
|
51702
|
+
next_action: "Review the cited evidence if the summary looks surprising; missing hard facts still remain errors."
|
|
51703
|
+
};
|
|
51704
|
+
}
|
|
51705
|
+
function citedTextForDecision2(decision, item) {
|
|
51706
|
+
const sourceRef = decision.proposed?.source_ref;
|
|
51707
|
+
const itemSupport = item?.source_support;
|
|
51708
|
+
if (typeof sourceRef === "string" && itemSupport?.source_ref === sourceRef && typeof itemSupport.cited_text === "string") {
|
|
51709
|
+
return itemSupport.cited_text;
|
|
51710
|
+
}
|
|
51711
|
+
return (item?.evidence ?? []).filter((span) => span.source_ref === undefined || span.source_ref === sourceRef).map((span) => span.quote).filter((quote) => typeof quote === "string" && quote.trim().length > 0).join(`
|
|
51712
|
+
`);
|
|
51713
|
+
}
|
|
51714
|
+
function needsExampleDetailPreservationQuestion(input) {
|
|
51715
|
+
if (input.decision.user_confirmation?.required === true || input.decision.action === "ask_user")
|
|
51716
|
+
return false;
|
|
51717
|
+
if (input.decision.decided_by === "user")
|
|
51718
|
+
return false;
|
|
51719
|
+
if (!actionNeedsSourceSupport2(input.decision.action))
|
|
51720
|
+
return false;
|
|
51721
|
+
if (supportKind(input.decision, input.item) !== "example")
|
|
51722
|
+
return false;
|
|
51723
|
+
if (!FENCED_CODE_RE.test(citedTextForDecision2(input.decision, input.item)))
|
|
51724
|
+
return false;
|
|
51725
|
+
return !FENCED_CODE_RE.test(input.decision.proposed?.content ?? "");
|
|
51726
|
+
}
|
|
51727
|
+
function exampleDetailPreservationQuestion(input) {
|
|
51728
|
+
return {
|
|
51729
|
+
question_id: `q-${String(input.questionIndex + 1).padStart(3, "0")}`,
|
|
51730
|
+
item_id: input.decision.item_id,
|
|
51731
|
+
type: "example_content_preservation",
|
|
51732
|
+
...input.summary !== undefined ? { candidate_summary: { active: input.summary.active, archive: input.summary.archive } } : {},
|
|
51733
|
+
...input.decision.proposed?.content !== undefined ? { proposed_content: input.decision.proposed.content } : {},
|
|
51734
|
+
prompt: "The cited raw evidence contains a fenced code/config/command block, but this example decision does not preserve it in proposed.content. " + "Add the relevant fenced block to proposed.content and rerun review, or ask the user to confirm that a prose-only summary is acceptable and mark the decision decided_by: user. Auto mode or general permission to continue is not confirmation."
|
|
51735
|
+
};
|
|
51736
|
+
}
|
|
51737
|
+
function sourceSupportFromDiagnostic(input) {
|
|
51738
|
+
return {
|
|
51739
|
+
source_ref: input.sourceRef,
|
|
51740
|
+
cited_text: input.citedText,
|
|
51741
|
+
verdict: input.diagnostic.verdict,
|
|
51742
|
+
content_term_count: input.diagnostic.contentTermCount,
|
|
51743
|
+
matched_term_count: input.diagnostic.matchedTermCount,
|
|
51744
|
+
required_term_count: input.diagnostic.requiredTermCount,
|
|
51745
|
+
overlap_ratio: input.diagnostic.overlapRatio,
|
|
51746
|
+
missing_content_terms: input.diagnostic.missingContentTerms,
|
|
51747
|
+
missing_hard_terms: input.diagnostic.missingHardTerms,
|
|
51748
|
+
...input.evidenceBlock !== undefined ? {
|
|
51749
|
+
evidence_block_source_ref: input.evidenceBlock.source_ref,
|
|
51750
|
+
evidence_block_line_range: input.evidenceBlock.line_range,
|
|
51751
|
+
evidence_block_locator_id: input.evidenceBlock.block_locator_id
|
|
51752
|
+
} : {},
|
|
51753
|
+
...input.evidenceBlockCandidates !== undefined ? { evidence_block_candidates: input.evidenceBlockCandidates } : {}
|
|
51754
|
+
};
|
|
51755
|
+
}
|
|
51756
|
+
function needsWorkspaceSupportReview(decision, item) {
|
|
51757
|
+
if (decision.user_confirmation?.required === true || decision.action === "ask_user")
|
|
51758
|
+
return false;
|
|
51759
|
+
if (!actionNeedsSourceSupport2(decision.action))
|
|
51760
|
+
return false;
|
|
51761
|
+
const sourceRef = decision.proposed?.source_ref;
|
|
51762
|
+
const content = decision.proposed?.content;
|
|
51763
|
+
if (typeof sourceRef !== "string" || typeof content !== "string")
|
|
51764
|
+
return false;
|
|
51765
|
+
return item?.source_support?.source_ref !== sourceRef || item.source_support.cited_text === undefined;
|
|
51766
|
+
}
|
|
51767
|
+
|
|
51768
|
+
// src/reconcile/review.ts
|
|
51201
51769
|
function isRecord21(value) {
|
|
51202
51770
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
51203
51771
|
}
|
|
@@ -51356,13 +51924,13 @@ function decisionItemIdIssues(input) {
|
|
|
51356
51924
|
}];
|
|
51357
51925
|
});
|
|
51358
51926
|
}
|
|
51359
|
-
function
|
|
51360
|
-
const
|
|
51361
|
-
return
|
|
51927
|
+
function preparedOptionalText(item, field) {
|
|
51928
|
+
const value = item?.proposed?.[field];
|
|
51929
|
+
return value === null || typeof value === "string" ? value : undefined;
|
|
51362
51930
|
}
|
|
51363
|
-
function
|
|
51364
|
-
const
|
|
51365
|
-
if (
|
|
51931
|
+
function shouldPreservePreparedOptionalText(decision, item, field) {
|
|
51932
|
+
const value = preparedOptionalText(item, field);
|
|
51933
|
+
if (value === undefined || !decision.proposed || decision.proposed[field] !== undefined)
|
|
51366
51934
|
return false;
|
|
51367
51935
|
const prepared = item?.proposed;
|
|
51368
51936
|
if (typeof prepared?.content === "string" && typeof decision.proposed.content === "string" && prepared.content !== decision.proposed.content) {
|
|
@@ -51373,23 +51941,29 @@ function shouldPreservePreparedDetail(decision, item) {
|
|
|
51373
51941
|
}
|
|
51374
51942
|
return true;
|
|
51375
51943
|
}
|
|
51376
|
-
function
|
|
51944
|
+
function preservePreparedOptionalText(input) {
|
|
51377
51945
|
const issues = [];
|
|
51378
51946
|
const decisions = input.document.decisions.map((decision, index) => {
|
|
51379
51947
|
const item = input.itemById.get(decision.item_id);
|
|
51380
|
-
const
|
|
51381
|
-
|
|
51948
|
+
const preserved = {};
|
|
51949
|
+
for (const field of ["summary", "raw"]) {
|
|
51950
|
+
const value = preparedOptionalText(item, field);
|
|
51951
|
+
if (value === undefined || !shouldPreservePreparedOptionalText(decision, item, field))
|
|
51952
|
+
continue;
|
|
51953
|
+
preserved[field] = value;
|
|
51954
|
+
issues.push({
|
|
51955
|
+
path: `decisions[${index}].proposed.${field}`,
|
|
51956
|
+
message: `decision omitted proposed.${field} from the prepared context; review apply_document preserves it for apply`,
|
|
51957
|
+
severity: "warning"
|
|
51958
|
+
});
|
|
51959
|
+
}
|
|
51960
|
+
if (Object.keys(preserved).length === 0)
|
|
51382
51961
|
return decision;
|
|
51383
|
-
issues.push({
|
|
51384
|
-
path: `decisions[${index}].proposed.detail`,
|
|
51385
|
-
message: "decision omitted proposed.detail from the prepared context; review apply_document preserves it for apply",
|
|
51386
|
-
severity: "warning"
|
|
51387
|
-
});
|
|
51388
51962
|
return {
|
|
51389
51963
|
...decision,
|
|
51390
51964
|
proposed: {
|
|
51391
51965
|
...decision.proposed,
|
|
51392
|
-
|
|
51966
|
+
...preserved
|
|
51393
51967
|
}
|
|
51394
51968
|
};
|
|
51395
51969
|
});
|
|
@@ -51405,6 +51979,8 @@ function proposedPatchFromItem(item) {
|
|
|
51405
51979
|
kind: proposed.kind,
|
|
51406
51980
|
content: proposed.content,
|
|
51407
51981
|
source_ref: proposed.source_ref,
|
|
51982
|
+
...typeof proposed.summary === "string" || proposed.summary === null ? { summary: proposed.summary } : {},
|
|
51983
|
+
...typeof proposed.raw === "string" || proposed.raw === null ? { raw: proposed.raw } : {},
|
|
51408
51984
|
...typeof proposed.detail === "string" || proposed.detail === null ? { detail: proposed.detail } : {},
|
|
51409
51985
|
...typeof proposed.confidence === "string" ? { confidence: proposed.confidence } : {},
|
|
51410
51986
|
...Array.isArray(proposed.refers_to_nodes) && proposed.refers_to_nodes.every((value) => typeof value === "string") ? { refers_to_nodes: proposed.refers_to_nodes } : {}
|
|
@@ -51421,133 +51997,6 @@ function hydrateOmitDecisions(input) {
|
|
|
51421
51997
|
})
|
|
51422
51998
|
};
|
|
51423
51999
|
}
|
|
51424
|
-
function supportDiagnosticFromItem(input) {
|
|
51425
|
-
if (input.decision.user_confirmation?.required === true)
|
|
51426
|
-
return null;
|
|
51427
|
-
if (input.decision.action === "ask_user")
|
|
51428
|
-
return null;
|
|
51429
|
-
if (!actionNeedsSourceSupport2(input.decision.action))
|
|
51430
|
-
return null;
|
|
51431
|
-
if (input.decision.judge_support_verdict !== undefined) {
|
|
51432
|
-
return {
|
|
51433
|
-
verdict: input.decision.judge_support_verdict,
|
|
51434
|
-
contentTermCount: 1,
|
|
51435
|
-
matchedTermCount: input.decision.judge_support_verdict === "unsupported" ? 0 : 1,
|
|
51436
|
-
requiredTermCount: 1,
|
|
51437
|
-
overlapRatio: input.decision.judge_support_verdict === "unsupported" ? 0 : 1,
|
|
51438
|
-
missingContentTerms: [],
|
|
51439
|
-
missingHardTerms: []
|
|
51440
|
-
};
|
|
51441
|
-
}
|
|
51442
|
-
const content = input.decision.proposed?.content;
|
|
51443
|
-
const sourceRef = input.decision.proposed?.source_ref;
|
|
51444
|
-
if (typeof content !== "string" || typeof sourceRef !== "string")
|
|
51445
|
-
return null;
|
|
51446
|
-
const kind = supportKind(input.decision, input.item);
|
|
51447
|
-
const detail = input.decision.proposed?.detail === null || typeof input.decision.proposed?.detail === "string" ? input.decision.proposed.detail : undefined;
|
|
51448
|
-
const itemSupport = input.item?.source_support;
|
|
51449
|
-
if (itemSupport !== undefined && itemSupport.source_ref === sourceRef && typeof itemSupport.cited_text === "string") {
|
|
51450
|
-
return sourceSectionSupportDiagnostic({ kind, content, detail, citedText: itemSupport.cited_text });
|
|
51451
|
-
}
|
|
51452
|
-
if (itemSupport !== undefined && itemSupport.source_ref === sourceRef && preparedSupportContentMatches({
|
|
51453
|
-
content,
|
|
51454
|
-
item: input.item
|
|
51455
|
-
})) {
|
|
51456
|
-
return {
|
|
51457
|
-
verdict: itemSupport.verdict,
|
|
51458
|
-
contentTermCount: itemSupport.content_term_count,
|
|
51459
|
-
matchedTermCount: itemSupport.matched_term_count,
|
|
51460
|
-
requiredTermCount: itemSupport.required_term_count,
|
|
51461
|
-
overlapRatio: itemSupport.overlap_ratio,
|
|
51462
|
-
missingContentTerms: itemSupport.missing_content_terms,
|
|
51463
|
-
missingHardTerms: itemSupport.missing_hard_terms
|
|
51464
|
-
};
|
|
51465
|
-
}
|
|
51466
|
-
const citedText = (input.item?.evidence ?? []).filter((span) => span.source_ref === undefined || span.source_ref === sourceRef).map((span) => span.quote).filter((quote) => typeof quote === "string" && quote.trim().length > 0).join(`
|
|
51467
|
-
`);
|
|
51468
|
-
return citedText.length > 0 ? sourceSectionSupportDiagnostic({ kind, content, detail, citedText }) : null;
|
|
51469
|
-
}
|
|
51470
|
-
function preparedSupportContentMatches(input) {
|
|
51471
|
-
return typeof input.item?.proposed?.content === "string" && input.item.proposed.content === input.content || typeof input.item?.default_decision?.proposed?.content === "string" && input.item.default_decision.proposed.content === input.content;
|
|
51472
|
-
}
|
|
51473
|
-
function actionNeedsSourceSupport2(action) {
|
|
51474
|
-
return action === "keep_separate" || actionRequiresStrictSourceSupport(action);
|
|
51475
|
-
}
|
|
51476
|
-
function actionRequiresStrictSourceSupport(action) {
|
|
51477
|
-
return action === "merge_update" || action === "supersede" || action === "reanchor" || action === "split_then_reanchor";
|
|
51478
|
-
}
|
|
51479
|
-
function sourceRefChangedFromPreparedSupport(input) {
|
|
51480
|
-
const proposedSourceRef = input.decision.proposed?.source_ref;
|
|
51481
|
-
const preparedSourceRef = input.item?.source_support?.source_ref;
|
|
51482
|
-
return typeof proposedSourceRef === "string" && typeof preparedSourceRef === "string" && proposedSourceRef !== preparedSourceRef;
|
|
51483
|
-
}
|
|
51484
|
-
function supportKind(decision, item) {
|
|
51485
|
-
if (typeof decision.proposed?.kind === "string")
|
|
51486
|
-
return decision.proposed.kind;
|
|
51487
|
-
const target = decision.target ?? item?.target;
|
|
51488
|
-
if (target?.section_id !== undefined) {
|
|
51489
|
-
const targetCandidate = item?.candidates.find((candidate) => candidate.node === target.node && candidate.section_id === target.section_id);
|
|
51490
|
-
if (targetCandidate !== undefined)
|
|
51491
|
-
return targetCandidate.kind;
|
|
51492
|
-
}
|
|
51493
|
-
return typeof item?.proposed?.kind === "string" ? item.proposed.kind : undefined;
|
|
51494
|
-
}
|
|
51495
|
-
function sourceSupportIssue(input) {
|
|
51496
|
-
const action = input.decision.action;
|
|
51497
|
-
const strict = actionRequiresStrictSourceSupport(action);
|
|
51498
|
-
const splitCandidates = input.support?.evidence_block_candidates?.slice(0, 6).map((candidate) => `${candidate.source_ref} (${candidate.block_locator_id})`).join("; ");
|
|
51499
|
-
const repairHint = strict ? "Use source_ref/source_refs copied from prepared evidence that fully covers the rewritten/reanchored content, split separable claims, or ask the user before choosing a different final action." : "Use source_ref/source_refs copied from prepared evidence that covers every sentence, split the summary into separately supported claims, or ask the user to confirm a weak summary only after the evidence boundary is correct.";
|
|
51500
|
-
const splitHint = splitCandidates !== undefined && splitCandidates.length > 0 ? ` Candidate evidence blocks for split decisions: ${splitCandidates}.` : "";
|
|
51501
|
-
const splitCandidateCount = input.support?.evidence_block_candidates?.length ?? 0;
|
|
51502
|
-
return {
|
|
51503
|
-
path: `${input.decision.item_id}.proposed.source_ref`,
|
|
51504
|
-
message: strict ? `${action} requires direct support from cited evidence before apply: ${formatSupportDiagnostic(input.diagnostic)}. ${repairHint}${splitHint}` : `proposed keep_separate is not supported by its cited raw text: ${formatSupportDiagnostic(input.diagnostic)}. ${repairHint}${splitHint}`,
|
|
51505
|
-
severity: "error",
|
|
51506
|
-
...splitCandidateCount > 1 ? { code: "source-support-split-by-evidence-blocks" } : {}
|
|
51507
|
-
};
|
|
51508
|
-
}
|
|
51509
|
-
function weakSupportWarning(input) {
|
|
51510
|
-
return {
|
|
51511
|
-
path: `${input.decision.item_id}.proposed.source_ref`,
|
|
51512
|
-
item_id: input.decision.item_id,
|
|
51513
|
-
severity: "warning",
|
|
51514
|
-
code: "weak-source-support",
|
|
51515
|
-
message: `proposed keep_separate is weakly supported by its cited raw text: ${formatSupportDiagnostic(input.diagnostic)}.`,
|
|
51516
|
-
next_action: "Review the cited evidence if the summary looks surprising; missing hard facts still remain errors."
|
|
51517
|
-
};
|
|
51518
|
-
}
|
|
51519
|
-
function citedTextForDecision2(decision, item) {
|
|
51520
|
-
const sourceRef = decision.proposed?.source_ref;
|
|
51521
|
-
const itemSupport = item?.source_support;
|
|
51522
|
-
if (typeof sourceRef === "string" && itemSupport?.source_ref === sourceRef && typeof itemSupport.cited_text === "string") {
|
|
51523
|
-
return itemSupport.cited_text;
|
|
51524
|
-
}
|
|
51525
|
-
return (item?.evidence ?? []).filter((span) => span.source_ref === undefined || span.source_ref === sourceRef).map((span) => span.quote).filter((quote) => typeof quote === "string" && quote.trim().length > 0).join(`
|
|
51526
|
-
`);
|
|
51527
|
-
}
|
|
51528
|
-
function needsExampleDetailPreservationQuestion(input) {
|
|
51529
|
-
if (input.decision.user_confirmation?.required === true || input.decision.action === "ask_user")
|
|
51530
|
-
return false;
|
|
51531
|
-
if (input.decision.decided_by === "user")
|
|
51532
|
-
return false;
|
|
51533
|
-
if (!actionNeedsSourceSupport2(input.decision.action))
|
|
51534
|
-
return false;
|
|
51535
|
-
if (supportKind(input.decision, input.item) !== "example")
|
|
51536
|
-
return false;
|
|
51537
|
-
if (!FENCED_CODE_RE2.test(citedTextForDecision2(input.decision, input.item)))
|
|
51538
|
-
return false;
|
|
51539
|
-
return !FENCED_CODE_RE2.test(input.decision.proposed?.detail ?? "");
|
|
51540
|
-
}
|
|
51541
|
-
function exampleDetailPreservationQuestion(input) {
|
|
51542
|
-
return {
|
|
51543
|
-
question_id: `q-${String(input.questionIndex + 1).padStart(3, "0")}`,
|
|
51544
|
-
item_id: input.decision.item_id,
|
|
51545
|
-
type: "example_detail_preservation",
|
|
51546
|
-
...input.summary !== undefined ? { candidate_summary: { active: input.summary.active, archive: input.summary.archive } } : {},
|
|
51547
|
-
...input.decision.proposed?.content !== undefined ? { proposed_content: input.decision.proposed.content } : {},
|
|
51548
|
-
prompt: "The cited raw evidence contains a fenced code/config/command block, but this example decision does not preserve it in proposed.detail. " + "Add the relevant fenced block to proposed.detail and rerun review, or ask the user to confirm that a prose-only summary is acceptable and mark the decision decided_by: user. Auto mode or general permission to continue is not confirmation."
|
|
51549
|
-
};
|
|
51550
|
-
}
|
|
51551
52000
|
function itemRequiresDecision(item) {
|
|
51552
52001
|
return item.status === undefined || item.status === "pending";
|
|
51553
52002
|
}
|
|
@@ -51582,7 +52031,7 @@ function reviewSemanticDecisions(input) {
|
|
|
51582
52031
|
candidateSummary
|
|
51583
52032
|
});
|
|
51584
52033
|
}
|
|
51585
|
-
const preserved =
|
|
52034
|
+
const preserved = preservePreparedOptionalText({
|
|
51586
52035
|
document: validation.document ?? { schema_version: "1.0", decisions: [] },
|
|
51587
52036
|
itemById
|
|
51588
52037
|
});
|
|
@@ -51598,7 +52047,11 @@ function reviewSemanticDecisions(input) {
|
|
|
51598
52047
|
...validation.issues.map(semanticValidationIssueToReviewIssue),
|
|
51599
52048
|
...preserved.issues,
|
|
51600
52049
|
...contextIssues,
|
|
51601
|
-
...itemIdIssues
|
|
52050
|
+
...itemIdIssues,
|
|
52051
|
+
...delegatedDecisionModeIssues({
|
|
52052
|
+
decisions: document2.decisions,
|
|
52053
|
+
allowDelegatedDecisions: input.allowDelegatedDecisions
|
|
52054
|
+
})
|
|
51602
52055
|
];
|
|
51603
52056
|
const candidateSummaryByItem = new Map(candidateSummary.map((summary) => [summary.item_id, summary]));
|
|
51604
52057
|
const leakageReview = applyLeakageReview({ document: document2, itemById });
|
|
@@ -51706,41 +52159,16 @@ function reviewSemanticDecisions(input) {
|
|
|
51706
52159
|
})
|
|
51707
52160
|
};
|
|
51708
52161
|
}
|
|
51709
|
-
function sourceSupportFromDiagnostic(input) {
|
|
51710
|
-
return {
|
|
51711
|
-
source_ref: input.sourceRef,
|
|
51712
|
-
cited_text: input.citedText,
|
|
51713
|
-
verdict: input.diagnostic.verdict,
|
|
51714
|
-
content_term_count: input.diagnostic.contentTermCount,
|
|
51715
|
-
matched_term_count: input.diagnostic.matchedTermCount,
|
|
51716
|
-
required_term_count: input.diagnostic.requiredTermCount,
|
|
51717
|
-
overlap_ratio: input.diagnostic.overlapRatio,
|
|
51718
|
-
missing_content_terms: input.diagnostic.missingContentTerms,
|
|
51719
|
-
missing_hard_terms: input.diagnostic.missingHardTerms,
|
|
51720
|
-
...input.evidenceBlock !== undefined ? {
|
|
51721
|
-
evidence_block_source_ref: input.evidenceBlock.source_ref,
|
|
51722
|
-
evidence_block_line_range: input.evidenceBlock.line_range,
|
|
51723
|
-
evidence_block_locator_id: input.evidenceBlock.block_locator_id
|
|
51724
|
-
} : {},
|
|
51725
|
-
...input.evidenceBlockCandidates !== undefined ? { evidence_block_candidates: input.evidenceBlockCandidates } : {}
|
|
51726
|
-
};
|
|
51727
|
-
}
|
|
51728
|
-
function needsWorkspaceSupportReview(decision, item) {
|
|
51729
|
-
if (decision.user_confirmation?.required === true || decision.action === "ask_user")
|
|
51730
|
-
return false;
|
|
51731
|
-
if (!actionNeedsSourceSupport2(decision.action))
|
|
51732
|
-
return false;
|
|
51733
|
-
const sourceRef = decision.proposed?.source_ref;
|
|
51734
|
-
const content = decision.proposed?.content;
|
|
51735
|
-
if (typeof sourceRef !== "string" || typeof content !== "string")
|
|
51736
|
-
return false;
|
|
51737
|
-
return item?.source_support?.source_ref !== sourceRef || item.source_support.cited_text === undefined;
|
|
51738
|
-
}
|
|
51739
52162
|
async function reviewSemanticDecisionsWithWorkspace(input) {
|
|
51740
52163
|
const itemById = new Map(input.context.items.map((item) => [item.item_id, item]));
|
|
51741
52164
|
const validation = validateSemanticDecisionDocument(hydrateRawPreparedDefaults(input.decisions, itemById));
|
|
51742
|
-
if (!validation.document)
|
|
51743
|
-
return reviewSemanticDecisions({
|
|
52165
|
+
if (!validation.document) {
|
|
52166
|
+
return reviewSemanticDecisions({
|
|
52167
|
+
context: input.context,
|
|
52168
|
+
decisions: input.decisions,
|
|
52169
|
+
...input.allowDelegatedDecisions !== undefined ? { allowDelegatedDecisions: input.allowDelegatedDecisions } : {}
|
|
52170
|
+
});
|
|
52171
|
+
}
|
|
51744
52172
|
const sources = await loadSources(input.ctxDir);
|
|
51745
52173
|
const sourceById = new Map(sources.sources.map((source2) => [source2.id, source2]));
|
|
51746
52174
|
const nodes = await readWorkspaceNodeFiles(input.ctxDir).then(flattenWorkspaceNodes).catch(() => []);
|
|
@@ -51768,6 +52196,7 @@ async function reviewSemanticDecisionsWithWorkspace(input) {
|
|
|
51768
52196
|
section: {
|
|
51769
52197
|
kind: supportKind(decision, item),
|
|
51770
52198
|
content,
|
|
52199
|
+
...typeof decision.proposed?.summary === "string" || decision.proposed?.summary === null ? { summary: decision.proposed.summary } : {},
|
|
51771
52200
|
...typeof decision.proposed?.detail === "string" || decision.proposed?.detail === null ? { detail: decision.proposed.detail } : {},
|
|
51772
52201
|
source_ref: sourceRef
|
|
51773
52202
|
}
|
|
@@ -51804,7 +52233,8 @@ async function reviewSemanticDecisionsWithWorkspace(input) {
|
|
|
51804
52233
|
return reviewSemanticDecisions({
|
|
51805
52234
|
context: { ...input.context, items: enrichedItems },
|
|
51806
52235
|
decisions: input.decisions,
|
|
51807
|
-
knownSlugs
|
|
52236
|
+
knownSlugs,
|
|
52237
|
+
...input.allowDelegatedDecisions !== undefined ? { allowDelegatedDecisions: input.allowDelegatedDecisions } : {}
|
|
51808
52238
|
});
|
|
51809
52239
|
}
|
|
51810
52240
|
|
|
@@ -51823,7 +52253,7 @@ function safeDefaultBlockers(item) {
|
|
|
51823
52253
|
}
|
|
51824
52254
|
return [...blockers].sort();
|
|
51825
52255
|
}
|
|
51826
|
-
function isSafeDefaultDecision(item, mode) {
|
|
52256
|
+
function isSafeDefaultDecision(item, mode, delegated) {
|
|
51827
52257
|
const decision = item.default_decision;
|
|
51828
52258
|
if (decision === undefined)
|
|
51829
52259
|
return false;
|
|
@@ -51840,7 +52270,7 @@ function isSafeDefaultDecision(item, mode) {
|
|
|
51840
52270
|
return false;
|
|
51841
52271
|
if (decision.user_confirmation?.required === true)
|
|
51842
52272
|
return false;
|
|
51843
|
-
if (item.source_support?.verdict !== "supported")
|
|
52273
|
+
if (item.source_support?.verdict !== "supported" && !(delegated && isDelegatedWeakDefault(item)))
|
|
51844
52274
|
return false;
|
|
51845
52275
|
if (decision.target?.section_id !== undefined)
|
|
51846
52276
|
return false;
|
|
@@ -51850,14 +52280,15 @@ function isSafeDefaultDecision(item, mode) {
|
|
|
51850
52280
|
return false;
|
|
51851
52281
|
return true;
|
|
51852
52282
|
}
|
|
51853
|
-
function safeDefaultDecisionDocument(context) {
|
|
52283
|
+
function safeDefaultDecisionDocument(context, options = {}) {
|
|
52284
|
+
const delegated = options.delegated === true;
|
|
51854
52285
|
return {
|
|
51855
52286
|
schema_version: "1.0",
|
|
51856
52287
|
mode: context.mode,
|
|
51857
|
-
decisions: context.items.filter((item) => isSafeDefaultDecision(item, context.mode)).map((item) => ({
|
|
52288
|
+
decisions: context.items.filter((item) => isSafeDefaultDecision(item, context.mode, delegated)).map((item) => ({
|
|
51858
52289
|
...item.default_decision,
|
|
51859
52290
|
item_id: item.item_id,
|
|
51860
|
-
decided_by: item.default_decision.decided_by === "cli_reviewed_no_write" ? "cli_reviewed_no_write" : "cli_safe_default"
|
|
52291
|
+
decided_by: item.default_decision.decided_by === "cli_reviewed_no_write" ? "cli_reviewed_no_write" : delegated && isDelegatedWeakDefault(item) ? DELEGATED_DECIDED_BY : "cli_safe_default"
|
|
51861
52292
|
}))
|
|
51862
52293
|
};
|
|
51863
52294
|
}
|
|
@@ -51865,12 +52296,8 @@ function safeDefaultDecisionDocument(context) {
|
|
|
51865
52296
|
// src/reconcile/apply.ts
|
|
51866
52297
|
init_verify();
|
|
51867
52298
|
init_shared();
|
|
51868
|
-
init_node2();
|
|
51869
52299
|
init_section();
|
|
51870
52300
|
init_sources();
|
|
51871
|
-
init_knowledge();
|
|
51872
|
-
init_compileContext();
|
|
51873
|
-
init_compileNode();
|
|
51874
52301
|
init_coverage();
|
|
51875
52302
|
init_evidence();
|
|
51876
52303
|
init_ledger();
|
|
@@ -51878,9 +52305,19 @@ import { existsSync as existsSync46 } from "node:fs";
|
|
|
51878
52305
|
import { cp as cp3, mkdir as mkdir25, mkdtemp as mkdtemp2, rm as rm14 } from "node:fs/promises";
|
|
51879
52306
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
51880
52307
|
import { dirname as dirname22, join as join55 } from "node:path";
|
|
51881
|
-
|
|
52308
|
+
|
|
52309
|
+
// src/reconcile/applyPreflight.ts
|
|
52310
|
+
init_sources();
|
|
52311
|
+
init_shared();
|
|
52312
|
+
init_compileContext();
|
|
52313
|
+
|
|
52314
|
+
// src/reconcile/applyOps.ts
|
|
52315
|
+
init_node2();
|
|
52316
|
+
init_shared();
|
|
52317
|
+
init_knowledge();
|
|
52318
|
+
init_compileNode();
|
|
52319
|
+
init_compileContext();
|
|
51882
52320
|
init_locatedNodeSources();
|
|
51883
|
-
init_types3();
|
|
51884
52321
|
function requireTarget(decision) {
|
|
51885
52322
|
if (!decision.target?.node || !decision.target.section_id) {
|
|
51886
52323
|
throw new Error(`${decision.action} requires target.node and target.section_id`);
|
|
@@ -51898,7 +52335,9 @@ function sectionInput(proposed) {
|
|
|
51898
52335
|
}
|
|
51899
52336
|
return {
|
|
51900
52337
|
kind: proposed.kind,
|
|
52338
|
+
...typeof proposed.summary === "string" ? { summary: proposed.summary } : {},
|
|
51901
52339
|
content: proposed.content,
|
|
52340
|
+
...typeof proposed.raw === "string" ? { raw: proposed.raw } : {},
|
|
51902
52341
|
source_ref: proposed.source_ref,
|
|
51903
52342
|
...typeof proposed.detail === "string" ? { detail: proposed.detail } : {},
|
|
51904
52343
|
...typeof proposed.confidence === "string" ? { confidence: proposed.confidence } : {},
|
|
@@ -51909,8 +52348,12 @@ function updatePatch(proposed) {
|
|
|
51909
52348
|
if (!proposed)
|
|
51910
52349
|
throw new Error("merge_update requires proposed payload");
|
|
51911
52350
|
const patch = {};
|
|
52351
|
+
if (proposed.summary !== undefined)
|
|
52352
|
+
patch.summary = proposed.summary;
|
|
51912
52353
|
if (proposed.content !== undefined)
|
|
51913
52354
|
patch.content = proposed.content;
|
|
52355
|
+
if (proposed.raw !== undefined)
|
|
52356
|
+
patch.raw = proposed.raw;
|
|
51914
52357
|
if (proposed.detail !== undefined)
|
|
51915
52358
|
patch.detail = proposed.detail;
|
|
51916
52359
|
if (proposed.confidence !== undefined)
|
|
@@ -51921,98 +52364,6 @@ function updatePatch(proposed) {
|
|
|
51921
52364
|
patch.refers_to_nodes = proposed.refers_to_nodes;
|
|
51922
52365
|
return patch;
|
|
51923
52366
|
}
|
|
51924
|
-
function assertMergeUpdatePersisted(input) {
|
|
51925
|
-
const mismatches = [];
|
|
51926
|
-
if (input.patch.content !== undefined && input.section.content !== input.patch.content) {
|
|
51927
|
-
mismatches.push("content");
|
|
51928
|
-
}
|
|
51929
|
-
if (input.patch.source_ref !== undefined && input.section.source_ref !== input.patch.source_ref) {
|
|
51930
|
-
mismatches.push("source_ref");
|
|
51931
|
-
}
|
|
51932
|
-
if (input.patch.detail !== undefined) {
|
|
51933
|
-
const expected = input.patch.detail === null ? undefined : input.patch.detail;
|
|
51934
|
-
if (input.section.detail !== expected)
|
|
51935
|
-
mismatches.push("detail");
|
|
51936
|
-
}
|
|
51937
|
-
if (input.patch.confidence !== undefined && input.section.confidence !== input.patch.confidence) {
|
|
51938
|
-
mismatches.push("confidence");
|
|
51939
|
-
}
|
|
51940
|
-
if (mismatches.length > 0) {
|
|
51941
|
-
throw new Error(`merge_update did not persist ${mismatches.join(", ")} for ${input.target.node}#${input.target.section_id}`);
|
|
51942
|
-
}
|
|
51943
|
-
}
|
|
51944
|
-
function rejectUnresolved(document2) {
|
|
51945
|
-
const unresolved = document2.decisions.filter((decision) => decision.action === "ask_user" || decision.user_confirmation?.required === true);
|
|
51946
|
-
if (unresolved.length > 0) {
|
|
51947
|
-
throw new Error(`cannot apply unresolved ask_user decisions: ${unresolved.map((decision) => decision.item_id).join(", ")}`);
|
|
51948
|
-
}
|
|
51949
|
-
}
|
|
51950
|
-
function countResolvedQuestions(document2) {
|
|
51951
|
-
return document2.decisions.filter((decision) => decision.decided_by === "user").length;
|
|
51952
|
-
}
|
|
51953
|
-
async function propagateOmitCoverageSkips(input) {
|
|
51954
|
-
for (const decision of input.document.decisions) {
|
|
51955
|
-
if (decision.action !== "omit")
|
|
51956
|
-
continue;
|
|
51957
|
-
const sourceRef = decision.proposed?.source_ref;
|
|
51958
|
-
if (typeof sourceRef !== "string" || sourceRef.length === 0)
|
|
51959
|
-
continue;
|
|
51960
|
-
await skipCoverageCandidatesBySourceRefs({
|
|
51961
|
-
ctxDir: input.ctxDir,
|
|
51962
|
-
...decision.target?.node !== undefined ? { nodeSlug: decision.target.node } : {},
|
|
51963
|
-
sourceRefs: [sourceRef],
|
|
51964
|
-
reason: `propagated from semantic omit decision ${decision.item_id}`,
|
|
51965
|
-
...input.now !== undefined ? { now: input.now } : {}
|
|
51966
|
-
});
|
|
51967
|
-
}
|
|
51968
|
-
}
|
|
51969
|
-
async function createApplyRollbackSnapshot(ctxDir) {
|
|
51970
|
-
const tmpDir = await mkdtemp2(join55(tmpdir2(), "c4a-reconcile-apply-"));
|
|
51971
|
-
const knowledgePath2 = join55(ctxDir, "knowledge");
|
|
51972
|
-
const ledgerPath = semanticLedgerPath2(ctxDir);
|
|
51973
|
-
const knowledgeBackup = join55(tmpDir, "knowledge");
|
|
51974
|
-
const ledgerBackup = join55(tmpDir, "semantic.yaml");
|
|
51975
|
-
const knowledgeExisted = existsSync46(knowledgePath2);
|
|
51976
|
-
const ledgerExisted = existsSync46(ledgerPath);
|
|
51977
|
-
if (knowledgeExisted)
|
|
51978
|
-
await cp3(knowledgePath2, knowledgeBackup, { recursive: true });
|
|
51979
|
-
if (ledgerExisted)
|
|
51980
|
-
await cp3(ledgerPath, ledgerBackup);
|
|
51981
|
-
return { ctxDir, tmpDir, knowledgeExisted, ledgerExisted, knowledgeBackup, ledgerBackup };
|
|
51982
|
-
}
|
|
51983
|
-
async function restoreApplyRollbackSnapshot(snapshot) {
|
|
51984
|
-
const knowledgePath2 = join55(snapshot.ctxDir, "knowledge");
|
|
51985
|
-
if (snapshot.knowledgeExisted) {
|
|
51986
|
-
await rm14(knowledgePath2, { recursive: true, force: true });
|
|
51987
|
-
await cp3(snapshot.knowledgeBackup, knowledgePath2, { recursive: true });
|
|
51988
|
-
} else {
|
|
51989
|
-
await rm14(knowledgePath2, { recursive: true, force: true });
|
|
51990
|
-
}
|
|
51991
|
-
const ledgerPath = semanticLedgerPath2(snapshot.ctxDir);
|
|
51992
|
-
if (snapshot.ledgerExisted) {
|
|
51993
|
-
await mkdir25(dirname22(ledgerPath), { recursive: true });
|
|
51994
|
-
await cp3(snapshot.ledgerBackup, ledgerPath);
|
|
51995
|
-
} else {
|
|
51996
|
-
await rm14(ledgerPath, { force: true });
|
|
51997
|
-
}
|
|
51998
|
-
}
|
|
51999
|
-
async function discardApplyRollbackSnapshot(snapshot) {
|
|
52000
|
-
await rm14(snapshot.tmpDir, { recursive: true, force: true });
|
|
52001
|
-
}
|
|
52002
|
-
function errorMessage(err2) {
|
|
52003
|
-
return err2 instanceof Error ? err2.message : String(err2);
|
|
52004
|
-
}
|
|
52005
|
-
function isRecord22(value) {
|
|
52006
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
52007
|
-
}
|
|
52008
|
-
function applyInputDocument(input) {
|
|
52009
|
-
if (!isRecord22(input) || !("apply_document" in input))
|
|
52010
|
-
return input;
|
|
52011
|
-
if (input.ready_to_apply !== true) {
|
|
52012
|
-
throw new Error("cannot apply review output that is not ready_to_apply");
|
|
52013
|
-
}
|
|
52014
|
-
return input.apply_document;
|
|
52015
|
-
}
|
|
52016
52367
|
function findNode(nodes, nodeSlug, action) {
|
|
52017
52368
|
const node2 = nodes.find((candidate) => candidate.parsed.node.id === nodeSlug);
|
|
52018
52369
|
if (!node2)
|
|
@@ -52050,76 +52401,14 @@ function findTargetSection(node2, sectionId, action) {
|
|
|
52050
52401
|
throw new Error(`${action} target section "${node2.parsed.node.id}#${sectionId}" does not exist`);
|
|
52051
52402
|
return section;
|
|
52052
52403
|
}
|
|
52053
|
-
function snapshotSourceRef2(value) {
|
|
52054
|
-
return isRecord22(value) && typeof value.source_ref === "string" ? value.source_ref : undefined;
|
|
52055
|
-
}
|
|
52056
|
-
function evidenceRefsForDecision(input) {
|
|
52057
|
-
const node2 = input.decision.target?.node;
|
|
52058
|
-
if (!node2)
|
|
52059
|
-
return [];
|
|
52060
|
-
if (input.decision.action === "split_then_reanchor") {
|
|
52061
|
-
return (input.decision.proposed?.sections ?? []).map((section) => ({ node: node2, sourceRef: section.source_ref, kind: "proposed" }));
|
|
52062
|
-
}
|
|
52063
|
-
const proposedRef = input.decision.proposed?.source_ref;
|
|
52064
|
-
if (typeof proposedRef === "string")
|
|
52065
|
-
return [{ node: node2, sourceRef: proposedRef, kind: "proposed" }];
|
|
52066
|
-
const targetRef = snapshotSourceRef2(input.targetAfter) ?? snapshotSourceRef2(input.targetBefore);
|
|
52067
|
-
return targetRef ? [{
|
|
52068
|
-
node: node2,
|
|
52069
|
-
sourceRef: targetRef,
|
|
52070
|
-
...input.decision.target?.section_id !== undefined ? { sectionId: input.decision.target.section_id } : {},
|
|
52071
|
-
kind: "target"
|
|
52072
|
-
}] : [];
|
|
52073
|
-
}
|
|
52074
|
-
async function collectEvidenceByItem(input) {
|
|
52075
|
-
const nodes = flattenWorkspaceNodes(await readWorkspaceNodeFiles(input.ctxDir));
|
|
52076
|
-
const sources = await loadSources(input.ctxDir);
|
|
52077
|
-
const sourceById = new Map(sources.sources.map((source2) => [source2.id, source2]));
|
|
52078
|
-
const out2 = new Map;
|
|
52079
|
-
for (const decision of input.document.decisions) {
|
|
52080
|
-
const refs = evidenceRefsForDecision({
|
|
52081
|
-
decision,
|
|
52082
|
-
targetBefore: input.targetBeforeByItem.get(decision.item_id),
|
|
52083
|
-
targetAfter: input.targetAfterByItem.get(decision.item_id)
|
|
52084
|
-
});
|
|
52085
|
-
const spans = [];
|
|
52086
|
-
for (const ref of refs) {
|
|
52087
|
-
const node2 = decision.action === "omit" ? await findNodeOrCompileTarget(input.ctxDir, nodes, ref.node, decision.action) : findNode(nodes, ref.node, decision.action);
|
|
52088
|
-
if (ref.kind === "target" && ref.sectionId !== undefined) {
|
|
52089
|
-
spans.push(...await baselineEvidenceSpansForTargetSection({
|
|
52090
|
-
ctxDir: input.ctxDir,
|
|
52091
|
-
nodeSlug: ref.node,
|
|
52092
|
-
sectionId: ref.sectionId,
|
|
52093
|
-
nodeSources: node2.parsed.node.sources,
|
|
52094
|
-
sourceRef: ref.sourceRef,
|
|
52095
|
-
sourceById,
|
|
52096
|
-
action: decision.action
|
|
52097
|
-
}));
|
|
52098
|
-
} else {
|
|
52099
|
-
const nodeSources = sourceRefNodeSources({
|
|
52100
|
-
sources: node2.parsed.node.sources,
|
|
52101
|
-
contextSources: node2.parsed.node.context_sources,
|
|
52102
|
-
includeContextSources: decision.action === "omit"
|
|
52103
|
-
});
|
|
52104
|
-
spans.push(...await evidenceSpansForNodeSourceRef({
|
|
52105
|
-
ctxDir: input.ctxDir,
|
|
52106
|
-
nodeSources,
|
|
52107
|
-
sourceRef: ref.sourceRef,
|
|
52108
|
-
sourceById,
|
|
52109
|
-
action: decision.action
|
|
52110
|
-
}));
|
|
52111
|
-
}
|
|
52112
|
-
}
|
|
52113
|
-
out2.set(decision.item_id, spans);
|
|
52114
|
-
}
|
|
52115
|
-
return out2;
|
|
52116
|
-
}
|
|
52117
52404
|
function sectionFromProposed(input) {
|
|
52118
52405
|
return {
|
|
52119
52406
|
id: input.sectionId,
|
|
52120
52407
|
anchor_slug: input.node.parsed.node.id,
|
|
52121
52408
|
kind: input.proposed.kind,
|
|
52409
|
+
...typeof input.proposed.summary === "string" ? { summary: input.proposed.summary } : {},
|
|
52122
52410
|
content: input.proposed.content,
|
|
52411
|
+
...typeof input.proposed.raw === "string" ? { raw: input.proposed.raw } : {},
|
|
52123
52412
|
source_ref: input.proposed.source_ref,
|
|
52124
52413
|
status: input.proposed.status ?? SectionStatus.active,
|
|
52125
52414
|
confidence: input.proposed.confidence ?? "confirmed",
|
|
@@ -52129,8 +52418,20 @@ function sectionFromProposed(input) {
|
|
|
52129
52418
|
}
|
|
52130
52419
|
function finalSectionFromPatch(section, patch) {
|
|
52131
52420
|
const next = { ...section };
|
|
52421
|
+
if (patch.summary !== undefined) {
|
|
52422
|
+
if (patch.summary === null)
|
|
52423
|
+
delete next.summary;
|
|
52424
|
+
else
|
|
52425
|
+
next.summary = patch.summary;
|
|
52426
|
+
}
|
|
52132
52427
|
if (patch.content !== undefined)
|
|
52133
52428
|
next.content = patch.content;
|
|
52429
|
+
if (patch.raw !== undefined) {
|
|
52430
|
+
if (patch.raw === null)
|
|
52431
|
+
delete next.raw;
|
|
52432
|
+
else
|
|
52433
|
+
next.raw = patch.raw;
|
|
52434
|
+
}
|
|
52134
52435
|
if (patch.detail !== undefined) {
|
|
52135
52436
|
if (patch.detail === null)
|
|
52136
52437
|
delete next.detail;
|
|
@@ -52151,6 +52452,33 @@ function finalSectionFromPatch(section, patch) {
|
|
|
52151
52452
|
}
|
|
52152
52453
|
return next;
|
|
52153
52454
|
}
|
|
52455
|
+
async function ensureKeepSeparateTargetNode(ctxDir, nodeSlug) {
|
|
52456
|
+
const exists = flattenWorkspaceNodes(await readWorkspaceNodeFiles(ctxDir)).some((candidate) => candidate.parsed.node.id === nodeSlug);
|
|
52457
|
+
if (exists)
|
|
52458
|
+
return;
|
|
52459
|
+
await ensureCompileNodeExists(ctxDir, await nodeGetContext(ctxDir, nodeSlug));
|
|
52460
|
+
}
|
|
52461
|
+
async function ensureNoWriteTargetNode(ctxDir, nodeSlug) {
|
|
52462
|
+
const exists = flattenWorkspaceNodes(await readWorkspaceNodeFiles(ctxDir)).some((candidate) => candidate.parsed.node.id === nodeSlug);
|
|
52463
|
+
if (exists)
|
|
52464
|
+
return;
|
|
52465
|
+
await ensureCompileNoWriteNodeExists(ctxDir, await nodeGetContext(ctxDir, nodeSlug));
|
|
52466
|
+
}
|
|
52467
|
+
function validateSectionForApply(input) {
|
|
52468
|
+
validateMountAndShape(input.node, input.section, input.action);
|
|
52469
|
+
validateRefersToNodes(input.section, input.knownSlugs, input.action);
|
|
52470
|
+
}
|
|
52471
|
+
|
|
52472
|
+
// src/reconcile/applyPreflight.ts
|
|
52473
|
+
init_sourceSupport();
|
|
52474
|
+
async function collectApplyKnownSlugs(ctxDir, nodes) {
|
|
52475
|
+
const slugs = new Set(nodes.map((node2) => node2.parsed.node.id));
|
|
52476
|
+
try {
|
|
52477
|
+
for (const slug of await collectKnownNodeSlugs(ctxDir))
|
|
52478
|
+
slugs.add(slug);
|
|
52479
|
+
} catch {}
|
|
52480
|
+
return slugs;
|
|
52481
|
+
}
|
|
52154
52482
|
async function preflightSemanticDecisions(input) {
|
|
52155
52483
|
const nodes = flattenWorkspaceNodes(await readWorkspaceNodeFiles(input.ctxDir));
|
|
52156
52484
|
const knownSlugs = await collectApplyKnownSlugs(input.ctxDir, nodes);
|
|
@@ -52170,8 +52498,7 @@ async function preflightSemanticDecisions(input) {
|
|
|
52170
52498
|
throw new Error("merge_update proposed.kind must match the target section kind; use supersede for kind changes");
|
|
52171
52499
|
}
|
|
52172
52500
|
const finalSection = finalSectionFromPatch(current, updatePatch(decision.proposed));
|
|
52173
|
-
|
|
52174
|
-
validateRefersToNodes(finalSection, knownSlugs, decision.action);
|
|
52501
|
+
validateSectionForApply({ node: node2, section: finalSection, knownSlugs, action: decision.action });
|
|
52175
52502
|
await validateSectionSourceSupport({ ctxDir: input.ctxDir, nodeSources: node2.parsed.node.sources, section: finalSection, sourceById, action: decision.action, strict: true });
|
|
52176
52503
|
continue;
|
|
52177
52504
|
}
|
|
@@ -52180,23 +52507,24 @@ async function preflightSemanticDecisions(input) {
|
|
|
52180
52507
|
const node2 = await findNodeWithCurrentSources(input.ctxDir, nodes, target.node, decision.action);
|
|
52181
52508
|
findTargetSection(node2, target.section_id, decision.action);
|
|
52182
52509
|
const section = sectionFromProposed({ node: node2, sectionId: "section-1", proposed: sectionInput(decision.proposed) });
|
|
52183
|
-
|
|
52184
|
-
validateRefersToNodes(section, knownSlugs, decision.action);
|
|
52510
|
+
validateSectionForApply({ node: node2, section, knownSlugs, action: decision.action });
|
|
52185
52511
|
await validateSectionSourceSupport({ ctxDir: input.ctxDir, nodeSources: node2.parsed.node.sources, section, sourceById, action: decision.action, strict: true });
|
|
52186
52512
|
continue;
|
|
52187
52513
|
}
|
|
52188
52514
|
if (decision.action === "keep_separate") {
|
|
52189
52515
|
const node2 = await findNodeOrCompileTarget(input.ctxDir, nodes, requireNode(decision), decision.action);
|
|
52190
52516
|
const section = sectionFromProposed({ node: node2, sectionId: "section-1", proposed: sectionInput(decision.proposed) });
|
|
52191
|
-
|
|
52192
|
-
validateRefersToNodes(section, knownSlugs, decision.action);
|
|
52517
|
+
validateSectionForApply({ node: node2, section, knownSlugs, action: decision.action });
|
|
52193
52518
|
await validateSectionSourceSupport({
|
|
52194
52519
|
ctxDir: input.ctxDir,
|
|
52195
52520
|
nodeSources: node2.parsed.node.sources,
|
|
52196
52521
|
section,
|
|
52197
52522
|
sourceById,
|
|
52198
52523
|
action: decision.action,
|
|
52199
|
-
allowWeak:
|
|
52524
|
+
allowWeak: allowsWeakSourceSupport({
|
|
52525
|
+
decision,
|
|
52526
|
+
allowDelegatedDecisions: input.allowDelegatedDecisions
|
|
52527
|
+
})
|
|
52200
52528
|
});
|
|
52201
52529
|
continue;
|
|
52202
52530
|
}
|
|
@@ -52211,14 +52539,12 @@ async function preflightSemanticDecisions(input) {
|
|
|
52211
52539
|
const target = requireTarget(decision);
|
|
52212
52540
|
const node2 = await findNodeWithCurrentSources(input.ctxDir, nodes, target.node, decision.action);
|
|
52213
52541
|
const current = findTargetSection(node2, target.section_id, decision.action);
|
|
52214
|
-
const reanchorPatch = {
|
|
52215
|
-
|
|
52216
|
-
|
|
52217
|
-
|
|
52218
|
-
reanchorPatch.confidence = decision.proposed.confidence;
|
|
52542
|
+
const reanchorPatch = {
|
|
52543
|
+
...decision.proposed?.source_ref !== undefined ? { source_ref: decision.proposed.source_ref } : {},
|
|
52544
|
+
...decision.proposed?.confidence !== undefined ? { confidence: decision.proposed.confidence } : {}
|
|
52545
|
+
};
|
|
52219
52546
|
const finalSection = finalSectionFromPatch(current, reanchorPatch);
|
|
52220
|
-
|
|
52221
|
-
validateRefersToNodes(finalSection, knownSlugs, decision.action);
|
|
52547
|
+
validateSectionForApply({ node: node2, section: finalSection, knownSlugs, action: decision.action });
|
|
52222
52548
|
await validateSectionSourceSupport({ ctxDir: input.ctxDir, nodeSources: node2.parsed.node.sources, section: finalSection, sourceById, action: decision.action, strict: true });
|
|
52223
52549
|
continue;
|
|
52224
52550
|
}
|
|
@@ -52235,26 +52561,170 @@ async function preflightSemanticDecisions(input) {
|
|
|
52235
52561
|
throw new Error("split_then_reanchor requires proposed.sections");
|
|
52236
52562
|
for (const [index, proposed] of decision.proposed.sections.entries()) {
|
|
52237
52563
|
const section = sectionFromProposed({ node: node2, sectionId: `section-${index + 1}`, proposed });
|
|
52238
|
-
|
|
52239
|
-
validateRefersToNodes(section, knownSlugs, decision.action);
|
|
52564
|
+
validateSectionForApply({ node: node2, section, knownSlugs, action: decision.action });
|
|
52240
52565
|
await validateSectionSourceSupport({ ctxDir: input.ctxDir, nodeSources: node2.parsed.node.sources, section, sourceById, action: decision.action, strict: true });
|
|
52241
52566
|
}
|
|
52242
52567
|
}
|
|
52243
52568
|
}
|
|
52244
52569
|
}
|
|
52245
|
-
|
|
52246
|
-
|
|
52247
|
-
|
|
52248
|
-
|
|
52249
|
-
|
|
52250
|
-
|
|
52251
|
-
|
|
52570
|
+
|
|
52571
|
+
// src/reconcile/apply.ts
|
|
52572
|
+
init_types3();
|
|
52573
|
+
function assertMergeUpdatePersisted(input) {
|
|
52574
|
+
const mismatches = [];
|
|
52575
|
+
if (input.patch.content !== undefined && input.section.content !== input.patch.content) {
|
|
52576
|
+
mismatches.push("content");
|
|
52577
|
+
}
|
|
52578
|
+
if (input.patch.source_ref !== undefined && input.section.source_ref !== input.patch.source_ref) {
|
|
52579
|
+
mismatches.push("source_ref");
|
|
52580
|
+
}
|
|
52581
|
+
if (input.patch.detail !== undefined) {
|
|
52582
|
+
const expected = input.patch.detail === null ? undefined : input.patch.detail;
|
|
52583
|
+
if (input.section.detail !== expected)
|
|
52584
|
+
mismatches.push("detail");
|
|
52585
|
+
}
|
|
52586
|
+
if (input.patch.confidence !== undefined && input.section.confidence !== input.patch.confidence) {
|
|
52587
|
+
mismatches.push("confidence");
|
|
52588
|
+
}
|
|
52589
|
+
if (mismatches.length > 0) {
|
|
52590
|
+
throw new Error(`merge_update did not persist ${mismatches.join(", ")} for ${input.target.node}#${input.target.section_id}`);
|
|
52591
|
+
}
|
|
52252
52592
|
}
|
|
52253
|
-
|
|
52254
|
-
const
|
|
52255
|
-
if (
|
|
52256
|
-
|
|
52257
|
-
|
|
52593
|
+
function rejectUnresolved(document2) {
|
|
52594
|
+
const unresolved = document2.decisions.filter((decision) => decision.action === "ask_user" || decision.user_confirmation?.required === true);
|
|
52595
|
+
if (unresolved.length > 0) {
|
|
52596
|
+
throw new Error(`cannot apply unresolved ask_user decisions: ${unresolved.map((decision) => decision.item_id).join(", ")}`);
|
|
52597
|
+
}
|
|
52598
|
+
}
|
|
52599
|
+
function countResolvedQuestions(document2) {
|
|
52600
|
+
return document2.decisions.filter((decision) => decision.decided_by === "user").length;
|
|
52601
|
+
}
|
|
52602
|
+
async function propagateOmitCoverageSkips(input) {
|
|
52603
|
+
for (const decision of input.document.decisions) {
|
|
52604
|
+
if (decision.action !== "omit")
|
|
52605
|
+
continue;
|
|
52606
|
+
const sourceRef = decision.proposed?.source_ref;
|
|
52607
|
+
if (typeof sourceRef !== "string" || sourceRef.length === 0)
|
|
52608
|
+
continue;
|
|
52609
|
+
await skipCoverageCandidatesBySourceRefs({
|
|
52610
|
+
ctxDir: input.ctxDir,
|
|
52611
|
+
...decision.target?.node !== undefined ? { nodeSlug: decision.target.node } : {},
|
|
52612
|
+
sourceRefs: [sourceRef],
|
|
52613
|
+
reason: `propagated from semantic omit decision ${decision.item_id}`,
|
|
52614
|
+
...input.now !== undefined ? { now: input.now } : {}
|
|
52615
|
+
});
|
|
52616
|
+
}
|
|
52617
|
+
}
|
|
52618
|
+
async function createApplyRollbackSnapshot(ctxDir) {
|
|
52619
|
+
const tmpDir = await mkdtemp2(join55(tmpdir2(), "c4a-reconcile-apply-"));
|
|
52620
|
+
const knowledgePath2 = join55(ctxDir, "knowledge");
|
|
52621
|
+
const ledgerPath = semanticLedgerPath2(ctxDir);
|
|
52622
|
+
const knowledgeBackup = join55(tmpDir, "knowledge");
|
|
52623
|
+
const ledgerBackup = join55(tmpDir, "semantic.yaml");
|
|
52624
|
+
const knowledgeExisted = existsSync46(knowledgePath2);
|
|
52625
|
+
const ledgerExisted = existsSync46(ledgerPath);
|
|
52626
|
+
if (knowledgeExisted)
|
|
52627
|
+
await cp3(knowledgePath2, knowledgeBackup, { recursive: true });
|
|
52628
|
+
if (ledgerExisted)
|
|
52629
|
+
await cp3(ledgerPath, ledgerBackup);
|
|
52630
|
+
return { ctxDir, tmpDir, knowledgeExisted, ledgerExisted, knowledgeBackup, ledgerBackup };
|
|
52631
|
+
}
|
|
52632
|
+
async function restoreApplyRollbackSnapshot(snapshot) {
|
|
52633
|
+
const knowledgePath2 = join55(snapshot.ctxDir, "knowledge");
|
|
52634
|
+
if (snapshot.knowledgeExisted) {
|
|
52635
|
+
await rm14(knowledgePath2, { recursive: true, force: true });
|
|
52636
|
+
await cp3(snapshot.knowledgeBackup, knowledgePath2, { recursive: true });
|
|
52637
|
+
} else {
|
|
52638
|
+
await rm14(knowledgePath2, { recursive: true, force: true });
|
|
52639
|
+
}
|
|
52640
|
+
const ledgerPath = semanticLedgerPath2(snapshot.ctxDir);
|
|
52641
|
+
if (snapshot.ledgerExisted) {
|
|
52642
|
+
await mkdir25(dirname22(ledgerPath), { recursive: true });
|
|
52643
|
+
await cp3(snapshot.ledgerBackup, ledgerPath);
|
|
52644
|
+
} else {
|
|
52645
|
+
await rm14(ledgerPath, { force: true });
|
|
52646
|
+
}
|
|
52647
|
+
}
|
|
52648
|
+
async function discardApplyRollbackSnapshot(snapshot) {
|
|
52649
|
+
await rm14(snapshot.tmpDir, { recursive: true, force: true });
|
|
52650
|
+
}
|
|
52651
|
+
function errorMessage(err2) {
|
|
52652
|
+
return err2 instanceof Error ? err2.message : String(err2);
|
|
52653
|
+
}
|
|
52654
|
+
function isRecord22(value) {
|
|
52655
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
52656
|
+
}
|
|
52657
|
+
function applyInputDocument(input) {
|
|
52658
|
+
if (!isRecord22(input) || !("apply_document" in input))
|
|
52659
|
+
return input;
|
|
52660
|
+
if (input.ready_to_apply !== true) {
|
|
52661
|
+
throw new Error("cannot apply review output that is not ready_to_apply");
|
|
52662
|
+
}
|
|
52663
|
+
return input.apply_document;
|
|
52664
|
+
}
|
|
52665
|
+
function snapshotSourceRef2(value) {
|
|
52666
|
+
return isRecord22(value) && typeof value.source_ref === "string" ? value.source_ref : undefined;
|
|
52667
|
+
}
|
|
52668
|
+
function evidenceRefsForDecision(input) {
|
|
52669
|
+
const node2 = input.decision.target?.node;
|
|
52670
|
+
if (!node2)
|
|
52671
|
+
return [];
|
|
52672
|
+
if (input.decision.action === "split_then_reanchor") {
|
|
52673
|
+
return (input.decision.proposed?.sections ?? []).map((section) => ({ node: node2, sourceRef: section.source_ref, kind: "proposed" }));
|
|
52674
|
+
}
|
|
52675
|
+
const proposedRef = input.decision.proposed?.source_ref;
|
|
52676
|
+
if (typeof proposedRef === "string")
|
|
52677
|
+
return [{ node: node2, sourceRef: proposedRef, kind: "proposed" }];
|
|
52678
|
+
const targetRef = snapshotSourceRef2(input.targetAfter) ?? snapshotSourceRef2(input.targetBefore);
|
|
52679
|
+
return targetRef ? [{
|
|
52680
|
+
node: node2,
|
|
52681
|
+
sourceRef: targetRef,
|
|
52682
|
+
...input.decision.target?.section_id !== undefined ? { sectionId: input.decision.target.section_id } : {},
|
|
52683
|
+
kind: "target"
|
|
52684
|
+
}] : [];
|
|
52685
|
+
}
|
|
52686
|
+
async function collectEvidenceByItem(input) {
|
|
52687
|
+
const nodes = flattenWorkspaceNodes(await readWorkspaceNodeFiles(input.ctxDir));
|
|
52688
|
+
const sources = await loadSources(input.ctxDir);
|
|
52689
|
+
const sourceById = new Map(sources.sources.map((source2) => [source2.id, source2]));
|
|
52690
|
+
const out2 = new Map;
|
|
52691
|
+
for (const decision of input.document.decisions) {
|
|
52692
|
+
const refs = evidenceRefsForDecision({
|
|
52693
|
+
decision,
|
|
52694
|
+
targetBefore: input.targetBeforeByItem.get(decision.item_id),
|
|
52695
|
+
targetAfter: input.targetAfterByItem.get(decision.item_id)
|
|
52696
|
+
});
|
|
52697
|
+
const spans = [];
|
|
52698
|
+
for (const ref of refs) {
|
|
52699
|
+
const node2 = decision.action === "omit" ? await findNodeOrCompileTarget(input.ctxDir, nodes, ref.node, decision.action) : findNode(nodes, ref.node, decision.action);
|
|
52700
|
+
if (ref.kind === "target" && ref.sectionId !== undefined) {
|
|
52701
|
+
spans.push(...await baselineEvidenceSpansForTargetSection({
|
|
52702
|
+
ctxDir: input.ctxDir,
|
|
52703
|
+
nodeSlug: ref.node,
|
|
52704
|
+
sectionId: ref.sectionId,
|
|
52705
|
+
nodeSources: node2.parsed.node.sources,
|
|
52706
|
+
sourceRef: ref.sourceRef,
|
|
52707
|
+
sourceById,
|
|
52708
|
+
action: decision.action
|
|
52709
|
+
}));
|
|
52710
|
+
} else {
|
|
52711
|
+
const nodeSources = sourceRefNodeSources({
|
|
52712
|
+
sources: node2.parsed.node.sources,
|
|
52713
|
+
contextSources: node2.parsed.node.context_sources,
|
|
52714
|
+
includeContextSources: decision.action === "omit"
|
|
52715
|
+
});
|
|
52716
|
+
spans.push(...await evidenceSpansForNodeSourceRef({
|
|
52717
|
+
ctxDir: input.ctxDir,
|
|
52718
|
+
nodeSources,
|
|
52719
|
+
sourceRef: ref.sourceRef,
|
|
52720
|
+
sourceById,
|
|
52721
|
+
action: decision.action
|
|
52722
|
+
}));
|
|
52723
|
+
}
|
|
52724
|
+
}
|
|
52725
|
+
out2.set(decision.item_id, spans);
|
|
52726
|
+
}
|
|
52727
|
+
return out2;
|
|
52258
52728
|
}
|
|
52259
52729
|
async function assertSemanticLedgerAppendable(ctxDir) {
|
|
52260
52730
|
const ledger = await readSemanticLedger(ctxDir);
|
|
@@ -52358,10 +52828,15 @@ async function applySplitThenReanchorPrimitive(input) {
|
|
|
52358
52828
|
async function applySemanticDecisions(input) {
|
|
52359
52829
|
const document2 = parseSemanticDecisionDocument(applyInputDocument(input.document));
|
|
52360
52830
|
rejectUnresolved(document2);
|
|
52831
|
+
assertDelegatedDecisionsAllowed({ decisions: document2.decisions, allowDelegatedDecisions: input.allowDelegatedDecisions });
|
|
52361
52832
|
if (input.verify === false && input.recordLedger !== false) {
|
|
52362
52833
|
throw new Error("semantic ledger cannot be recorded when verify is disabled");
|
|
52363
52834
|
}
|
|
52364
|
-
await preflightSemanticDecisions({
|
|
52835
|
+
await preflightSemanticDecisions({
|
|
52836
|
+
ctxDir: input.ctxDir,
|
|
52837
|
+
document: document2,
|
|
52838
|
+
allowDelegatedDecisions: input.allowDelegatedDecisions
|
|
52839
|
+
});
|
|
52365
52840
|
if (input.recordLedger !== false) {
|
|
52366
52841
|
await assertSemanticLedgerAppendable(input.ctxDir);
|
|
52367
52842
|
}
|
|
@@ -52438,6 +52913,9 @@ async function applySemanticDecisions(input) {
|
|
|
52438
52913
|
continue;
|
|
52439
52914
|
}
|
|
52440
52915
|
if (decision.action === "omit") {
|
|
52916
|
+
if (decision.decided_by === "cli_reviewed_no_write" && decision.target?.node !== undefined) {
|
|
52917
|
+
await ensureNoWriteTargetNode(input.ctxDir, decision.target.node);
|
|
52918
|
+
}
|
|
52441
52919
|
result.omitted += 1;
|
|
52442
52920
|
continue;
|
|
52443
52921
|
}
|
|
@@ -53296,8 +53774,8 @@ function registerReconcileCommand(program2) {
|
|
|
53296
53774
|
" relation: <exact_duplicate|strong_equivalent|complement|conflicts|unsupported>",
|
|
53297
53775
|
" action: <duplicate_skip|merge_update|keep_separate|ask_user|remove_unsupported>",
|
|
53298
53776
|
" target: { node: <slug>, section_id: <section-id> }",
|
|
53299
|
-
" proposed: { kind: <section-kind>, content: <
|
|
53300
|
-
"For examples/code blocks, keep proposed.content
|
|
53777
|
+
" proposed: { kind: <section-kind>, content: <section text>, summary: <optional short summary>, source_ref: <src-N#anchor Lx-y@hash> }",
|
|
53778
|
+
"For long examples/code blocks, keep fenced code in proposed.content and add proposed.summary when a short reader/query aid is useful.",
|
|
53301
53779
|
"Compile draft cites raw via source_ref/source_refs copied from raw_snippets[].source_ref.",
|
|
53302
53780
|
"Review reads the current prepare workflow payload by default; --prepare-digest is only a stale guard.",
|
|
53303
53781
|
"When several node-scoped prepare payloads exist, pass --scope <node-run-scope> from workflow show/status.",
|
|
@@ -53318,6 +53796,7 @@ function registerReconcileCommand(program2) {
|
|
|
53318
53796
|
throw new Error("reconcile review requires --decisions - unless --accept-safe-defaults is used");
|
|
53319
53797
|
}
|
|
53320
53798
|
const currentForPrepare = await readReadyCurrentWorkflow(ctxDir, "reconcile review");
|
|
53799
|
+
const delegatedWorkflow = isDelegatedWorkflow(currentForPrepare);
|
|
53321
53800
|
const requestedScope = typeof options.scope === "string" ? options.scope : workflowScope(currentForPrepare);
|
|
53322
53801
|
const preparePayload = await readWorkflowPayloadByDigest({
|
|
53323
53802
|
ctxDir,
|
|
@@ -53341,14 +53820,15 @@ function registerReconcileCommand(program2) {
|
|
|
53341
53820
|
if (reviewScope !== undefined)
|
|
53342
53821
|
await assertReconcileWorkflowWritable({ ctxDir, mode: reconcileContext.mode, scope: reviewScope });
|
|
53343
53822
|
const explicitDecisions = decisionsInput === undefined ? undefined : await readStructuredInput(resolveStdinOnlyInput(decisionsInput, "--decisions"));
|
|
53344
|
-
const decisions = options.acceptSafeDefaults === true ? explicitDecisions === undefined ? safeDefaultDecisionDocument(reconcileContext) : mergeSafeDefaultDecisions({
|
|
53345
|
-
safeDefaults: safeDefaultDecisionDocument(reconcileContext),
|
|
53823
|
+
const decisions = options.acceptSafeDefaults === true ? explicitDecisions === undefined ? safeDefaultDecisionDocument(reconcileContext, { delegated: delegatedWorkflow }) : mergeSafeDefaultDecisions({
|
|
53824
|
+
safeDefaults: safeDefaultDecisionDocument(reconcileContext, { delegated: delegatedWorkflow }),
|
|
53346
53825
|
explicit: explicitDecisions
|
|
53347
53826
|
}) : explicitDecisions;
|
|
53348
53827
|
let result = await reviewSemanticDecisionsWithWorkspace({
|
|
53349
53828
|
ctxDir,
|
|
53350
53829
|
context: reconcileContext,
|
|
53351
|
-
decisions
|
|
53830
|
+
decisions,
|
|
53831
|
+
allowDelegatedDecisions: delegatedWorkflow
|
|
53352
53832
|
});
|
|
53353
53833
|
result = { mode: reconcileContext.mode, ...result };
|
|
53354
53834
|
const workflowState = reviewScope === undefined ? undefined : await ensureReconcileWorkflow({
|
|
@@ -53408,6 +53888,7 @@ function registerReconcileCommand(program2) {
|
|
|
53408
53888
|
run: async (ctx) => {
|
|
53409
53889
|
const ctxDir = requireWorkspace2(ctx.ctxDir, "reconcile apply");
|
|
53410
53890
|
const currentArtifact = await readUniqueReadyReviewArtifactForCurrent(ctxDir);
|
|
53891
|
+
const currentWorkflow = await readReadyCurrentWorkflow(ctxDir, "reconcile apply");
|
|
53411
53892
|
const documentInput = currentArtifact.artifact;
|
|
53412
53893
|
const mode = semanticApplyMode(documentInput);
|
|
53413
53894
|
const applyScope = mode !== undefined ? {
|
|
@@ -53418,7 +53899,8 @@ function registerReconcileCommand(program2) {
|
|
|
53418
53899
|
await assertReconcileWorkflowWritable({ ctxDir, mode, scope: applyScope });
|
|
53419
53900
|
const result = await applySemanticDecisions({
|
|
53420
53901
|
ctxDir,
|
|
53421
|
-
document: documentInput
|
|
53902
|
+
document: documentInput,
|
|
53903
|
+
allowDelegatedDecisions: isDelegatedWorkflow(currentWorkflow)
|
|
53422
53904
|
});
|
|
53423
53905
|
if (mode !== undefined && applyScope !== undefined) {
|
|
53424
53906
|
await advanceReconcileWorkflow({
|
|
@@ -54747,6 +55229,7 @@ var DETAIL_OUTPUT_CHARS_PER_TOKEN = 4;
|
|
|
54747
55229
|
var DEFAULT_DETAIL_TOKEN_BUDGET = 1200;
|
|
54748
55230
|
var SUMMARY_PREVIEW_LIMIT = 4;
|
|
54749
55231
|
var WINDOW_PREVIEW_LIMIT = 1;
|
|
55232
|
+
var SOURCE_WINDOW_SELECTOR_RE = /^(src-[1-9]\d*):([1-9]\d*)$/u;
|
|
54750
55233
|
function blockSignalLabels(block, textPreview) {
|
|
54751
55234
|
const haystack = [
|
|
54752
55235
|
typeof textPreview === "string" ? textPreview : "",
|
|
@@ -54826,6 +55309,33 @@ function alignWindowRows(value) {
|
|
|
54826
55309
|
};
|
|
54827
55310
|
}));
|
|
54828
55311
|
}
|
|
55312
|
+
function windowSelectorOptions(windows) {
|
|
55313
|
+
const sourceOrdinals = new Map;
|
|
55314
|
+
return windows.map((window2) => {
|
|
55315
|
+
const ordinal = (sourceOrdinals.get(window2.source_alias) ?? 0) + 1;
|
|
55316
|
+
sourceOrdinals.set(window2.source_alias, ordinal);
|
|
55317
|
+
return {
|
|
55318
|
+
selector: `${window2.source_alias}:${ordinal}`,
|
|
55319
|
+
window_id: window2.window_id,
|
|
55320
|
+
source_alias: window2.source_alias,
|
|
55321
|
+
source_id: window2.source_id,
|
|
55322
|
+
heading_path: window2.heading_path,
|
|
55323
|
+
...window2.block_range !== undefined ? { block_range: window2.block_range } : {},
|
|
55324
|
+
...window2.block_count !== undefined ? { block_count: window2.block_count } : {}
|
|
55325
|
+
};
|
|
55326
|
+
});
|
|
55327
|
+
}
|
|
55328
|
+
function resolveWindowSelector(windows, selector) {
|
|
55329
|
+
const exact = windows.find((window2) => window2.window_id === selector);
|
|
55330
|
+
if (exact !== undefined)
|
|
55331
|
+
return exact;
|
|
55332
|
+
const match = SOURCE_WINDOW_SELECTOR_RE.exec(selector);
|
|
55333
|
+
if (match === null)
|
|
55334
|
+
return;
|
|
55335
|
+
const [, sourceAlias3, rawOrdinal] = match;
|
|
55336
|
+
const ordinal = Number(rawOrdinal);
|
|
55337
|
+
return windows.filter((window2) => window2.source_alias === sourceAlias3)[ordinal - 1];
|
|
55338
|
+
}
|
|
54829
55339
|
function windowSummaryRow(window2) {
|
|
54830
55340
|
const row = { ...window2 };
|
|
54831
55341
|
delete row.block_ids;
|
|
@@ -55033,12 +55543,14 @@ function compactAlignSegmentBlocks(record, value, options) {
|
|
|
55033
55543
|
if (!hasAlignBlockDrilldown(options))
|
|
55034
55544
|
return compactAlignSegmentBlocksSummary(record, value);
|
|
55035
55545
|
const windows = alignWindowRows(value);
|
|
55036
|
-
const selectedWindow = typeof options.windowId === "string" ? windows
|
|
55546
|
+
const selectedWindow = typeof options.windowId === "string" ? resolveWindowSelector(windows, options.windowId) : undefined;
|
|
55037
55547
|
if (typeof options.windowId === "string" && selectedWindow === undefined) {
|
|
55038
55548
|
throw new ContextError(ExitCode.UserError, `workflow blocks window "${options.windowId}" was not found`, {
|
|
55039
55549
|
category: ErrorCategory.UserInputInvalid,
|
|
55040
55550
|
window: options.windowId,
|
|
55041
|
-
|
|
55551
|
+
accepted_window_selectors: ["window_id", "src-N:M"],
|
|
55552
|
+
available_windows: windows.map((window2) => window2.window_id).filter((item) => typeof item === "string"),
|
|
55553
|
+
available_window_selectors: windowSelectorOptions(windows)
|
|
55042
55554
|
});
|
|
55043
55555
|
}
|
|
55044
55556
|
const windowBlockIds = selectedWindow === undefined ? undefined : new Set(selectedWindow.block_ids);
|
|
@@ -55091,7 +55603,9 @@ function compactAlignSegmentBlocks(record, value, options) {
|
|
|
55091
55603
|
};
|
|
55092
55604
|
}
|
|
55093
55605
|
function compactAlignSegmentWindows(value, options) {
|
|
55094
|
-
const
|
|
55606
|
+
const allWindows = alignWindowRows(value);
|
|
55607
|
+
const selectedWindow = typeof options.windowId === "string" ? resolveWindowSelector(allWindows, options.windowId) : undefined;
|
|
55608
|
+
const windows = allWindows.filter((window2) => (options.sourceId === undefined || window2.source_id === options.sourceId) && (options.windowId === undefined || window2.window_id === selectedWindow?.window_id) && headingMatches(window2.heading_path, options.heading));
|
|
55095
55609
|
const detail = options.windowId !== undefined;
|
|
55096
55610
|
const rows = detail ? windows : windows.map(windowSummaryRow);
|
|
55097
55611
|
return {
|
|
@@ -55937,7 +56451,7 @@ function workflowPayloadViewGuide(record) {
|
|
|
55937
56451
|
}));
|
|
55938
56452
|
const payloadSpecificCommands = record.payload === "align-segments" ? {
|
|
55939
56453
|
content_slice: workflowPayloadShowCommand(record, ["--view blocks --token-budget 1200", "--unwrap", "--format json"]),
|
|
55940
|
-
block_window: workflowPayloadShowCommand(record, ["--view blocks --window <window-id>", "--unwrap", "--format json"]),
|
|
56454
|
+
block_window: workflowPayloadShowCommand(record, ["--view blocks --window <window-id|src-N:M>", "--unwrap", "--format json"]),
|
|
55941
56455
|
block_heading: workflowPayloadShowCommand(record, ["--view blocks --heading <heading-prefix>", "--unwrap", "--format json"]),
|
|
55942
56456
|
block_range: workflowPayloadShowCommand(record, ["--view blocks --range 1:20", "--unwrap", "--format json"]),
|
|
55943
56457
|
ledger_status: "context workflow show --payload align-candidate-ledger --view ledger --status <status> --unwrap --format json",
|
|
@@ -56064,7 +56578,7 @@ function registerWorkflowStateCommands(program2) {
|
|
|
56064
56578
|
}
|
|
56065
56579
|
});
|
|
56066
56580
|
});
|
|
56067
|
-
workflow.command("show").description("Read a workflow payload by name").requiredOption("--payload <name>", "payload name, for example node-context or prepare").option("--scope <scope>", "workflow scope id; defaults to active node/source/workspace").option("--digest <digest>", "expected payload digest").option("--metadata-only", "print workflow/payload metadata without the payload value").option("--digest-only", "print only the payload digest").option("--unwrap", "print only the payload value or compact view, without workflow metadata wrapper").option("--view <view>", "compact payload view: summary | segment | blocks | windows | ledger | aggregate | structure-decision | coverage | source-refs | unowned | by-node | issues").option("--source <source-id>", "narrow compact views to one source id").option("--window <window-
|
|
56581
|
+
workflow.command("show").description("Read a workflow payload by name").requiredOption("--payload <name>", "payload name, for example node-context or prepare").option("--scope <scope>", "workflow scope id; defaults to active node/source/workspace").option("--digest <digest>", "expected payload digest").option("--metadata-only", "print workflow/payload metadata without the payload value").option("--digest-only", "print only the payload digest").option("--unwrap", "print only the payload value or compact view, without workflow metadata wrapper").option("--view <view>", "compact payload view: summary | segment | blocks | windows | ledger | aggregate | structure-decision | coverage | source-refs | unowned | by-node | issues").option("--source <source-id>", "narrow compact views to one source id").option("--window <window-selector>", "narrow align-segments views to one window id or src-N:M alias").option("--heading <heading-prefix>", "narrow compact views to a heading path prefix or heading text").option("--range <start:end>", "narrow ordinal-based compact views to an inclusive range").option("--node <slug>", "narrow node-oriented compact views to one node slug").option("--status <status>", "narrow compact views by view-specific status").option("--candidate-id <id>", "narrow candidate-oriented compact views to one candidate id").option("--item-id <id>", "narrow item-oriented compact views to one item id").option("--page-size <n>", "limit detail rows for large filtered views").option("--page-token <offset>", "continue a paged detail view from an offset returned as next_token").option("--token-budget <n>", "limit text-rich detail views by approximate source token budget").option("--format <format>", "output format: json | yaml | text", "json").action(async (options) => {
|
|
56068
56582
|
await runWithPrelude({
|
|
56069
56583
|
name: "workflow show",
|
|
56070
56584
|
stateRequirement: "state-required",
|
|
@@ -56522,8 +57036,8 @@ function plannedSectionSourceRefGroups(context, rows) {
|
|
|
56522
57036
|
op: "add",
|
|
56523
57037
|
kind: plan.section_kind,
|
|
56524
57038
|
content: "<write supported section content>",
|
|
56525
|
-
|
|
56526
|
-
|
|
57039
|
+
summary: "<optional short summary when content is long>",
|
|
57040
|
+
source_refs: sourceRefs
|
|
56527
57041
|
}
|
|
56528
57042
|
};
|
|
56529
57043
|
});
|
|
@@ -58247,8 +58761,7 @@ function blockSourceIds(sources) {
|
|
|
58247
58761
|
function mergeSectionPlans(input) {
|
|
58248
58762
|
const currentSourceIds = new Set(input.current.sources.map((source2) => source2.source_id));
|
|
58249
58763
|
const previousBlockSource = blockSourceIds(input.previous.sources);
|
|
58250
|
-
const
|
|
58251
|
-
const previous = (input.previous.section_plans ?? []).filter((plan) => input.activeSlugs.has(plan.owner) && !currentSectionIds.has(plan.section_id) && !plan.block_ids.some((blockId) => currentSourceIds.has(previousBlockSource.get(blockId) ?? "")));
|
|
58764
|
+
const previous = (input.previous.section_plans ?? []).filter((plan) => input.activeSlugs.has(plan.owner) && !plan.block_ids.some((blockId) => currentSourceIds.has(previousBlockSource.get(blockId) ?? "")));
|
|
58252
58765
|
const current = (input.current.section_plans ?? []).filter((plan) => input.activeSlugs.has(plan.owner));
|
|
58253
58766
|
return [...previous, ...current];
|
|
58254
58767
|
}
|
|
@@ -58400,7 +58913,11 @@ var plannedSectionsUniqueConstraint = {
|
|
|
58400
58913
|
return [{
|
|
58401
58914
|
code: "planned-sections-duplicate-kinds",
|
|
58402
58915
|
path: `nodes[${nodeIndex}].planned_sections`,
|
|
58403
|
-
message: `planned_sections
|
|
58916
|
+
message: `planned_sections is the distinct set of Section kinds planned for this node; remove duplicate kind(s): ${duplicates.join(", ")}`,
|
|
58917
|
+
diagnostics: {
|
|
58918
|
+
duplicate_kinds: duplicates,
|
|
58919
|
+
next_action: "List each Section kind at most once in nodes[].planned_sections. Do not mirror every sections[] row; sections[] carries per-section detail."
|
|
58920
|
+
}
|
|
58404
58921
|
}];
|
|
58405
58922
|
}
|
|
58406
58923
|
};
|
|
@@ -58743,7 +59260,8 @@ function applyAlignOwnershipPatch(input) {
|
|
|
58743
59260
|
};
|
|
58744
59261
|
if (ids.context.length > 0)
|
|
58745
59262
|
return { ...next, context_sources: ids.context };
|
|
58746
|
-
const
|
|
59263
|
+
const rest = { ...next };
|
|
59264
|
+
delete rest.context_sources;
|
|
58747
59265
|
return rest;
|
|
58748
59266
|
});
|
|
58749
59267
|
return {
|
|
@@ -58912,8 +59430,8 @@ var SCHEMAS = {
|
|
|
58912
59430
|
generation_policy: {
|
|
58913
59431
|
language: "Chinese",
|
|
58914
59432
|
source: "workspace.language",
|
|
58915
|
-
applies_to: ["node.title", "node.summary", "section.
|
|
58916
|
-
instruction: "Generate knowledge titles, summaries, and user-facing reports in Chinese; keep node.summary concise (target <15 tokens, never >30 tokens); for source-bound Section content
|
|
59433
|
+
applies_to: ["node.title", "node.summary", "section.summary", "section.content", "user_facing_report"],
|
|
59434
|
+
instruction: "Generate knowledge titles, node summaries, Section summaries, and user-facing reports in Chinese; keep node.summary concise (target <15 tokens, never >30 tokens); for source-bound Section content, prefer the cited source language when it differs from Chinese; preserve product names, code identifiers, CLI flags, block_id/source_ref tokens, slugs, and quoted evidence exactly when needed."
|
|
58917
59435
|
},
|
|
58918
59436
|
sources: [{
|
|
58919
59437
|
source_id: "local:demo",
|
|
@@ -59298,6 +59816,8 @@ var SCHEMAS = {
|
|
|
59298
59816
|
"Incremental finalize may reference previous active Nodes from nodes[].contains_parent, edges[].from/to, domain_gate.child_refs, and block_ownership owners/visible_to/primary_owner. Do not redeclare an old parent/domain just to attach new children.",
|
|
59299
59817
|
"sections[].owner is intentionally limited to nodes declared in the current align-structure-decision payload; do not plan new Sections for previous finalized Nodes in an incremental payload.",
|
|
59300
59818
|
"Existing and previously removed Node slugs cannot change node_type in either incremental or full finalize. context align --scan --full controls replacement/removal semantics, not type-drift bypass. Use a new slug for a different type, or retire the old slug through context drop or explicit structure correction first.",
|
|
59819
|
+
"nodes[].planned_sections is the distinct set of Section kinds expected for that Node. List each kind at most once; do not mirror every sections[] row or repeat example/spec/etc. for multiple Sections.",
|
|
59820
|
+
"Navigation-only or placeholder-only Nodes may intentionally use planned_sections: [] and no owned citation evidence. Keep relation/placeholder blocks context_only or ignored; the align graph preserves structure and compile close materializes an empty placeholder Node when useful.",
|
|
59301
59821
|
"action_probe is the only place for action qualification booleans; action_gate accepts inference_sources only.",
|
|
59302
59822
|
"If the current candidate ledger already has action_probe for this action node and the digest matches, finalize may hydrate it. Directly new action nodes must provide action_probe explicitly.",
|
|
59303
59823
|
"action_gate.inference_sources needs actor, outcome_or_goal, repeatability_or_plan, and answerability. source_type must be one of explicit-block / heading-and-block / ref-node / inferred-from-block. explicit-block and heading-and-block entries may omit rationale; ref-node and inferred-from-block mappings must explain rationale.",
|
|
@@ -61043,7 +61563,7 @@ async function runAlignScanCommand(input) {
|
|
|
61043
61563
|
blocks: "context workflow show --payload align-segments --view blocks --unwrap --format json",
|
|
61044
61564
|
windows: "context workflow show --payload align-segments --view windows --unwrap --format json",
|
|
61045
61565
|
content_slice: "context workflow show --payload align-segments --view blocks --token-budget 1200 --unwrap --format json",
|
|
61046
|
-
block_detail: "context workflow show --payload align-segments --view blocks --window <window-id> --unwrap --format json",
|
|
61566
|
+
block_detail: "context workflow show --payload align-segments --view blocks --window <window-id|src-N:M> --unwrap --format json",
|
|
61047
61567
|
full_payload_explicit: "context workflow show --payload align-segments --unwrap --format json"
|
|
61048
61568
|
},
|
|
61049
61569
|
summary: summary3,
|
|
@@ -61518,7 +62038,7 @@ function registerAlignWorkflowCommand(program2) {
|
|
|
61518
62038
|
"Flow:",
|
|
61519
62039
|
" context align --scan --format json",
|
|
61520
62040
|
" context workflow show --payload align-segments --view blocks --unwrap --format json",
|
|
61521
|
-
" context workflow show --payload align-segments --view blocks --window <window-id> --unwrap --format json",
|
|
62041
|
+
" context workflow show --payload align-segments --view blocks --window <window-id|src-N:M> --unwrap --format json",
|
|
61522
62042
|
" context align --coarse-read - --format json",
|
|
61523
62043
|
" context align --ops - --format json",
|
|
61524
62044
|
" context workflow show --payload align-candidate-ledger --view ledger --unwrap --format json",
|
|
@@ -61717,6 +62237,24 @@ function prepareIssueViewCommand(input) {
|
|
|
61717
62237
|
}
|
|
61718
62238
|
function nodeCycleReviewRequiredHint(input) {
|
|
61719
62239
|
const command = prepareIssueViewCommand(input);
|
|
62240
|
+
if (input.partialApply !== undefined) {
|
|
62241
|
+
const sourceSupportSuffix = input.sourceSupportStatus === undefined ? "" : ` The remaining set includes ${input.sourceSupportStatus} source_support item(s).`;
|
|
62242
|
+
return {
|
|
62243
|
+
code: "node-cycle-partial-applied-review-required",
|
|
62244
|
+
severity: input.sourceSupportStatus === "unsupported" ? "error" : input.sourceSupportStatus === "weak" ? "warning" : "info",
|
|
62245
|
+
message: `Node-cycle applied ${input.partialApply.applied} active write(s) from ${input.safeDecisionCount ?? 0} safe decision(s); ${input.remainingItems ?? 0} item(s) still need semantic decisions.${sourceSupportSuffix}`,
|
|
62246
|
+
next_action: input.sourceSupportStatus === "unsupported" ? "Inspect the unsupported issue view and repair the draft/source_refs or split the claim before accepting defaults. The already-applied safe subset is recorded; continue only with the remaining items." : input.sourceSupportStatus === "weak" ? "Inspect the weak issue view and confirm the evidence boundary before accepting defaults or asking the user. The already-applied safe subset is recorded; continue only with the remaining items." : "Load the prepare issue view, decide only the remaining items, then run context reconcile review/apply for this scope.",
|
|
62247
|
+
command,
|
|
62248
|
+
diagnostics: {
|
|
62249
|
+
safe_decisions: input.safeDecisionCount ?? 0,
|
|
62250
|
+
active_writes: input.partialApply.applied,
|
|
62251
|
+
skipped: input.partialApply.skipped,
|
|
62252
|
+
omitted: input.partialApply.omitted,
|
|
62253
|
+
remaining_items: input.remainingItems ?? 0,
|
|
62254
|
+
...input.sourceSupportStatus !== undefined ? { source_support_status: input.sourceSupportStatus } : {}
|
|
62255
|
+
}
|
|
62256
|
+
};
|
|
62257
|
+
}
|
|
61720
62258
|
if (input.sourceSupportStatus !== undefined) {
|
|
61721
62259
|
return {
|
|
61722
62260
|
code: "node-cycle-review-required-source-support",
|
|
@@ -61795,13 +62333,15 @@ async function runCompileNodeCycle(input) {
|
|
|
61795
62333
|
value: context,
|
|
61796
62334
|
format: "json"
|
|
61797
62335
|
});
|
|
61798
|
-
const
|
|
62336
|
+
const delegatedWorkflow = isDelegatedWorkflow(preparedWorkflow);
|
|
62337
|
+
const decisions = safeDefaultDecisionDocument(context, { delegated: delegatedWorkflow });
|
|
61799
62338
|
const review = {
|
|
61800
62339
|
mode: "compile",
|
|
61801
62340
|
...await reviewSemanticDecisionsWithWorkspace({
|
|
61802
62341
|
ctxDir: input.ctxDir,
|
|
61803
62342
|
context,
|
|
61804
|
-
decisions
|
|
62343
|
+
decisions,
|
|
62344
|
+
allowDelegatedDecisions: delegatedWorkflow
|
|
61805
62345
|
})
|
|
61806
62346
|
};
|
|
61807
62347
|
const reviewStage = review.ready_to_apply ? "node_review_ready" : "node_prepared";
|
|
@@ -61834,7 +62374,8 @@ async function runCompileNodeCycle(input) {
|
|
|
61834
62374
|
try {
|
|
61835
62375
|
partialApply = await applySemanticDecisions({
|
|
61836
62376
|
ctxDir: input.ctxDir,
|
|
61837
|
-
document: review.apply_document
|
|
62377
|
+
document: review.apply_document,
|
|
62378
|
+
allowDelegatedDecisions: delegatedWorkflow
|
|
61838
62379
|
});
|
|
61839
62380
|
} catch (error) {
|
|
61840
62381
|
throw new ContextError(ExitCode.WorkspaceStateError, `node-cycle partial apply failed after safe-default review: ${errorMessage2(error)}`, {
|
|
@@ -61863,7 +62404,7 @@ async function runCompileNodeCycle(input) {
|
|
|
61863
62404
|
review: workflowPayloadReceipt(reviewPayload),
|
|
61864
62405
|
safe_defaults: {
|
|
61865
62406
|
auto_decided: decisions.decisions.length,
|
|
61866
|
-
auto_applied:
|
|
62407
|
+
auto_applied: partialApply?.applied ?? 0,
|
|
61867
62408
|
remaining_items: remaining,
|
|
61868
62409
|
applied: partialApplied,
|
|
61869
62410
|
complete: false
|
|
@@ -61876,7 +62417,12 @@ async function runCompileNodeCycle(input) {
|
|
|
61876
62417
|
next_command: issueViewCommand,
|
|
61877
62418
|
agent_hints: [nodeCycleReviewRequiredHint({
|
|
61878
62419
|
preparePayload,
|
|
61879
|
-
...supportStatus !== undefined ? { sourceSupportStatus: supportStatus } : {}
|
|
62420
|
+
...supportStatus !== undefined ? { sourceSupportStatus: supportStatus } : {},
|
|
62421
|
+
...partialApply !== undefined ? {
|
|
62422
|
+
partialApply,
|
|
62423
|
+
safeDecisionCount: partialDecisionCount,
|
|
62424
|
+
remainingItems: remaining
|
|
62425
|
+
} : {}
|
|
61880
62426
|
})]
|
|
61881
62427
|
};
|
|
61882
62428
|
return input.format === "json" ? `${JSON.stringify(output2, null, 2)}
|
|
@@ -61906,7 +62452,8 @@ async function runCompileNodeCycle(input) {
|
|
|
61906
62452
|
try {
|
|
61907
62453
|
apply = await applySemanticDecisions({
|
|
61908
62454
|
ctxDir: input.ctxDir,
|
|
61909
|
-
document: artifact.artifact
|
|
62455
|
+
document: artifact.artifact,
|
|
62456
|
+
allowDelegatedDecisions: delegatedWorkflow
|
|
61910
62457
|
});
|
|
61911
62458
|
} catch (error) {
|
|
61912
62459
|
throw new ContextError(ExitCode.WorkspaceStateError, `node-cycle apply failed after review became ready: ${errorMessage2(error)}`, {
|
|
@@ -61948,7 +62495,7 @@ async function runCompileNodeCycle(input) {
|
|
|
61948
62495
|
},
|
|
61949
62496
|
safe_defaults: {
|
|
61950
62497
|
auto_decided: decisions.decisions.length,
|
|
61951
|
-
auto_applied:
|
|
62498
|
+
auto_applied: apply.applied,
|
|
61952
62499
|
remaining_items: 0,
|
|
61953
62500
|
applied: true,
|
|
61954
62501
|
complete: true
|
|
@@ -62052,7 +62599,7 @@ function rejectRetiredDraftPatchFields(patchInput, slug) {
|
|
|
62052
62599
|
code: "compile-draft-patch-retired-field",
|
|
62053
62600
|
severity: "error",
|
|
62054
62601
|
message: first.message,
|
|
62055
|
-
next_action: "Patch actions must use
|
|
62602
|
+
next_action: "Patch actions must use content plus optional summary and source_refs[]; remove retired body/detail/raw and extractive fields.",
|
|
62056
62603
|
command: `context compile --draft-patch ${slug} --input - --plan`,
|
|
62057
62604
|
target_node: slug,
|
|
62058
62605
|
path: first.path,
|
|
@@ -62078,7 +62625,7 @@ init_prepare();
|
|
|
62078
62625
|
init_exitCode();
|
|
62079
62626
|
init_currentWorkflow();
|
|
62080
62627
|
init_workflowPayloadStore();
|
|
62081
|
-
function prepareReviewNextCommand(
|
|
62628
|
+
function prepareReviewNextCommand() {
|
|
62082
62629
|
return [
|
|
62083
62630
|
"context reconcile review",
|
|
62084
62631
|
"--decisions -",
|
|
@@ -62091,7 +62638,7 @@ function withPayloadMeta2(value, payload) {
|
|
|
62091
62638
|
return {
|
|
62092
62639
|
...value,
|
|
62093
62640
|
workflow_payload: workflowPayloadReceipt(payload, {
|
|
62094
|
-
nextCommand: prepareReviewNextCommand(
|
|
62641
|
+
nextCommand: prepareReviewNextCommand()
|
|
62095
62642
|
})
|
|
62096
62643
|
};
|
|
62097
62644
|
}
|
|
@@ -62143,7 +62690,7 @@ async function prepareCompileDraftWorkflow(input) {
|
|
|
62143
62690
|
`prepare payload digest: ${preparePayload.digest} (optional stale guard)`,
|
|
62144
62691
|
`prepare payload show: ${workflowPayloadShowCommand(preparePayload)}`
|
|
62145
62692
|
],
|
|
62146
|
-
next: `run context:skill-compile-judge with the prepare payload, then ${prepareReviewNextCommand(
|
|
62693
|
+
next: `run context:skill-compile-judge with the prepare payload, then ${prepareReviewNextCommand()}`
|
|
62147
62694
|
});
|
|
62148
62695
|
}
|
|
62149
62696
|
|
|
@@ -62458,6 +63005,8 @@ function coverageSkipMissingOptionsError(missingFields, mode = "single") {
|
|
|
62458
63005
|
});
|
|
62459
63006
|
}
|
|
62460
63007
|
function compileStageForOptions(options) {
|
|
63008
|
+
if (options.scanChanges === true && options.delegated === true)
|
|
63009
|
+
return "planned";
|
|
62461
63010
|
if (typeof options.nodeCycle === "string")
|
|
62462
63011
|
return "node_draft_ready";
|
|
62463
63012
|
if (typeof options.context === "string")
|
|
@@ -62480,7 +63029,7 @@ function compileScopeForOptions(options) {
|
|
|
62480
63029
|
function registerWorkflowCommands(program2) {
|
|
62481
63030
|
registerWorkflowStateCommands(program2);
|
|
62482
63031
|
registerAlignWorkflowCommand(program2);
|
|
62483
|
-
program2.command("compile").description("Workflow helpers for /context:compile").option("--scan-changes", "print incremental compile workset without creating a workflow lock").addOption(new Option("--scan", "removed; use --scan-changes").hideHelp()).option("--format <format>", "with --scan-changes/--context/--source-refs, output format: json | table", "table").option("--view <view>", "compact output view: full | summary | source-refs | issues").option("--ignore-source <source-id>", "with --scan-changes, --context, or --source-refs, ignore refresh-applied source ids", collectIgnoredSource, []).option("--context <slug>", "prepare NodeContext payload for one align node and print summary/digests").option("--cover-uncovered-only", "with --context, return only unresolved coverage candidates for a targeted repair round").option("--source-refs <slug>", "print compact citation source_ref list for one align node").option("--request-full-text <block-id>", "with --context, expand one visible finalized evidence block", collectRequestedBlock, []).option("--node-cycle <slug>", "validate one node draft, prepare reconcile, review safe defaults, and apply in one command").option("--draft <slug>", "validate a compile draft JSON/YAML document from stdin, or with --prepare reuse the saved draft").option("--prepare", "with --draft --plan, also prepare the semantic reconcile payload").option("--draft-status <slug>", "print the current compile draft session summary").option("--draft-patch <slug>", "apply a compile draft patch for one node").option("--input <stdin>", "compile draft JSON/YAML document used with --draft; use '-' for stdin").option("--accept-safe-defaults", "with --node-cycle, accept mechanically safe defaults and stop if anything needs judgment").option("--coverage-disposition <stdin>", "coverage disposition patch JSON/YAML document; use '-' for stdin").option("--coverage-skip <candidate-id>", "skip one coverage candidate without writing a disposition file").option("--coverage-skip-unresolved", "skip every unresolved coverage candidate in the node payload").option("--coverage-disposition-node <slug>", "node slug for --coverage-disposition").option("--coverage-disposition-replace", "replace existing dispositions for the patched coverage candidates").option("--payload-digest <digest>", "optional workflow payload digest stale guard for write commands").option("--reason <text>", "reason for coverage skip shortcuts").option("--plan", "validate the draft without writing knowledge").option("--close", "run compile close: compact, rebuild index, append changelog, verify").option("--save-input", "with --draft, save the consumed draft under output/compile/compile.<slug>.draft.yaml").action(async (options) => {
|
|
63032
|
+
program2.command("compile").description("Workflow helpers for /context:compile").option("--scan-changes", "print incremental compile workset without creating a workflow lock").addOption(new Option("--scan", "removed; use --scan-changes").hideHelp()).option("--format <format>", "with --scan-changes/--context/--source-refs, output format: json | table", "table").option("--view <view>", "compact output view: full | summary | source-refs | issues").option("--ignore-source <source-id>", "with --scan-changes, --context, or --source-refs, ignore refresh-applied source ids", collectIgnoredSource, []).option("--context <slug>", "prepare NodeContext payload for one align node and print summary/digests").option("--cover-uncovered-only", "with --context, return only unresolved coverage candidates for a targeted repair round").option("--source-refs <slug>", "print compact citation source_ref list for one align node").option("--request-full-text <block-id>", "with --context, expand one visible finalized evidence block", collectRequestedBlock, []).option("--node-cycle <slug>", "validate one node draft, prepare reconcile, review safe defaults, and apply in one command").option("--delegated", "with a new compile workflow, record user-authorized delegated mode for low-risk review decisions").option("--draft <slug>", "validate a compile draft JSON/YAML document from stdin, or with --prepare reuse the saved draft").option("--prepare", "with --draft --plan, also prepare the semantic reconcile payload").option("--draft-status <slug>", "print the current compile draft session summary").option("--draft-patch <slug>", "apply a compile draft patch for one node").option("--input <stdin>", "compile draft JSON/YAML document used with --draft; use '-' for stdin").option("--accept-safe-defaults", "with --node-cycle, accept mechanically safe defaults and stop if anything needs judgment").option("--coverage-disposition <stdin>", "coverage disposition patch JSON/YAML document; use '-' for stdin").option("--coverage-skip <candidate-id>", "skip one coverage candidate without writing a disposition file").option("--coverage-skip-unresolved", "skip every unresolved coverage candidate in the node payload").option("--coverage-disposition-node <slug>", "node slug for --coverage-disposition").option("--coverage-disposition-replace", "replace existing dispositions for the patched coverage candidates").option("--payload-digest <digest>", "optional workflow payload digest stale guard for write commands").option("--reason <text>", "reason for coverage skip shortcuts").option("--plan", "validate the draft without writing knowledge").option("--close", "run compile close: compact, rebuild index, append changelog, verify").option("--save-input", "with --draft, save the consumed draft under output/compile/compile.<slug>.draft.yaml").action(async (options) => {
|
|
62484
63033
|
if (options.scan === true) {
|
|
62485
63034
|
throw new ContextError(ExitCode.UserError, "context compile --scan was removed; use context compile --scan-changes", {
|
|
62486
63035
|
category: ErrorCategory.UserInputInvalid,
|
|
@@ -62496,7 +63045,7 @@ function registerWorkflowCommands(program2) {
|
|
|
62496
63045
|
const wantsChanges = options.scanChanges === true;
|
|
62497
63046
|
const actionCount = countActions(wantsChanges, typeof options.context === "string", typeof options.sourceRefs === "string", typeof options.nodeCycle === "string", typeof options.draft === "string", typeof options.draftStatus === "string", typeof options.draftPatch === "string", typeof options.coverageDisposition === "string", typeof options.coverageSkip === "string", options.coverageSkipUnresolved === true, options.close === true);
|
|
62498
63047
|
if (actionCount !== 1) {
|
|
62499
|
-
throw new ContextError(ExitCode.UserError, "usage: context compile --scan-changes | --context <slug> | --source-refs <slug> | --node-cycle <slug> --input - --accept-safe-defaults | --draft <slug> --input - --plan [--prepare] | --draft <slug> --plan --prepare | --draft-status <slug> | --draft-patch <slug> --input - --plan [--payload-digest <digest>] | --coverage-disposition - --coverage-disposition-node <slug> [--payload-digest <digest>] | --coverage-skip <candidate-id> --coverage-disposition-node <slug> --reason <text> | --coverage-skip-unresolved --coverage-disposition-node <slug> --reason <text> | --close", { category: ErrorCategory.UserInputInvalid });
|
|
63048
|
+
throw new ContextError(ExitCode.UserError, "usage: context compile --scan-changes [--delegated] | --context <slug> [--delegated] | --source-refs <slug> | --node-cycle <slug> --input - --accept-safe-defaults [--delegated] | --draft <slug> --input - --plan [--prepare] [--delegated] | --draft <slug> --plan --prepare | --draft-status <slug> | --draft-patch <slug> --input - --plan [--payload-digest <digest>] | --coverage-disposition - --coverage-disposition-node <slug> [--payload-digest <digest>] | --coverage-skip <candidate-id> --coverage-disposition-node <slug> --reason <text> | --coverage-skip-unresolved --coverage-disposition-node <slug> --reason <text> | --close", { category: ErrorCategory.UserInputInvalid });
|
|
62500
63049
|
}
|
|
62501
63050
|
const viewWasExplicit = typeof options.view === "string";
|
|
62502
63051
|
const view = compileOutputView(options.view);
|
|
@@ -62525,6 +63074,20 @@ function registerWorkflowCommands(program2) {
|
|
|
62525
63074
|
}
|
|
62526
63075
|
const requestFullTextBlockIds = ignoredSourceIds(options.requestFullText);
|
|
62527
63076
|
const coverUncoveredOnly = options.coverUncoveredOnly === true;
|
|
63077
|
+
const delegated = options.delegated === true;
|
|
63078
|
+
const delegatedAllowed = wantsChanges || typeof options.context === "string" || typeof options.nodeCycle === "string" || typeof options.draft === "string";
|
|
63079
|
+
if (delegated && !delegatedAllowed) {
|
|
63080
|
+
throw new ContextError(ExitCode.UserError, "--delegated is only valid when starting or advancing a compile workflow", {
|
|
63081
|
+
category: ErrorCategory.UserInputInvalid,
|
|
63082
|
+
agent_hints: [{
|
|
63083
|
+
code: "compile-delegated-workflow-entry-only",
|
|
63084
|
+
severity: "error",
|
|
63085
|
+
message: "--delegated records conversation-level user authorization on the compile workflow; it is not a per-command override.",
|
|
63086
|
+
next_action: "Use --delegated only on the initial context compile --scan-changes, --context, --draft, or --node-cycle command after explicit user authorization.",
|
|
63087
|
+
command: "context compile --scan-changes --delegated --format json"
|
|
63088
|
+
}]
|
|
63089
|
+
});
|
|
63090
|
+
}
|
|
62528
63091
|
assertNodeCycleOptions({
|
|
62529
63092
|
slug: options.nodeCycle,
|
|
62530
63093
|
inputFlag: options.input,
|
|
@@ -62621,6 +63184,13 @@ function registerWorkflowCommands(program2) {
|
|
|
62621
63184
|
family: "compile",
|
|
62622
63185
|
stage,
|
|
62623
63186
|
scopeId: scope.scopeId,
|
|
63187
|
+
...delegated ? {
|
|
63188
|
+
executionMode: "delegated",
|
|
63189
|
+
delegatedAuthority: {
|
|
63190
|
+
source: "user_conversation",
|
|
63191
|
+
scope: "low_risk_review_decisions"
|
|
63192
|
+
}
|
|
63193
|
+
} : {},
|
|
62624
63194
|
...scope.activeNodeRun !== undefined ? { activeNodeRun: scope.activeNodeRun } : {}
|
|
62625
63195
|
}) : undefined;
|
|
62626
63196
|
if (wantsChanges) {
|
|
@@ -64172,9 +64742,9 @@ function reconcileSchemaExample(name) {
|
|
|
64172
64742
|
"Run context reconcile review before apply. Review persists the ready artifact; apply reads it from the current workflow scope.",
|
|
64173
64743
|
"If prepare items include default_decision and you accept it, emit one compact decision object per item_id with accept_default: true; review hydrates target/proposed/action from that default.",
|
|
64174
64744
|
"Do not use decisions: [] to accept all defaults; an empty decisions array means no decisions were made.",
|
|
64175
|
-
"Keep proposed.content
|
|
64176
|
-
"Do not copy basis/evidence text into
|
|
64177
|
-
"For kind=example, preserving the cited fenced code/config/command block in proposed.
|
|
64745
|
+
"Keep proposed.content as the user-facing Section text. For long content, include proposed.summary as one plain paragraph; do not emit retired long-form fields.",
|
|
64746
|
+
"Do not copy basis/evidence text into hidden fields just to show the original raw text; source_ref/source_refs already provide traceability. Preserved raw wording is acceptable only when it is active user-facing Section content.",
|
|
64747
|
+
"For kind=example, preserving the cited fenced code/config/command block in proposed.content is active example knowledge, not raw-evidence echo.",
|
|
64178
64748
|
'Use source_ref/source_refs copied from raw_snippets[].source_ref. Only run context source resolve-ref --node <slug> --text "<quote>" for manual recovery from a short quoted text fragment.',
|
|
64179
64749
|
"Only set decided_by: user after an actual user or tester confirmed the answer. Auto mode or broad permission to continue is not user confirmation; if no confirmation exists, fix/split evidence or leave ask_user unresolved.",
|
|
64180
64750
|
"When prepare/review returns agent_hints[], follow those result-specific hints before retrying."
|
|
@@ -64192,7 +64762,7 @@ function reconcileSchemaExample(name) {
|
|
|
64192
64762
|
proposed: {
|
|
64193
64763
|
kind: "description",
|
|
64194
64764
|
content: "Runtime Service owns request routing and retry policy.",
|
|
64195
|
-
|
|
64765
|
+
summary: "Runtime Service owns routing and retry policy.",
|
|
64196
64766
|
confidence: "confirmed",
|
|
64197
64767
|
source_ref: "src-1#runtime-service L3-8@7a6f4c9d2e10",
|
|
64198
64768
|
refers_to_nodes: ["deployment-pipeline"]
|
|
@@ -64253,7 +64823,9 @@ function compileSchemaExample(name) {
|
|
|
64253
64823
|
ownership_requested_role: ["owned", "shared"]
|
|
64254
64824
|
},
|
|
64255
64825
|
limits: {
|
|
64256
|
-
|
|
64826
|
+
summary_recommended_when_content_over_chars: 160,
|
|
64827
|
+
summary_required_when_content_over_chars: 200,
|
|
64828
|
+
summary_target: "about content length / 10, minimum 10 characters, recommended maximum 120; warnings are advisory"
|
|
64257
64829
|
},
|
|
64258
64830
|
section_kind_priority: SECTION_DRAFT_PRIORITY,
|
|
64259
64831
|
section_kind_triggers: {
|
|
@@ -64272,14 +64844,15 @@ function compileSchemaExample(name) {
|
|
|
64272
64844
|
notes: [
|
|
64273
64845
|
"Use the NodeContext payload prepared by context compile --context <slug> --format json to choose source_refs[] from raw_snippets[].source_ref.",
|
|
64274
64846
|
"Op naming standard: compile-draft actions[] already targets Sections, so Section lifecycle ops are verb-only names. Use op: add for a new Section; do not use add_section, write_section, or propose_section.",
|
|
64275
|
-
"Every add/update/supersede Section write uses
|
|
64276
|
-
"
|
|
64847
|
+
"Every add/update/supersede Section write uses content plus source_refs[]. content is the user-facing Section text and may be long or contain fenced code.",
|
|
64848
|
+
"If content is longer than 200 characters, provide summary. summary is LLM-authored, one plain paragraph, about content length / 10, minimum 10 characters, recommended maximum 120. The CLI reports summary quality as warning hints, not hard errors.",
|
|
64849
|
+
"content should default to the cited raw wording. Only make semantic-preserving edits for formatting, typos, casing, entity/alias consistency, or sentence cleanup. If raw is already clear, keep content equal to raw.",
|
|
64277
64850
|
"source_support is a lexical diagnostic, not a target to game. There is no separate default evidence-echo warning; preserve source wording only when it is active user-facing knowledge, not traceability padding.",
|
|
64278
|
-
"For description/spec, a
|
|
64279
|
-
"
|
|
64851
|
+
"For description/spec, a short summary plus cited descriptive bullets in content is allowed when the bullets themselves are useful knowledge. For code/config/command samples, prefer kind=example and keep the sample in content.",
|
|
64852
|
+
"Do not emit body, detail, raw, rewrite, content_mode, paraphrase_reason, basis_spans, or section_id for new Sections. If content differs from cited raw, the CLI derives a debug-only raw block during prepare/apply.",
|
|
64280
64853
|
"source_refs is the only compile-draft citation input. For a single citation, use an array with one source_ref string.",
|
|
64281
|
-
"For dense raw material where one Section summarizes multiple contiguous blocks, provide only the source_refs actually consumed by that Section
|
|
64282
|
-
"If multiple source_refs are over-cited but the
|
|
64854
|
+
"For dense raw material where one Section summarizes multiple contiguous blocks, provide only the source_refs actually consumed by that Section content. Contiguous means the selected source_refs resolve to consecutive evidence-manifest blocks from the same source, snapshot, and alias; if an intervening citation-eligible block is skipped, split the action or include that block's source_ref.",
|
|
64855
|
+
"If multiple source_refs are over-cited but the content is fully supported by a smaller contiguous subset, the CLI may narrow the citation and report compile-source-refs-auto-narrowed; removed refs remain uncovered for later draft/skip actions.",
|
|
64283
64856
|
"If NodeContext only contains navigation or placeholder evidence (Parent/Children/Related/Relations, no detailed content), use op: skip; do not create a low-value description Section from those lines.",
|
|
64284
64857
|
"Use structure_challenge for missing action nodes, extra action nodes, wrong shared block splits, missing depends_on edges, or wrong parents.",
|
|
64285
64858
|
"Use pending_ownership_challenge for visible context_only blocks or secondary shared blocks that should become owned/shared evidence.",
|
|
@@ -64291,14 +64864,14 @@ function compileSchemaExample(name) {
|
|
|
64291
64864
|
actions: [{
|
|
64292
64865
|
op: "add",
|
|
64293
64866
|
kind: "description",
|
|
64294
|
-
|
|
64295
|
-
rewrite: false,
|
|
64867
|
+
content: "Runtime Service owns request routing and retry policy.",
|
|
64296
64868
|
source_refs: ["src-1#runtime-service L3-8@7a6f4c9d2e10"],
|
|
64297
64869
|
refers_to_nodes: ["deployment-pipeline"]
|
|
64298
64870
|
}, {
|
|
64299
64871
|
op: "add",
|
|
64300
64872
|
kind: "example",
|
|
64301
|
-
|
|
64873
|
+
summary: "Runtime Service supports retry backoff configuration.",
|
|
64874
|
+
content: [
|
|
64302
64875
|
"Runtime Service can be configured with retry limits and exponential backoff.",
|
|
64303
64876
|
"",
|
|
64304
64877
|
"```ts",
|
|
@@ -64312,7 +64885,7 @@ function compileSchemaExample(name) {
|
|
|
64312
64885
|
}, {
|
|
64313
64886
|
op: "update",
|
|
64314
64887
|
target_section_id: "section-1",
|
|
64315
|
-
|
|
64888
|
+
content: "Runtime Service owns request routing and retry policy.",
|
|
64316
64889
|
source_refs: ["src-1#runtime-service L3-8@7a6f4c9d2e10"]
|
|
64317
64890
|
}, {
|
|
64318
64891
|
op: "supersede",
|
|
@@ -64320,7 +64893,7 @@ function compileSchemaExample(name) {
|
|
|
64320
64893
|
reason: "Source now describes the replacement behavior.",
|
|
64321
64894
|
new: {
|
|
64322
64895
|
kind: "spec",
|
|
64323
|
-
|
|
64896
|
+
content: "Retries use exponential backoff.",
|
|
64324
64897
|
source_refs: ["src-1#retry-policy L12-16@c0d4e5f61728"]
|
|
64325
64898
|
}
|
|
64326
64899
|
}, {
|
|
@@ -64412,7 +64985,7 @@ function compileSchemaExample(name) {
|
|
|
64412
64985
|
action: {
|
|
64413
64986
|
op: "add",
|
|
64414
64987
|
kind: "description",
|
|
64415
|
-
|
|
64988
|
+
content: "Runtime Service owns request routing.",
|
|
64416
64989
|
source_refs: ["src-1#runtime-service L3-8@7a6f4c9d2e10"]
|
|
64417
64990
|
}
|
|
64418
64991
|
}, {
|
|
@@ -64467,11 +65040,11 @@ function compileSchemaExample(name) {
|
|
|
64467
65040
|
applies_to: [
|
|
64468
65041
|
"node.title",
|
|
64469
65042
|
"node.summary",
|
|
65043
|
+
"section.summary",
|
|
64470
65044
|
"section.content",
|
|
64471
|
-
"section.detail",
|
|
64472
65045
|
"user_facing_report"
|
|
64473
65046
|
],
|
|
64474
|
-
instruction: "Generate knowledge titles, summaries, and user-facing reports in Chinese; keep node.summary concise (target <15 tokens, never >30 tokens); for source-bound Section content
|
|
65047
|
+
instruction: "Generate knowledge titles, summaries, and user-facing reports in Chinese; keep node.summary concise (target <15 tokens, never >30 tokens); section.summary is a short one-paragraph reader/query aid for long content; for source-bound Section content, prefer the cited source language when it differs from Chinese; preserve product names, code identifiers, CLI flags, block_id/source_ref tokens, slugs, and quoted evidence exactly when needed."
|
|
64475
65048
|
},
|
|
64476
65049
|
existing: {
|
|
64477
65050
|
sections: [{
|