@c4a/context-cli 0.5.29-beta.21 → 0.5.29-beta.22
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/cli.js +609 -119
- package/package.json +1 -1
- package/plugin/commands/align.md +4 -3
- package/plugin/commands/capture.md +1 -1
- package/plugin/commands/compile.md +7 -7
- package/plugin/skills/skill-align-workflow/SKILL.md +5 -4
- package/plugin/skills/skill-align-workflow/references/gates.md +17 -0
- package/plugin/skills/skill-compile-draft/SKILL.md +3 -3
- package/plugin/skills/skill-context-query/SKILL.md +4 -4
package/cli.js
CHANGED
|
@@ -19189,6 +19189,65 @@ function parseOptionalCommentBlock(input) {
|
|
|
19189
19189
|
after: trimBlankEdges(input.lines.slice(end + 1))
|
|
19190
19190
|
};
|
|
19191
19191
|
}
|
|
19192
|
+
function stripSummaryBlockquote(value) {
|
|
19193
|
+
const lines = value.split(/\r?\n/u);
|
|
19194
|
+
const allQuoted = lines.every((line) => {
|
|
19195
|
+
const trimmed = line.trimStart();
|
|
19196
|
+
return trimmed.length === 0 || trimmed.startsWith(">");
|
|
19197
|
+
});
|
|
19198
|
+
if (!allQuoted)
|
|
19199
|
+
return value;
|
|
19200
|
+
return lines.map((line) => {
|
|
19201
|
+
const trimmed = line.trimStart();
|
|
19202
|
+
if (!trimmed.startsWith(">"))
|
|
19203
|
+
return "";
|
|
19204
|
+
return trimmed.slice(1).replace(/^\s/u, "");
|
|
19205
|
+
}).join(`
|
|
19206
|
+
`).trim();
|
|
19207
|
+
}
|
|
19208
|
+
function unescapeRawComment(value) {
|
|
19209
|
+
return value.replace(/--\\>/gu, "-->");
|
|
19210
|
+
}
|
|
19211
|
+
function parseOptionalRawBlock(lines, sectionId) {
|
|
19212
|
+
const hiddenStart = lines.findIndex((line) => RAW_OPEN_RE.test(line.trim()));
|
|
19213
|
+
const hiddenEnd = lines.findIndex((line) => RAW_CLOSE_RE.test(line.trim()));
|
|
19214
|
+
const legacyStart = lines.findIndex((line) => LEGACY_RAW_OPEN_RE.test(line.trim()));
|
|
19215
|
+
const legacyEnd = lines.findIndex((line) => LEGACY_RAW_CLOSE_RE.test(line.trim()));
|
|
19216
|
+
if (hiddenStart >= 0 && legacyStart >= 0) {
|
|
19217
|
+
throw new Error(`section ${sectionId} must contain at most one c4a:raw block`);
|
|
19218
|
+
}
|
|
19219
|
+
if (hiddenStart < 0 && hiddenEnd >= 0) {
|
|
19220
|
+
throw new Error(`section ${sectionId} has c4a:raw close without open`);
|
|
19221
|
+
}
|
|
19222
|
+
if (legacyStart < 0 && legacyEnd >= 0) {
|
|
19223
|
+
throw new Error(`section ${sectionId} has raw close without open`);
|
|
19224
|
+
}
|
|
19225
|
+
if (hiddenStart >= 0 && hiddenEnd < 0) {
|
|
19226
|
+
throw new Error(`section ${sectionId} is missing /c4a:raw`);
|
|
19227
|
+
}
|
|
19228
|
+
if (hiddenStart >= 0 && hiddenEnd < hiddenStart) {
|
|
19229
|
+
throw new Error(`section ${sectionId} has /c4a:raw before c4a:raw`);
|
|
19230
|
+
}
|
|
19231
|
+
if (hiddenStart >= 0) {
|
|
19232
|
+
const valueLines = trimBlankEdges(lines.slice(hiddenStart + 1, hiddenEnd));
|
|
19233
|
+
if (valueLines.length === 0) {
|
|
19234
|
+
throw new Error(`section ${sectionId} has empty c4a:raw`);
|
|
19235
|
+
}
|
|
19236
|
+
return {
|
|
19237
|
+
value: unescapeRawComment(valueLines.join(`
|
|
19238
|
+
`).trim()),
|
|
19239
|
+
before: trimBlankEdges(lines.slice(0, hiddenStart)),
|
|
19240
|
+
after: trimBlankEdges(lines.slice(hiddenEnd + 1))
|
|
19241
|
+
};
|
|
19242
|
+
}
|
|
19243
|
+
return parseOptionalCommentBlock({
|
|
19244
|
+
lines,
|
|
19245
|
+
sectionId,
|
|
19246
|
+
name: "raw",
|
|
19247
|
+
open: LEGACY_RAW_OPEN_RE,
|
|
19248
|
+
close: LEGACY_RAW_CLOSE_RE
|
|
19249
|
+
});
|
|
19250
|
+
}
|
|
19192
19251
|
function parseSectionBody(lines, sectionId) {
|
|
19193
19252
|
const summary = parseOptionalCommentBlock({
|
|
19194
19253
|
lines,
|
|
@@ -19201,13 +19260,7 @@ function parseSectionBody(lines, sectionId) {
|
|
|
19201
19260
|
throw new Error(`section ${sectionId} has content before c4a:summary`);
|
|
19202
19261
|
}
|
|
19203
19262
|
const afterSummary = summary.value !== undefined ? summary.after : summary.before;
|
|
19204
|
-
const raw =
|
|
19205
|
-
lines: afterSummary,
|
|
19206
|
-
sectionId,
|
|
19207
|
-
name: "raw",
|
|
19208
|
-
open: RAW_OPEN_RE,
|
|
19209
|
-
close: RAW_CLOSE_RE
|
|
19210
|
-
});
|
|
19263
|
+
const raw = parseOptionalRawBlock(afterSummary, sectionId);
|
|
19211
19264
|
if (raw.after.length > 0) {
|
|
19212
19265
|
throw new Error(`section ${sectionId} has content after /c4a:raw`);
|
|
19213
19266
|
}
|
|
@@ -19216,7 +19269,7 @@ function parseSectionBody(lines, sectionId) {
|
|
|
19216
19269
|
throw new Error(`section ${sectionId} is missing content`);
|
|
19217
19270
|
}
|
|
19218
19271
|
return {
|
|
19219
|
-
...summary.value !== undefined ? { summary: summary.value } : {},
|
|
19272
|
+
...summary.value !== undefined ? { summary: stripSummaryBlockquote(summary.value) } : {},
|
|
19220
19273
|
content: contentLines.join(`
|
|
19221
19274
|
`).trim(),
|
|
19222
19275
|
...raw.value !== undefined ? { raw: raw.value } : {}
|
|
@@ -19287,7 +19340,7 @@ function parseSectionBlock(lines, startIndex, anchorSlug) {
|
|
|
19287
19340
|
}
|
|
19288
19341
|
return { section, nextIndex: index };
|
|
19289
19342
|
}
|
|
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;
|
|
19343
|
+
var SECTION_OPEN_RE, SECTION_CLOSE_RE, LEGACY_SECTION_OPEN_RE, SUMMARY_OPEN_RE, SUMMARY_CLOSE_RE, RAW_OPEN_RE, RAW_CLOSE_RE, LEGACY_RAW_OPEN_RE, LEGACY_RAW_CLOSE_RE, RELATION_RE, ATTR_RE;
|
|
19291
19344
|
var init_nodeParserSections = __esm(() => {
|
|
19292
19345
|
init_knowledge();
|
|
19293
19346
|
SECTION_OPEN_RE = /^<!--\s*c4a:section\b([\s\S]*?)\s*-->$/u;
|
|
@@ -19295,8 +19348,10 @@ var init_nodeParserSections = __esm(() => {
|
|
|
19295
19348
|
LEGACY_SECTION_OPEN_RE = /^<!--\s*section-\d+\s+([A-Za-z_][\w-]*)\b[\s\S]*-->$/u;
|
|
19296
19349
|
SUMMARY_OPEN_RE = /^<!--\s*c4a:summary\s*-->$/u;
|
|
19297
19350
|
SUMMARY_CLOSE_RE = /^<!--\s*\/c4a:summary\s*-->$/u;
|
|
19298
|
-
RAW_OPEN_RE = /^<!--\s*c4a:raw\s
|
|
19299
|
-
RAW_CLOSE_RE =
|
|
19351
|
+
RAW_OPEN_RE = /^<!--\s*c4a:raw\s*$/u;
|
|
19352
|
+
RAW_CLOSE_RE = /^\/c4a:raw\s*-->$/u;
|
|
19353
|
+
LEGACY_RAW_OPEN_RE = /^<!--\s*c4a:raw\s*-->$/u;
|
|
19354
|
+
LEGACY_RAW_CLOSE_RE = /^<!--\s*\/c4a:raw\s*-->$/u;
|
|
19300
19355
|
RELATION_RE = /^<!--\s*c4a:relation\b([\s\S]*?)\s*-->$/u;
|
|
19301
19356
|
ATTR_RE = /([A-Za-z_][\w:-]*)="([^"]*)"/yu;
|
|
19302
19357
|
});
|
|
@@ -19847,12 +19902,15 @@ function renderSectionComment(section) {
|
|
|
19847
19902
|
return [head, ...relationLines].join(`
|
|
19848
19903
|
`);
|
|
19849
19904
|
}
|
|
19905
|
+
function renderSummaryText(value) {
|
|
19906
|
+
return value.trim().split(/\r?\n/u).map((line) => line.trim().length > 0 ? `> ${line}` : ">").join(`
|
|
19907
|
+
`);
|
|
19908
|
+
}
|
|
19850
19909
|
function renderSectionBody(section) {
|
|
19851
19910
|
return [
|
|
19852
19911
|
renderSectionComment(section),
|
|
19853
|
-
...section.summary !== undefined ? ["<!-- c4a:summary -->", section.summary
|
|
19912
|
+
...section.summary !== undefined ? ["<!-- c4a:summary -->", renderSummaryText(section.summary), "<!-- /c4a:summary -->", ""] : [],
|
|
19854
19913
|
section.content.trim(),
|
|
19855
|
-
...section.raw !== undefined ? ["", "<!-- c4a:raw -->", section.raw.trim(), "<!-- /c4a:raw -->"] : [],
|
|
19856
19914
|
"<!-- /c4a:section -->"
|
|
19857
19915
|
].join(`
|
|
19858
19916
|
`);
|
|
@@ -27004,6 +27062,20 @@ async function readCurrentSourceOwnershipRecord(ctxDir) {
|
|
|
27004
27062
|
async function readCurrentSourceOwnership(ctxDir) {
|
|
27005
27063
|
return (await readCurrentSourceOwnershipRecord(ctxDir))?.ownership ?? null;
|
|
27006
27064
|
}
|
|
27065
|
+
async function readFreshCurrentSourceOwnership(ctxDir) {
|
|
27066
|
+
const ownership = await readCurrentSourceOwnership(ctxDir);
|
|
27067
|
+
if (ownership === null)
|
|
27068
|
+
return null;
|
|
27069
|
+
const currentHashes = await latestSnapshotHashes(ctxDir);
|
|
27070
|
+
const stale = staleOwnershipSourceIds(ownership, currentHashes);
|
|
27071
|
+
if (stale.length === 0)
|
|
27072
|
+
return ownership;
|
|
27073
|
+
const refreshed = await refreshStaleSourceOwnership(ctxDir, ownership);
|
|
27074
|
+
if (refreshed === null)
|
|
27075
|
+
throw sourceOwnershipStaleError(stale);
|
|
27076
|
+
await writeCurrentSourceOwnership(ctxDir, refreshed);
|
|
27077
|
+
return refreshed;
|
|
27078
|
+
}
|
|
27007
27079
|
function publishedSourceOwnershipSummary(record) {
|
|
27008
27080
|
return {
|
|
27009
27081
|
source: "finalized-ownership",
|
|
@@ -27155,18 +27227,9 @@ function sourceOwnershipStaleError(sourceIds) {
|
|
|
27155
27227
|
});
|
|
27156
27228
|
}
|
|
27157
27229
|
async function assertNoUnownedSourceOwnership(ctxDir) {
|
|
27158
|
-
|
|
27230
|
+
const ownership = await readFreshCurrentSourceOwnership(ctxDir);
|
|
27159
27231
|
if (ownership === null)
|
|
27160
27232
|
return;
|
|
27161
|
-
const currentHashes = await latestSnapshotHashes(ctxDir);
|
|
27162
|
-
const stale = staleOwnershipSourceIds(ownership, currentHashes);
|
|
27163
|
-
if (stale.length > 0) {
|
|
27164
|
-
const refreshed = await refreshStaleSourceOwnership(ctxDir, ownership);
|
|
27165
|
-
if (refreshed === null)
|
|
27166
|
-
throw sourceOwnershipStaleError(stale);
|
|
27167
|
-
ownership = refreshed;
|
|
27168
|
-
await writeCurrentSourceOwnership(ctxDir, refreshed);
|
|
27169
|
-
}
|
|
27170
27233
|
const unowned = ownership.sources.flatMap((source2) => source2.blocks.filter((block) => block.status === "unowned" && block.reason !== "no-accepted-heading-owner-after-refresh").map((block) => `${source2.source_id}:${block.file}:L${block.line_start}-L${block.line_end}`));
|
|
27171
27234
|
if (unowned.length === 0)
|
|
27172
27235
|
return;
|
|
@@ -28550,6 +28613,29 @@ function pushNodeSourceStateIssues(node2, sourceStatuses, alignedPendingCompileS
|
|
|
28550
28613
|
});
|
|
28551
28614
|
}
|
|
28552
28615
|
}
|
|
28616
|
+
function staleSourceSnapshot(input) {
|
|
28617
|
+
const current = parseVersionedSourceId(input.sourceEntry).snapshotHash;
|
|
28618
|
+
if (current === undefined || input.source === undefined)
|
|
28619
|
+
return null;
|
|
28620
|
+
const latest = selectLatestSnapshot(input.source.snapshots);
|
|
28621
|
+
if (latest === null)
|
|
28622
|
+
return null;
|
|
28623
|
+
const latestHash = shortSnapshotHash(latest.content_hash);
|
|
28624
|
+
return current === latestHash ? null : {
|
|
28625
|
+
current_snapshot_hash: current,
|
|
28626
|
+
latest_snapshot_hash: latestHash
|
|
28627
|
+
};
|
|
28628
|
+
}
|
|
28629
|
+
function pushStaleSourceSnapshotIssue(input) {
|
|
28630
|
+
input.issues.push({
|
|
28631
|
+
severity: "error",
|
|
28632
|
+
code: "stale-node-source-snapshot",
|
|
28633
|
+
message: `section source_ref "${input.section.source_ref}" cannot resolve because node.sources[] points to stale snapshot "${input.sourceEntry}" (latest @${input.stale.latest_snapshot_hash})`,
|
|
28634
|
+
path: input.node.relativePath,
|
|
28635
|
+
slug: input.node.parsed.node.id,
|
|
28636
|
+
sectionId: input.section.id
|
|
28637
|
+
});
|
|
28638
|
+
}
|
|
28553
28639
|
async function pushSectionReferenceIssues(input) {
|
|
28554
28640
|
const { node: node2, section, issues } = input;
|
|
28555
28641
|
for (const target of section.refers_to_nodes ?? []) {
|
|
@@ -28616,6 +28702,11 @@ async function pushSectionReferenceIssues(input) {
|
|
|
28616
28702
|
const source2 = input.sourcesById.get(sourceId);
|
|
28617
28703
|
if (source2?.status !== "active")
|
|
28618
28704
|
return;
|
|
28705
|
+
const stale = staleSourceSnapshot({ sourceEntry, source: source2 });
|
|
28706
|
+
if (stale !== null) {
|
|
28707
|
+
pushStaleSourceSnapshotIssue({ issues, node: node2, section, sourceEntry, stale });
|
|
28708
|
+
return;
|
|
28709
|
+
}
|
|
28619
28710
|
const canonicalSourceRef = await canonicalizeHashedSourceRef({
|
|
28620
28711
|
ctxDir: input.ctxDir,
|
|
28621
28712
|
sourceRef: section.source_ref,
|
|
@@ -28979,8 +29070,7 @@ function hasUrlReferenceLabel(text) {
|
|
|
28979
29070
|
return regexMatches(EN_URL_REFERENCE_LABEL_RE, text) || regexMatches(CJK_URL_REFERENCE_LABEL_RE, text);
|
|
28980
29071
|
}
|
|
28981
29072
|
function diagnoseUrlReferencePreservation(input) {
|
|
28982
|
-
const proposedText = `${input.
|
|
28983
|
-
${input.content}
|
|
29073
|
+
const proposedText = `${input.content}
|
|
28984
29074
|
${input.detail ?? ""}`;
|
|
28985
29075
|
const citedUrls = evidenceUrlsIn(input.citedText);
|
|
28986
29076
|
const proposedUrls = evidenceUrlsIn(proposedText);
|
|
@@ -29042,14 +29132,17 @@ function supportLexicalOverlap(content, citedText) {
|
|
|
29042
29132
|
};
|
|
29043
29133
|
}
|
|
29044
29134
|
function hardTermPresent(term, citedText, citedHardTerms) {
|
|
29045
|
-
|
|
29135
|
+
const variants = uniqueSorted([term, term.replace(TRAILING_HARD_TERM_PUNCTUATION_RE, "")]);
|
|
29136
|
+
if (variants.some((variant) => citedHardTerms.has(variant) || normalizedToken(citedText).includes(variant))) {
|
|
29046
29137
|
return true;
|
|
29138
|
+
}
|
|
29047
29139
|
const normalizedCited = normalizedToken(citedText);
|
|
29048
|
-
const
|
|
29140
|
+
const normalizedTerm = variants[0] ?? term;
|
|
29141
|
+
const slashParts = normalizedTerm.split("/").map(normalizedToken).filter((part) => part.length > 0);
|
|
29049
29142
|
if (slashParts.length > 1) {
|
|
29050
29143
|
return slashParts.every((part) => citedHardTerms.has(part) || normalizedCited.includes(part));
|
|
29051
29144
|
}
|
|
29052
|
-
const hyphenParts =
|
|
29145
|
+
const hyphenParts = normalizedTerm.includes("-") && !/[0-9._/:#]/u.test(normalizedTerm) ? normalizedTerm.split("-").map(normalizedToken).filter((part) => part.length > 1) : [];
|
|
29053
29146
|
return hyphenParts.length > 1 && hyphenParts.every((part) => citedHardTerms.has(part) || normalizedCited.includes(part));
|
|
29054
29147
|
}
|
|
29055
29148
|
function thresholdsForKind(kind) {
|
|
@@ -29127,12 +29220,13 @@ function sourceTextSupportDiagnostic(content, citedText, thresholds = DEFAULT_TH
|
|
|
29127
29220
|
};
|
|
29128
29221
|
}
|
|
29129
29222
|
function sourceSectionSupportDiagnostic(input) {
|
|
29130
|
-
const summary = typeof input.summary === "string" ? input.summary.trim() : "";
|
|
29131
29223
|
const detail = typeof input.detail === "string" ? input.detail.trim() : "";
|
|
29132
|
-
const content =
|
|
29133
|
-
${input.content}` : input.content;
|
|
29224
|
+
const content = input.content;
|
|
29134
29225
|
if (detail.length === 0) {
|
|
29135
|
-
return
|
|
29226
|
+
return {
|
|
29227
|
+
...sourceTextSupportDiagnostic(content, input.citedText, thresholdsForKind(input.kind)),
|
|
29228
|
+
checkedFields: ["content"]
|
|
29229
|
+
};
|
|
29136
29230
|
}
|
|
29137
29231
|
const thresholds = thresholdsForKind(input.kind);
|
|
29138
29232
|
const contentDiagnostic = sourceTextSupportDiagnostic(content, input.citedText, thresholds);
|
|
@@ -29141,6 +29235,7 @@ ${input.content}` : input.content;
|
|
|
29141
29235
|
${detail}`, input.citedText, thresholds);
|
|
29142
29236
|
const detailAware = {
|
|
29143
29237
|
...combined,
|
|
29238
|
+
checkedFields: ["content", "detail"],
|
|
29144
29239
|
detailAware: true,
|
|
29145
29240
|
detailVerdict: detailDiagnostic.verdict
|
|
29146
29241
|
};
|
|
@@ -29178,11 +29273,13 @@ function sourceTextSupportsContent(content, citedText) {
|
|
|
29178
29273
|
return sourceTextSupportDiagnostic(content, citedText).verdict !== "unsupported";
|
|
29179
29274
|
}
|
|
29180
29275
|
function formatSupportDiagnostic(diagnostic) {
|
|
29276
|
+
const basis = diagnostic.checkedFields !== undefined && diagnostic.checkedFields.length > 0 ? diagnostic.checkedFields.join("+") : diagnostic.detailAware === true ? "content+detail" : "content";
|
|
29181
29277
|
const parts = [
|
|
29182
|
-
`support=${diagnostic.verdict}; lexical overlap ${diagnostic.matchedTermCount}/${diagnostic.contentTermCount} terms; requires ${diagnostic.requiredTermCount}/${diagnostic.contentTermCount}
|
|
29278
|
+
`support=${diagnostic.verdict}; lexical overlap ${diagnostic.matchedTermCount}/${diagnostic.contentTermCount} terms; requires ${diagnostic.requiredTermCount}/${diagnostic.contentTermCount}`,
|
|
29279
|
+
`basis=${basis}`
|
|
29183
29280
|
];
|
|
29184
29281
|
if (diagnostic.detailAware === true) {
|
|
29185
|
-
parts.push(`
|
|
29282
|
+
parts.push(`detail=${diagnostic.detailVerdict ?? "unknown"}`);
|
|
29186
29283
|
}
|
|
29187
29284
|
if (diagnostic.missingContentTerms.length > 0) {
|
|
29188
29285
|
parts.push(`content terms not found in cited raw text: ${diagnostic.missingContentTerms.join(", ")}`);
|
|
@@ -29224,12 +29321,16 @@ async function findAutoNarrowedSourceRefs(input) {
|
|
|
29224
29321
|
});
|
|
29225
29322
|
if (resolved === null)
|
|
29226
29323
|
continue;
|
|
29324
|
+
const { supportText } = supportTextWithHeadingContext({
|
|
29325
|
+
citedText: resolved.cited_text,
|
|
29326
|
+
blocks: resolved.blocks
|
|
29327
|
+
});
|
|
29227
29328
|
const diagnostic = sourceSectionSupportDiagnostic({
|
|
29228
29329
|
kind: input.section.kind,
|
|
29229
29330
|
summary: input.section.summary,
|
|
29230
29331
|
content: input.section.content,
|
|
29231
29332
|
detail: input.section.detail,
|
|
29232
|
-
citedText:
|
|
29333
|
+
citedText: supportText
|
|
29233
29334
|
});
|
|
29234
29335
|
if (!isStrictlySupported(diagnostic))
|
|
29235
29336
|
continue;
|
|
@@ -29267,6 +29368,21 @@ function evidenceBlocksLineRange(blocks) {
|
|
|
29267
29368
|
function evidenceBlocksLocatorId(blocks) {
|
|
29268
29369
|
return blocks.map((block) => block.block_locator_id).filter((value) => typeof value === "string" && value.length > 0).join(" + ");
|
|
29269
29370
|
}
|
|
29371
|
+
function evidenceHeadingContext(blocks) {
|
|
29372
|
+
const headings = blocks.flatMap((block) => block.heading_path ?? []).map((heading) => heading.trim()).filter((heading) => heading.length > 0 && heading !== "document");
|
|
29373
|
+
return [...new Set(headings)];
|
|
29374
|
+
}
|
|
29375
|
+
function supportTextWithHeadingContext(input) {
|
|
29376
|
+
const headingContext = evidenceHeadingContext(input.blocks);
|
|
29377
|
+
if (headingContext.length === 0)
|
|
29378
|
+
return { supportText: input.citedText };
|
|
29379
|
+
return {
|
|
29380
|
+
supportText: `${headingContext.join(`
|
|
29381
|
+
`)}
|
|
29382
|
+
${input.citedText}`,
|
|
29383
|
+
headingContext
|
|
29384
|
+
};
|
|
29385
|
+
}
|
|
29270
29386
|
async function sourceRefForBlock(input) {
|
|
29271
29387
|
return sourceRefForRange({
|
|
29272
29388
|
ctxDir: input.ctxDir,
|
|
@@ -29277,12 +29393,16 @@ async function sourceRefForBlock(input) {
|
|
|
29277
29393
|
async function rankEvidenceBlockCandidates(input) {
|
|
29278
29394
|
const ranked = (await Promise.all(input.blocks.map(async (block) => {
|
|
29279
29395
|
const citedText = sourceRefRangeText(input.raw, block.line_start, block.line_end);
|
|
29396
|
+
const { supportText } = supportTextWithHeadingContext({
|
|
29397
|
+
citedText,
|
|
29398
|
+
blocks: [block]
|
|
29399
|
+
});
|
|
29280
29400
|
const diagnostic = sourceSectionSupportDiagnostic({
|
|
29281
29401
|
kind: input.section.kind,
|
|
29282
29402
|
summary: input.section.summary,
|
|
29283
29403
|
content: input.section.content,
|
|
29284
29404
|
detail: input.section.detail,
|
|
29285
|
-
citedText
|
|
29405
|
+
citedText: supportText
|
|
29286
29406
|
});
|
|
29287
29407
|
if (diagnostic.matchedTermCount === 0 && diagnostic.overlapRatio === 0)
|
|
29288
29408
|
return null;
|
|
@@ -29320,6 +29440,10 @@ async function diagnoseSectionSourceSupport(input) {
|
|
|
29320
29440
|
throw new Error(`${input.action} source_ref "${input.section.source_ref}" does not point to an active source`);
|
|
29321
29441
|
}
|
|
29322
29442
|
const citedText = resolved.cited_text;
|
|
29443
|
+
const { supportText, headingContext } = supportTextWithHeadingContext({
|
|
29444
|
+
citedText,
|
|
29445
|
+
blocks: resolved.blocks
|
|
29446
|
+
});
|
|
29323
29447
|
const alias = `src-${resolved.alias_index}`;
|
|
29324
29448
|
const rawBlocks = resolved.raw_text !== null ? extractRawBlocks(resolved.raw_text) : [];
|
|
29325
29449
|
const evidenceBlock = {
|
|
@@ -29332,7 +29456,7 @@ async function diagnoseSectionSourceSupport(input) {
|
|
|
29332
29456
|
summary: input.section.summary,
|
|
29333
29457
|
content: input.section.content,
|
|
29334
29458
|
detail: input.section.detail,
|
|
29335
|
-
citedText
|
|
29459
|
+
citedText: supportText
|
|
29336
29460
|
});
|
|
29337
29461
|
const evidenceBlockCandidates = resolved.raw_text !== null ? await rankEvidenceBlockCandidates({
|
|
29338
29462
|
ctxDir: input.ctxDir,
|
|
@@ -29347,6 +29471,7 @@ async function diagnoseSectionSourceSupport(input) {
|
|
|
29347
29471
|
sourceId,
|
|
29348
29472
|
sourceRef: resolved.source_ref,
|
|
29349
29473
|
citedText,
|
|
29474
|
+
...headingContext !== undefined ? { headingContext } : {},
|
|
29350
29475
|
diagnostic,
|
|
29351
29476
|
evidenceBlock,
|
|
29352
29477
|
...evidenceBlockCandidates !== undefined ? { evidenceBlockCandidates } : {}
|
|
@@ -29365,11 +29490,11 @@ function weakSourceSupportGuidance(action, verdict) {
|
|
|
29365
29490
|
if (verdict !== "weak")
|
|
29366
29491
|
return "";
|
|
29367
29492
|
if (action === "keep_separate") {
|
|
29368
|
-
return " Key facts match, but support is weak; ask the user to confirm the
|
|
29493
|
+
return " Key facts match, but support is weak; ask the user to confirm the content compression during review, then apply the final keep_separate decision marked decided_by: user. Auto mode or general permission to continue is not confirmation.";
|
|
29369
29494
|
}
|
|
29370
29495
|
return " Key facts match, but this action rewrites or reanchors existing knowledge and requires direct support; choose source_ref/source_refs from the prepared evidence, split the claim, or ask the user before choosing a different final action.";
|
|
29371
29496
|
}
|
|
29372
|
-
var DEFAULT_THRESHOLDS, CJK_ONLY_RE, CJK_CHAR_RE, URL_RE2, TRAILING_URL_PUNCTUATION_RE, TRACKING_QUERY_PARAM_RE, EN_URL_REFERENCE_LABEL_RE, CJK_URL_REFERENCE_LABEL_RE, CONSTRAINT_PATTERNS, PLACEHOLDER_ANCHOR_PARTS;
|
|
29497
|
+
var DEFAULT_THRESHOLDS, CJK_ONLY_RE, CJK_CHAR_RE, URL_RE2, TRAILING_URL_PUNCTUATION_RE, TRAILING_HARD_TERM_PUNCTUATION_RE, TRACKING_QUERY_PARAM_RE, EN_URL_REFERENCE_LABEL_RE, CJK_URL_REFERENCE_LABEL_RE, CONSTRAINT_PATTERNS, PLACEHOLDER_ANCHOR_PARTS;
|
|
29373
29498
|
var init_sourceSupport = __esm(() => {
|
|
29374
29499
|
init_normalize();
|
|
29375
29500
|
init_sectionDetail();
|
|
@@ -29382,6 +29507,7 @@ var init_sourceSupport = __esm(() => {
|
|
|
29382
29507
|
CJK_CHAR_RE = /[\u4e00-\u9fff]/gu;
|
|
29383
29508
|
URL_RE2 = /https?:\/\/[^\s)\]}>"')】》」』,。;:!?]+/giu;
|
|
29384
29509
|
TRAILING_URL_PUNCTUATION_RE = /[.,;:!?)\]\}>"',。;:!?)】》」』]+$/u;
|
|
29510
|
+
TRAILING_HARD_TERM_PUNCTUATION_RE = /[.,;:!?)\]\}>"',。;:!?)】》」』]+$/u;
|
|
29385
29511
|
TRACKING_QUERY_PARAM_RE = /^(?:utm_|fbclid$|gclid$|mc_cid$|mc_eid$)/iu;
|
|
29386
29512
|
EN_URL_REFERENCE_LABEL_RE = /\b(?:url|urls|link|links|doc|docs|document|documents|documentation|reference|references|page|pages|guide|guides|entry|entries|website|official|source|sources)\b/giu;
|
|
29387
29513
|
CJK_URL_REFERENCE_LABEL_RE = /文档|链接|入口|参考|资料|页面|地址|官网|官方|指南|来源|网址/gu;
|
|
@@ -32069,12 +32195,13 @@ async function upsertCoverageCandidates(input) {
|
|
|
32069
32195
|
dispositions: existing?.dispositions ?? []
|
|
32070
32196
|
});
|
|
32071
32197
|
}
|
|
32198
|
+
const candidates = await adjustMaterializedCandidates(input.ctxDir, [...byId.values()]);
|
|
32072
32199
|
await writeCoverageStateFile(input.ctxDir, {
|
|
32073
32200
|
schema_version: COVERAGE_STATE_SCHEMA_VERSION,
|
|
32074
32201
|
updated_at: (input.now ?? new Date).toISOString(),
|
|
32075
|
-
candidates
|
|
32202
|
+
candidates
|
|
32076
32203
|
});
|
|
32077
|
-
return summarizeCoverageCandidates(
|
|
32204
|
+
return summarizeCoverageCandidates(candidates, 0, pruned.staleDropped);
|
|
32078
32205
|
}
|
|
32079
32206
|
function dispositionError(code, message) {
|
|
32080
32207
|
const hint = {
|
|
@@ -33208,16 +33335,13 @@ function urlsIn(text) {
|
|
|
33208
33335
|
}
|
|
33209
33336
|
function proposedTextForAction(action) {
|
|
33210
33337
|
if (action.op === "add")
|
|
33211
|
-
return `${action.
|
|
33212
|
-
${action.content}
|
|
33338
|
+
return `${action.content}
|
|
33213
33339
|
${action.detail ?? ""}`;
|
|
33214
33340
|
if (action.op === "update")
|
|
33215
|
-
return `${action.
|
|
33216
|
-
${action.content ?? ""}
|
|
33341
|
+
return `${action.content ?? ""}
|
|
33217
33342
|
${action.detail ?? ""}`;
|
|
33218
33343
|
if (action.op === "supersede")
|
|
33219
|
-
return `${action.new.
|
|
33220
|
-
${action.new.content}
|
|
33344
|
+
return `${action.new.content}
|
|
33221
33345
|
${action.new.detail ?? ""}`;
|
|
33222
33346
|
return "";
|
|
33223
33347
|
}
|
|
@@ -34010,8 +34134,24 @@ async function contentForBlock(ctxDir, source2, block, sourceEntry, options = {}
|
|
|
34010
34134
|
const fullQuote = lines.slice(start2 - 1, end).join(`
|
|
34011
34135
|
`).trim() || block.text_preview || "";
|
|
34012
34136
|
const compactQuote = fullQuote.slice(0, MAX_SNIPPET_CHARS);
|
|
34137
|
+
if (options.fullText === true) {
|
|
34138
|
+
const blockLines = lines.slice(start2 - 1, end);
|
|
34139
|
+
const page = fullTextPageForBlock({
|
|
34140
|
+
nodeSlug: options.nodeSlug ?? "",
|
|
34141
|
+
blockId: block.block_id,
|
|
34142
|
+
blockLines,
|
|
34143
|
+
blockRawStartLine: start2,
|
|
34144
|
+
...options.lineRange !== undefined ? { requestedRange: options.lineRange } : {}
|
|
34145
|
+
});
|
|
34146
|
+
return {
|
|
34147
|
+
quote: page.quote.length > 0 ? page.quote : compactQuote,
|
|
34148
|
+
compactQuote,
|
|
34149
|
+
fullTextPage: page.info,
|
|
34150
|
+
...raw.note !== undefined ? { note: raw.note } : {}
|
|
34151
|
+
};
|
|
34152
|
+
}
|
|
34013
34153
|
return {
|
|
34014
|
-
quote:
|
|
34154
|
+
quote: compactQuote,
|
|
34015
34155
|
compactQuote,
|
|
34016
34156
|
...raw.note !== undefined ? { note: raw.note } : {}
|
|
34017
34157
|
};
|
|
@@ -34044,6 +34184,7 @@ function toSnippet(input) {
|
|
|
34044
34184
|
block_id: input.entry.block_id,
|
|
34045
34185
|
...input.entry.block_locator_id !== undefined ? { block_locator_id: input.entry.block_locator_id } : {},
|
|
34046
34186
|
...input.entry.source_ref !== undefined ? { source_ref: input.entry.source_ref } : {},
|
|
34187
|
+
...input.entry.full_text_page !== undefined ? { full_text_page: input.entry.full_text_page } : {},
|
|
34047
34188
|
...input.sourceType !== undefined ? { source_type: input.sourceType } : {},
|
|
34048
34189
|
...input.note !== undefined ? {
|
|
34049
34190
|
note_intent: input.note.intent,
|
|
@@ -34076,6 +34217,117 @@ function graphContext(edges, slug) {
|
|
|
34076
34217
|
function tokenEstimate2(value) {
|
|
34077
34218
|
return Math.ceil(value.length / 4);
|
|
34078
34219
|
}
|
|
34220
|
+
function lineRangeText(range) {
|
|
34221
|
+
return `${range.start}:${range.end}`;
|
|
34222
|
+
}
|
|
34223
|
+
function requestFullTextPageCommand(slug, blockId, range) {
|
|
34224
|
+
return `context compile --context ${slug} --request-full-text ${blockId} --request-full-text-range ${range} --format json`;
|
|
34225
|
+
}
|
|
34226
|
+
function isFenceLine(line) {
|
|
34227
|
+
return /^\s*(```|~~~)/u.test(line);
|
|
34228
|
+
}
|
|
34229
|
+
function isTableLine(line) {
|
|
34230
|
+
return /^\s*\|.*\|\s*$/u.test(line);
|
|
34231
|
+
}
|
|
34232
|
+
function isMarkdownHeading(line) {
|
|
34233
|
+
return /^\s{0,3}#{1,6}\s+\S/u.test(line);
|
|
34234
|
+
}
|
|
34235
|
+
function isNaturalBreak(line, nextLine, inFenceAfterLine) {
|
|
34236
|
+
if (line.trim() === "")
|
|
34237
|
+
return true;
|
|
34238
|
+
if (isFenceLine(line) && !inFenceAfterLine)
|
|
34239
|
+
return true;
|
|
34240
|
+
if (inFenceAfterLine)
|
|
34241
|
+
return false;
|
|
34242
|
+
if (nextLine !== undefined && isMarkdownHeading(nextLine))
|
|
34243
|
+
return true;
|
|
34244
|
+
if (isTableLine(line))
|
|
34245
|
+
return true;
|
|
34246
|
+
return false;
|
|
34247
|
+
}
|
|
34248
|
+
function selectFullTextPageEnd(lines, startIndex) {
|
|
34249
|
+
if (startIndex >= lines.length)
|
|
34250
|
+
return { endIndex: lines.length };
|
|
34251
|
+
if (tokenEstimate2(lines[startIndex] ?? "") > FULL_TEXT_PAGE_HARD_TOKENS) {
|
|
34252
|
+
return {
|
|
34253
|
+
endIndex: startIndex + 1,
|
|
34254
|
+
warning: "single-line page exceeds the target token budget; content was kept intact at the line boundary"
|
|
34255
|
+
};
|
|
34256
|
+
}
|
|
34257
|
+
let inFence = false;
|
|
34258
|
+
let targetEnd;
|
|
34259
|
+
for (let index = startIndex;index < lines.length; index += 1) {
|
|
34260
|
+
const line = lines[index] ?? "";
|
|
34261
|
+
if (isFenceLine(line))
|
|
34262
|
+
inFence = !inFence;
|
|
34263
|
+
const pageText = lines.slice(startIndex, index + 1).join(`
|
|
34264
|
+
`);
|
|
34265
|
+
const tokens = tokenEstimate2(pageText);
|
|
34266
|
+
const nextLine = lines[index + 1];
|
|
34267
|
+
if (tokens >= FULL_TEXT_PAGE_TARGET_TOKENS && targetEnd === undefined && !inFence) {
|
|
34268
|
+
targetEnd = index + 1;
|
|
34269
|
+
}
|
|
34270
|
+
if (tokens >= FULL_TEXT_PAGE_MIN_TOKENS && isNaturalBreak(line, nextLine, inFence)) {
|
|
34271
|
+
return { endIndex: index + 1 };
|
|
34272
|
+
}
|
|
34273
|
+
if (tokens >= FULL_TEXT_PAGE_MAX_TOKENS && !inFence) {
|
|
34274
|
+
return { endIndex: targetEnd ?? index + 1 };
|
|
34275
|
+
}
|
|
34276
|
+
if (tokens >= FULL_TEXT_PAGE_HARD_TOKENS) {
|
|
34277
|
+
return {
|
|
34278
|
+
endIndex: index + 1,
|
|
34279
|
+
...inFence ? { warning: "page reached the hard token budget inside a fenced block; content was kept intact at the line boundary" } : {}
|
|
34280
|
+
};
|
|
34281
|
+
}
|
|
34282
|
+
}
|
|
34283
|
+
return { endIndex: lines.length };
|
|
34284
|
+
}
|
|
34285
|
+
function normalizeRequestedFullTextRange(range, lineCount) {
|
|
34286
|
+
if (lineCount === 0)
|
|
34287
|
+
return { start: 1, end: 1 };
|
|
34288
|
+
if (range === undefined)
|
|
34289
|
+
return { start: 1, end: lineCount };
|
|
34290
|
+
if (range.start < 1 || range.end < range.start || range.start > lineCount) {
|
|
34291
|
+
throw new ContextError(ExitCode.UserError, `request_full_text range ${lineRangeText(range)} is outside the requested block`, {
|
|
34292
|
+
category: ErrorCategory.UserInputInvalid,
|
|
34293
|
+
agent_hints: [{
|
|
34294
|
+
code: "compile-request-full-text-invalid",
|
|
34295
|
+
severity: "error",
|
|
34296
|
+
message: "request_full_text range must use block-relative line numbers inside the selected block.",
|
|
34297
|
+
path: "request_full_text.range",
|
|
34298
|
+
reason_code: "range-out-of-bounds",
|
|
34299
|
+
next_action: "Use full_text_page.next_range from the previous response, or retry without --request-full-text-range."
|
|
34300
|
+
}]
|
|
34301
|
+
});
|
|
34302
|
+
}
|
|
34303
|
+
return { start: range.start, end: Math.min(range.end, lineCount) };
|
|
34304
|
+
}
|
|
34305
|
+
function fullTextPageForBlock(input) {
|
|
34306
|
+
const requested = normalizeRequestedFullTextRange(input.requestedRange, input.blockLines.length);
|
|
34307
|
+
const shouldAutoPage = input.requestedRange !== undefined || tokenEstimate2(input.blockLines.slice(requested.start - 1, requested.end).join(`
|
|
34308
|
+
`)) > FULL_TEXT_PAGE_MAX_TOKENS;
|
|
34309
|
+
const startIndex = requested.start - 1;
|
|
34310
|
+
const selected = shouldAutoPage ? selectFullTextPageEnd(input.blockLines.slice(0, requested.end), startIndex) : { endIndex: requested.end };
|
|
34311
|
+
const relativeEnd = Math.max(requested.start, Math.min(selected.endIndex, requested.end));
|
|
34312
|
+
const quote = input.blockLines.slice(startIndex, relativeEnd).join(`
|
|
34313
|
+
`).trim();
|
|
34314
|
+
const hasMore = relativeEnd < input.blockLines.length;
|
|
34315
|
+
const nextRange = hasMore ? `${relativeEnd + 1}:${Math.min(input.blockLines.length, relativeEnd + (relativeEnd - requested.start + 1))}` : undefined;
|
|
34316
|
+
const range = `${requested.start}:${relativeEnd}`;
|
|
34317
|
+
const info2 = {
|
|
34318
|
+
block_id: input.blockId,
|
|
34319
|
+
status: hasMore || input.requestedRange !== undefined ? "paged" : "full",
|
|
34320
|
+
range,
|
|
34321
|
+
raw_line_range: [input.blockRawStartLine + requested.start - 1, input.blockRawStartLine + relativeEnd - 1],
|
|
34322
|
+
block_line_count: input.blockLines.length,
|
|
34323
|
+
token_estimate: tokenEstimate2(quote),
|
|
34324
|
+
has_more: hasMore,
|
|
34325
|
+
...nextRange !== undefined ? { next_range: nextRange } : {},
|
|
34326
|
+
...nextRange !== undefined && input.nodeSlug.length > 0 ? { next_command: requestFullTextPageCommand(input.nodeSlug, input.blockId, nextRange) } : {},
|
|
34327
|
+
...selected.warning !== undefined ? { warning: selected.warning } : {}
|
|
34328
|
+
};
|
|
34329
|
+
return { quote, info: info2 };
|
|
34330
|
+
}
|
|
34079
34331
|
function requestableFullTextBlockIds(ownership, slug) {
|
|
34080
34332
|
return ownership.sources.flatMap((source2) => source2.blocks.filter((block) => isPrimaryEvidence(block, slug) || isSecondaryShared(block, slug)).map((block) => block.block_id));
|
|
34081
34333
|
}
|
|
@@ -34129,9 +34381,44 @@ function invalidRequestFullTextDetails(input) {
|
|
|
34129
34381
|
reasonCode: "not-visible-evidence"
|
|
34130
34382
|
};
|
|
34131
34383
|
}
|
|
34384
|
+
function fullTextPagingHints(input) {
|
|
34385
|
+
const pages = input.snippets.flatMap((snippet) => snippet.full_text_page?.has_more === true ? [snippet.full_text_page] : []);
|
|
34386
|
+
if (pages.length === 0 && input.addedTokens <= input.tokenGrowthBudget)
|
|
34387
|
+
return [];
|
|
34388
|
+
return [{
|
|
34389
|
+
code: "compile-request-full-text-paged",
|
|
34390
|
+
severity: "info",
|
|
34391
|
+
message: pages.length > 0 ? "request_full_text returned line-bounded page(s) for long evidence instead of failing the NodeContext token budget." : "request_full_text expansion exceeded the historical growth budget but stayed within page-bounded output.",
|
|
34392
|
+
target_node: input.nodeSlug,
|
|
34393
|
+
next_action: pages.length > 0 ? "Use raw_snippets[].full_text_page.next_command to continue reading the same block; cite only source_refs already present in NodeContext." : "Continue with the returned NodeContext.",
|
|
34394
|
+
...pages[0]?.next_command !== undefined ? { command: pages[0].next_command } : {},
|
|
34395
|
+
diagnostics: {
|
|
34396
|
+
added_tokens: input.addedTokens,
|
|
34397
|
+
historical_growth_budget: input.tokenGrowthBudget,
|
|
34398
|
+
page_count_with_more: pages.length,
|
|
34399
|
+
pages: pages.map((page) => ({
|
|
34400
|
+
block_id: page.block_id,
|
|
34401
|
+
range: page.range,
|
|
34402
|
+
raw_line_range: page.raw_line_range,
|
|
34403
|
+
token_estimate: page.token_estimate,
|
|
34404
|
+
next_range: page.next_range,
|
|
34405
|
+
next_command: page.next_command
|
|
34406
|
+
}))
|
|
34407
|
+
}
|
|
34408
|
+
}];
|
|
34409
|
+
}
|
|
34132
34410
|
function validateExpandRequest(input) {
|
|
34133
34411
|
const requested = [...new Set(input.request.blockIds)].filter((blockId) => blockId.length > 0);
|
|
34134
34412
|
const availableBlockIds = requestableFullTextBlockIds(input.ownership, input.slug);
|
|
34413
|
+
if (input.request.lineRange !== undefined && requested.length !== 1) {
|
|
34414
|
+
throw requestFullTextError({
|
|
34415
|
+
slug: input.slug,
|
|
34416
|
+
message: "request_full_text range requires exactly one --request-full-text block id",
|
|
34417
|
+
reasonCode: "range-requires-single-block",
|
|
34418
|
+
availableBlockIds,
|
|
34419
|
+
requestedBlockIds: requested
|
|
34420
|
+
});
|
|
34421
|
+
}
|
|
34135
34422
|
if (requested.length > MAX_FULL_TEXT_REQUESTS) {
|
|
34136
34423
|
throw requestFullTextError({
|
|
34137
34424
|
slug: input.slug,
|
|
@@ -34187,7 +34474,10 @@ async function appendFinalizedBlock(input) {
|
|
|
34187
34474
|
const blockId = input.block.block_id;
|
|
34188
34475
|
const expanded = input.expandedBlockIds.has(blockId);
|
|
34189
34476
|
const fullText = primary || expanded;
|
|
34190
|
-
const content = await contentForBlock(input.ctxDir, input.source, input.block, input.sourceEntry, {
|
|
34477
|
+
const content = await contentForBlock(input.ctxDir, input.source, input.block, input.sourceEntry, {
|
|
34478
|
+
fullText: expanded,
|
|
34479
|
+
...expanded ? { lineRange: input.expandLineRange, nodeSlug: input.nodeSlug } : {}
|
|
34480
|
+
});
|
|
34191
34481
|
const quote = content.quote;
|
|
34192
34482
|
const compactPrefix = (input.block.context_prefix ?? input.block.text_preview ?? quote).replace(/\s+/g, " ").slice(0, MAX_CONTEXT_PREFIX_CHARS);
|
|
34193
34483
|
if (expanded) {
|
|
@@ -34213,6 +34503,7 @@ async function appendFinalizedBlock(input) {
|
|
|
34213
34503
|
ownership_reason: input.block.reason,
|
|
34214
34504
|
...input.block.primary_owner !== undefined ? { primary_owner: input.block.primary_owner } : {},
|
|
34215
34505
|
...input.block.owners !== undefined ? { owners: [...input.block.owners] } : {},
|
|
34506
|
+
...content.fullTextPage !== undefined ? { full_text_page: content.fullTextPage } : {},
|
|
34216
34507
|
...secondary && !expanded ? {
|
|
34217
34508
|
request_full_text: {
|
|
34218
34509
|
available: true,
|
|
@@ -34275,6 +34566,7 @@ async function buildNodeContextFromFinalizedOwnership(input) {
|
|
|
34275
34566
|
source: source2,
|
|
34276
34567
|
block,
|
|
34277
34568
|
expandedBlockIds,
|
|
34569
|
+
...input.options?.expand?.lineRange !== undefined ? { expandLineRange: input.options.expand.lineRange } : {},
|
|
34278
34570
|
fullTextTokenGrowth,
|
|
34279
34571
|
groups,
|
|
34280
34572
|
snippets,
|
|
@@ -34286,20 +34578,12 @@ async function buildNodeContextFromFinalizedOwnership(input) {
|
|
|
34286
34578
|
const addedTokens = fullTextTokenGrowth.reduce((sum, value) => sum + value, 0);
|
|
34287
34579
|
const baseTokens = Math.max(1, snippets.reduce((sum, snippet) => sum + tokenEstimate2(snippet.quote), 0) - addedTokens);
|
|
34288
34580
|
const tokenGrowthBudget = Math.max(MIN_CONTEXT_TOKEN_GROWTH_TOKENS, Math.ceil(baseTokens * MAX_CONTEXT_TOKEN_GROWTH_RATIO));
|
|
34289
|
-
|
|
34290
|
-
|
|
34291
|
-
|
|
34292
|
-
|
|
34293
|
-
|
|
34294
|
-
|
|
34295
|
-
requestedBlockIds: [...expandedBlockIds],
|
|
34296
|
-
repairOptions: [
|
|
34297
|
-
"Retry with fewer visible evidence blocks.",
|
|
34298
|
-
"Continue from the compact NodeContext snippet when it is enough.",
|
|
34299
|
-
"Use pending_ownership_challenge only if a secondary shared block should become owned/shared-primary evidence for this Node."
|
|
34300
|
-
]
|
|
34301
|
-
});
|
|
34302
|
-
}
|
|
34581
|
+
const pagingHints = fullTextPagingHints({
|
|
34582
|
+
nodeSlug: input.node.slug,
|
|
34583
|
+
snippets,
|
|
34584
|
+
addedTokens,
|
|
34585
|
+
tokenGrowthBudget
|
|
34586
|
+
});
|
|
34303
34587
|
return {
|
|
34304
34588
|
node: {
|
|
34305
34589
|
...input.node,
|
|
@@ -34312,10 +34596,11 @@ async function buildNodeContextFromFinalizedOwnership(input) {
|
|
|
34312
34596
|
finalized_ownership: {
|
|
34313
34597
|
source: "finalized-ownership",
|
|
34314
34598
|
groups
|
|
34315
|
-
}
|
|
34599
|
+
},
|
|
34600
|
+
...pagingHints.length > 0 ? { agent_hints: pagingHints } : {}
|
|
34316
34601
|
};
|
|
34317
34602
|
}
|
|
34318
|
-
var MAX_FULL_TEXT_REQUESTS = 3, MAX_CONTEXT_TOKEN_GROWTH_RATIO = 0.3, MIN_CONTEXT_TOKEN_GROWTH_TOKENS = 120, MAX_SNIPPET_CHARS = 1800, MAX_CONTEXT_PREFIX_CHARS = 320, NON_EVIDENCE_PLACEHOLDERS2;
|
|
34603
|
+
var MAX_FULL_TEXT_REQUESTS = 3, MAX_CONTEXT_TOKEN_GROWTH_RATIO = 0.3, MIN_CONTEXT_TOKEN_GROWTH_TOKENS = 120, MAX_SNIPPET_CHARS = 1800, MAX_CONTEXT_PREFIX_CHARS = 320, FULL_TEXT_PAGE_MIN_TOKENS = 600, FULL_TEXT_PAGE_TARGET_TOKENS = 800, FULL_TEXT_PAGE_MAX_TOKENS = 1000, FULL_TEXT_PAGE_HARD_TOKENS = 1200, NON_EVIDENCE_PLACEHOLDERS2;
|
|
34319
34604
|
var init_compileFinalizedContext = __esm(() => {
|
|
34320
34605
|
init_ref();
|
|
34321
34606
|
init_manifest();
|
|
@@ -34464,7 +34749,7 @@ async function readCompileAlignNodes(ctxDir) {
|
|
|
34464
34749
|
const node2 = compileAlignNodeFromKnowledge(located.parsed.node);
|
|
34465
34750
|
return [node2.slug, node2];
|
|
34466
34751
|
}));
|
|
34467
|
-
const finalizedOwnership = await
|
|
34752
|
+
const finalizedOwnership = await readFreshCurrentSourceOwnership(ctxDir);
|
|
34468
34753
|
for (const node2 of finalizedOwnership?.nodes ?? []) {
|
|
34469
34754
|
const finalized = compileAlignNodeFromFinalized(node2);
|
|
34470
34755
|
const existing = bySlug.get(finalized.slug);
|
|
@@ -34496,7 +34781,7 @@ async function readCompileAlignEdges(ctxDir) {
|
|
|
34496
34781
|
for (const edge2 of await loadKnowledgeGraphEdges(ctxDir)) {
|
|
34497
34782
|
add(edge2.type, edge2.from, edge2.to, edge2.note);
|
|
34498
34783
|
}
|
|
34499
|
-
const finalizedOwnership = await
|
|
34784
|
+
const finalizedOwnership = await readFreshCurrentSourceOwnership(ctxDir);
|
|
34500
34785
|
for (const node2 of finalizedOwnership?.nodes ?? []) {
|
|
34501
34786
|
if (typeof node2.contains_parent === "string" && node2.contains_parent.length > 0) {
|
|
34502
34787
|
add("contains", node2.contains_parent, node2.slug);
|
|
@@ -34660,7 +34945,8 @@ async function readChangedBlockSnippet(ctxDir, block, source2, aliasIndex2) {
|
|
|
34660
34945
|
}
|
|
34661
34946
|
async function buildChangedNodeContext(ctxDir, slug, options = {}) {
|
|
34662
34947
|
const full = await buildFullNodeContextWithOptions(ctxDir, slug, {
|
|
34663
|
-
...options.requestFullTextBlockIds !== undefined ? { requestFullTextBlockIds: options.requestFullTextBlockIds } : {}
|
|
34948
|
+
...options.requestFullTextBlockIds !== undefined ? { requestFullTextBlockIds: options.requestFullTextBlockIds } : {},
|
|
34949
|
+
...options.requestFullTextRange !== undefined ? { requestFullTextRange: options.requestFullTextRange } : {}
|
|
34664
34950
|
});
|
|
34665
34951
|
const changes = options.changes ?? await computeCompileChanges({
|
|
34666
34952
|
ctxDir,
|
|
@@ -34739,7 +35025,7 @@ async function buildFullNodeContextWithOptions(ctxDir, slug, options = {}) {
|
|
|
34739
35025
|
} catch {
|
|
34740
35026
|
existing = undefined;
|
|
34741
35027
|
}
|
|
34742
|
-
const finalizedOwnership = await
|
|
35028
|
+
const finalizedOwnership = await readFreshCurrentSourceOwnership(ctxDir);
|
|
34743
35029
|
if (finalizedOwnership === null) {
|
|
34744
35030
|
throw new ContextError(ExitCode.WorkspaceStateError, "compile context requires finalized source ownership; run /context:align finalize first", {
|
|
34745
35031
|
category: ErrorCategory.WorkspaceStateInvalid,
|
|
@@ -34749,7 +35035,12 @@ async function buildFullNodeContextWithOptions(ctxDir, slug, options = {}) {
|
|
|
34749
35035
|
}
|
|
34750
35036
|
const sourcesFile = await loadSources(ctxDir);
|
|
34751
35037
|
const edges = await readCompileAlignEdges(ctxDir);
|
|
34752
|
-
const finalizedOptions = options.requestFullTextBlockIds !== undefined ? {
|
|
35038
|
+
const finalizedOptions = options.requestFullTextBlockIds !== undefined ? {
|
|
35039
|
+
expand: {
|
|
35040
|
+
blockIds: options.requestFullTextBlockIds,
|
|
35041
|
+
...options.requestFullTextRange !== undefined ? { lineRange: options.requestFullTextRange } : {}
|
|
35042
|
+
}
|
|
35043
|
+
} : {};
|
|
34753
35044
|
const baseContext = await buildNodeContextFromFinalizedOwnership({
|
|
34754
35045
|
ctxDir,
|
|
34755
35046
|
node: node2,
|
|
@@ -36146,6 +36437,7 @@ var init_agentHintRegistry = __esm(() => {
|
|
|
36146
36437
|
"compile-prepare-missing-draft",
|
|
36147
36438
|
"compile-prepare-missing-node",
|
|
36148
36439
|
"compile-request-full-text-invalid",
|
|
36440
|
+
"compile-request-full-text-paged",
|
|
36149
36441
|
"compile-secondary-shared-compact",
|
|
36150
36442
|
"compile-scan-changes-required",
|
|
36151
36443
|
"compile-section-kind-guidance",
|
|
@@ -36195,6 +36487,7 @@ var init_agentHintRegistry = __esm(() => {
|
|
|
36195
36487
|
"query-recall-truncated",
|
|
36196
36488
|
"query-recall-uneven-anchors",
|
|
36197
36489
|
"query-select-needs-scope",
|
|
36490
|
+
"raw-snapshot-pending-compile",
|
|
36198
36491
|
"ready-no-op-review",
|
|
36199
36492
|
"ready-review-output",
|
|
36200
36493
|
"reconcile-prepare-draft-mode-invalid",
|
|
@@ -37402,7 +37695,8 @@ function draftSessionError(message) {
|
|
|
37402
37695
|
severity: "error",
|
|
37403
37696
|
message,
|
|
37404
37697
|
next_action: "Read the draft status, then submit a corrected compile draft patch.",
|
|
37405
|
-
command: "context compile --draft-status <slug> --format json"
|
|
37698
|
+
command: "context compile --draft-status <slug> --format json",
|
|
37699
|
+
patch_schema_version: COMPILE_DRAFT_PATCH_SCHEMA_VERSION
|
|
37406
37700
|
}]
|
|
37407
37701
|
});
|
|
37408
37702
|
}
|
|
@@ -37484,7 +37778,7 @@ function parseCompileDraftPatch(value) {
|
|
|
37484
37778
|
if (value.patches !== undefined) {
|
|
37485
37779
|
throw draftSessionError("compile draft patch field patches is not supported; use operations[]");
|
|
37486
37780
|
}
|
|
37487
|
-
if (value.schema_version !== COMPILE_DRAFT_PATCH_SCHEMA_VERSION) {
|
|
37781
|
+
if (value.schema_version !== undefined && value.schema_version !== COMPILE_DRAFT_PATCH_SCHEMA_VERSION) {
|
|
37488
37782
|
throw draftSessionError(`schema_version must be ${COMPILE_DRAFT_PATCH_SCHEMA_VERSION}`);
|
|
37489
37783
|
}
|
|
37490
37784
|
if (!Array.isArray(value.operations) || value.operations.length === 0) {
|
|
@@ -38111,8 +38405,11 @@ function uniqueSourceEntries(values) {
|
|
|
38111
38405
|
continue;
|
|
38112
38406
|
const base = sourceIdWithoutVersion(value);
|
|
38113
38407
|
const current = byBase.get(base);
|
|
38114
|
-
|
|
38408
|
+
const currentVersion = current === undefined ? undefined : parseVersionedSourceId(current).snapshotHash;
|
|
38409
|
+
const nextVersion = parseVersionedSourceId(value).snapshotHash;
|
|
38410
|
+
if (current === undefined || nextVersion !== undefined && currentVersion === undefined || nextVersion !== undefined && currentVersion !== undefined && nextVersion !== currentVersion) {
|
|
38115
38411
|
byBase.set(base, value);
|
|
38412
|
+
}
|
|
38116
38413
|
}
|
|
38117
38414
|
return [...byBase.values()];
|
|
38118
38415
|
}
|
|
@@ -38697,7 +38994,7 @@ async function compileSourceSupport(input) {
|
|
|
38697
38994
|
if (typeof candidate.section.content !== "string" || candidate.section.content.length === 0)
|
|
38698
38995
|
return;
|
|
38699
38996
|
const sourceRefs = draftActionSourceRefs(input.action);
|
|
38700
|
-
const { sourceRef, citedText, diagnostic, evidenceBlock, evidenceBlockCandidates } = await diagnoseSectionSourceSupport({
|
|
38997
|
+
const { sourceRef, citedText, headingContext, diagnostic, evidenceBlock, evidenceBlockCandidates } = await diagnoseSectionSourceSupport({
|
|
38701
38998
|
ctxDir: input.ctxDir,
|
|
38702
38999
|
nodeSources: input.node.parsed.node.sources,
|
|
38703
39000
|
sourceById: input.sourceById,
|
|
@@ -38713,7 +39010,10 @@ async function compileSourceSupport(input) {
|
|
|
38713
39010
|
return {
|
|
38714
39011
|
source_ref: sourceRef,
|
|
38715
39012
|
cited_text: citedText,
|
|
39013
|
+
...headingContext !== undefined ? { heading_context: headingContext } : {},
|
|
38716
39014
|
verdict: diagnostic.verdict,
|
|
39015
|
+
...diagnostic.checkedFields !== undefined ? { checked_fields: diagnostic.checkedFields } : {},
|
|
39016
|
+
...candidate.section.summary !== undefined ? { summary_policy: "advisory_not_hard_gated" } : {},
|
|
38717
39017
|
content_term_count: diagnostic.contentTermCount,
|
|
38718
39018
|
matched_term_count: diagnostic.matchedTermCount,
|
|
38719
39019
|
required_term_count: diagnostic.requiredTermCount,
|
|
@@ -39227,6 +39527,8 @@ async function prepareCompileReconcileContext(input) {
|
|
|
39227
39527
|
});
|
|
39228
39528
|
resolvedItems.push({
|
|
39229
39529
|
item_id: itemId,
|
|
39530
|
+
...typeof action.action_id === "string" ? { draft_action_id: action.action_id } : {},
|
|
39531
|
+
draft_action_index: indexInDraft + 1,
|
|
39230
39532
|
proposed: temporal.proposed,
|
|
39231
39533
|
...defaultDecision !== undefined ? { default_decision: defaultDecision } : {},
|
|
39232
39534
|
...target !== undefined ? { target } : {},
|
|
@@ -40891,16 +41193,17 @@ function queryAgentOutput(value) {
|
|
|
40891
41193
|
return rest;
|
|
40892
41194
|
}
|
|
40893
41195
|
function semanticStatusAgentView(status) {
|
|
40894
|
-
const
|
|
40895
|
-
const agentHints =
|
|
40896
|
-
code: "
|
|
41196
|
+
const refreshedSourceIds = status.refreshed_source_pending_compile.source_ids;
|
|
41197
|
+
const agentHints = refreshedSourceIds.length > 0 ? [{
|
|
41198
|
+
code: "raw-snapshot-pending-compile",
|
|
40897
41199
|
severity: "info",
|
|
40898
|
-
message: "One or more
|
|
40899
|
-
next_action: "Run /context:compile
|
|
41200
|
+
message: "One or more active sources have newer raw snapshots that have not been absorbed into compiled knowledge.",
|
|
41201
|
+
next_action: "Run /context:compile. The CLI will refresh deterministic source ownership when possible; if ownership cannot be reanchored, rerun context align --scan before compiling.",
|
|
40900
41202
|
command: "/context:compile",
|
|
40901
41203
|
diagnostics: {
|
|
40902
|
-
source_ids:
|
|
40903
|
-
status_field: "semantic.refreshed_source_pending_compile.source_ids"
|
|
41204
|
+
source_ids: refreshedSourceIds,
|
|
41205
|
+
status_field: "semantic.refreshed_source_pending_compile.source_ids",
|
|
41206
|
+
note: "This status means raw snapshots changed; it does not mean finalized ownership or node.sources[] are already updated."
|
|
40904
41207
|
}
|
|
40905
41208
|
}] : [];
|
|
40906
41209
|
return agentPathFreeView({
|
|
@@ -41763,6 +42066,40 @@ async function refreshSources(input) {
|
|
|
41763
42066
|
const file = await loadSources2(input.ctxDir);
|
|
41764
42067
|
const rows = [];
|
|
41765
42068
|
for (const s of file.sources.filter((source2) => source2.status === "active")) {
|
|
42069
|
+
if (s.type === "local" && typeof s.origin === "string" && s.origin.length > 0) {
|
|
42070
|
+
const path2 = isAbsolute2(s.origin) ? s.origin : input.workspaceRoot === undefined ? null : join21(input.workspaceRoot, s.origin);
|
|
42071
|
+
if (path2 === null || !existsSync19(path2)) {
|
|
42072
|
+
rows.push({
|
|
42073
|
+
sourceId: s.id,
|
|
42074
|
+
status: "skipped",
|
|
42075
|
+
action: "skipped",
|
|
42076
|
+
error: path2 === null ? "local source refresh requires workspaceRoot" : `local source origin not found: ${s.origin}`
|
|
42077
|
+
});
|
|
42078
|
+
continue;
|
|
42079
|
+
}
|
|
42080
|
+
try {
|
|
42081
|
+
const outcome = await captureFile({
|
|
42082
|
+
path: path2,
|
|
42083
|
+
cwd: input.workspaceRoot ?? process.cwd(),
|
|
42084
|
+
ctxDir: input.ctxDir,
|
|
42085
|
+
...input.workspaceRoot !== undefined ? { workspaceRoot: input.workspaceRoot } : {},
|
|
42086
|
+
...input.now !== undefined ? { now: input.now } : {}
|
|
42087
|
+
});
|
|
42088
|
+
rows.push({
|
|
42089
|
+
sourceId: s.id,
|
|
42090
|
+
status: "ok",
|
|
42091
|
+
action: outcome.action === "unchanged" || outcome.action === "moved" || outcome.action === "duplicate" ? "unchanged" : "new-snapshot"
|
|
42092
|
+
});
|
|
42093
|
+
} catch (err2) {
|
|
42094
|
+
rows.push({
|
|
42095
|
+
sourceId: s.id,
|
|
42096
|
+
status: "failed",
|
|
42097
|
+
action: "failed",
|
|
42098
|
+
error: err2 instanceof Error ? err2.message : String(err2)
|
|
42099
|
+
});
|
|
42100
|
+
}
|
|
42101
|
+
continue;
|
|
42102
|
+
}
|
|
41766
42103
|
if (s.type !== "feishu" || typeof s.url !== "string" || s.url.length === 0) {
|
|
41767
42104
|
rows.push({ sourceId: s.id, status: "skipped", action: "skipped" });
|
|
41768
42105
|
continue;
|
|
@@ -51128,7 +51465,7 @@ function reviewAgentHints(input) {
|
|
|
51128
51465
|
code: "split-by-evidence-blocks",
|
|
51129
51466
|
severity: "error",
|
|
51130
51467
|
message: `${splitByEvidenceBlockCount} unsupported decision(s) appear to combine facts from multiple evidence blocks.`,
|
|
51131
|
-
next_action: "Split the proposed
|
|
51468
|
+
next_action: "Split the proposed content into one draft action per source_support.evidence_block_candidates[] entry, then rerun prepare/review. If the draft session is available, patch only the affected action with context compile --draft-patch <slug> --input - --plan.",
|
|
51132
51469
|
command: "context compile --draft-patch <slug> --input - --plan"
|
|
51133
51470
|
});
|
|
51134
51471
|
}
|
|
@@ -51138,7 +51475,7 @@ function reviewAgentHints(input) {
|
|
|
51138
51475
|
code: "review-content-shape",
|
|
51139
51476
|
severity: "error",
|
|
51140
51477
|
message: `${contentShapeIssueCount} proposed content field(s) contain long, multi-line, or code-block material.`,
|
|
51141
|
-
next_action: "Use proposed.content for the active Section text
|
|
51478
|
+
next_action: "Use proposed.content for the active Section text; proposed.summary is optional and is not a replacement for content. Rerun review with the current semantic-decisions schema.",
|
|
51142
51479
|
schema: "context schema semantic-decisions --format yaml"
|
|
51143
51480
|
});
|
|
51144
51481
|
}
|
|
@@ -51216,7 +51553,7 @@ function reviewAgentHints(input) {
|
|
|
51216
51553
|
code: "weak-source-support-warning",
|
|
51217
51554
|
severity: "warning",
|
|
51218
51555
|
message: `${weakSupportCount} item(s) are only weakly supported by the cited evidence.`,
|
|
51219
|
-
next_action: "Proceed only if the weak
|
|
51556
|
+
next_action: "Proceed only if the weak content compression is acceptable for this workflow; otherwise narrow content or choose/split source_ref/source_refs."
|
|
51220
51557
|
});
|
|
51221
51558
|
}
|
|
51222
51559
|
const exampleDetailQuestionCount = input.questions.filter((question) => question.type === "example_content_preservation").length;
|
|
@@ -51225,7 +51562,7 @@ function reviewAgentHints(input) {
|
|
|
51225
51562
|
code: "example-content-preservation",
|
|
51226
51563
|
severity: "warning",
|
|
51227
51564
|
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
|
|
51565
|
+
next_action: "Move the relevant fenced block into proposed.content and rerun review, or ask the user to confirm prose-only content is acceptable. Auto mode or general permission to continue is not confirmation."
|
|
51229
51566
|
});
|
|
51230
51567
|
}
|
|
51231
51568
|
const urlReferenceQuestionCount = input.questions.filter((question) => question.type === "url_reference_preservation").length;
|
|
@@ -51645,6 +51982,7 @@ function supportDiagnosticFromItem(input) {
|
|
|
51645
51982
|
if (input.decision.judge_support_verdict !== undefined) {
|
|
51646
51983
|
return {
|
|
51647
51984
|
verdict: input.decision.judge_support_verdict,
|
|
51985
|
+
checkedFields: ["content"],
|
|
51648
51986
|
contentTermCount: 1,
|
|
51649
51987
|
matchedTermCount: input.decision.judge_support_verdict === "unsupported" ? 0 : 1,
|
|
51650
51988
|
requiredTermCount: 1,
|
|
@@ -51661,11 +51999,15 @@ function supportDiagnosticFromItem(input) {
|
|
|
51661
51999
|
const detail = input.decision.proposed?.detail === null || typeof input.decision.proposed?.detail === "string" ? input.decision.proposed.detail : undefined;
|
|
51662
52000
|
const itemSupport = input.item?.source_support;
|
|
51663
52001
|
if (itemSupport !== undefined && itemSupport.source_ref === sourceRef && typeof itemSupport.cited_text === "string") {
|
|
51664
|
-
|
|
52002
|
+
const citedText2 = itemSupport.heading_context !== undefined && itemSupport.heading_context.length > 0 ? `${itemSupport.heading_context.join(`
|
|
52003
|
+
`)}
|
|
52004
|
+
${itemSupport.cited_text}` : itemSupport.cited_text;
|
|
52005
|
+
return sourceSectionSupportDiagnostic({ kind, content, detail, citedText: citedText2 });
|
|
51665
52006
|
}
|
|
51666
52007
|
if (itemSupport !== undefined && itemSupport.source_ref === sourceRef && preparedSupportContentMatches({ content, item: input.item })) {
|
|
51667
52008
|
return {
|
|
51668
52009
|
verdict: itemSupport.verdict,
|
|
52010
|
+
...itemSupport.checked_fields !== undefined ? { checkedFields: itemSupport.checked_fields } : {},
|
|
51669
52011
|
contentTermCount: itemSupport.content_term_count,
|
|
51670
52012
|
matchedTermCount: itemSupport.matched_term_count,
|
|
51671
52013
|
requiredTermCount: itemSupport.required_term_count,
|
|
@@ -51682,7 +52024,7 @@ function sourceSupportIssue(input) {
|
|
|
51682
52024
|
const action = input.decision.action;
|
|
51683
52025
|
const strict = actionRequiresStrictSourceSupport(action);
|
|
51684
52026
|
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
|
|
52027
|
+
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 content into separately supported claims, or ask the user to confirm weak content only after the evidence boundary is correct.";
|
|
51686
52028
|
const splitHint = splitCandidates !== undefined && splitCandidates.length > 0 ? ` Candidate evidence blocks for split decisions: ${splitCandidates}.` : "";
|
|
51687
52029
|
const splitCandidateCount = input.support?.evidence_block_candidates?.length ?? 0;
|
|
51688
52030
|
return {
|
|
@@ -51699,7 +52041,7 @@ function weakSupportWarning(input) {
|
|
|
51699
52041
|
severity: "warning",
|
|
51700
52042
|
code: "weak-source-support",
|
|
51701
52043
|
message: `proposed keep_separate is weakly supported by its cited raw text: ${formatSupportDiagnostic(input.diagnostic)}.`,
|
|
51702
|
-
next_action: "Review the cited evidence if the
|
|
52044
|
+
next_action: "Review the cited evidence if the content looks surprising; missing hard facts still remain errors."
|
|
51703
52045
|
};
|
|
51704
52046
|
}
|
|
51705
52047
|
function citedTextForDecision2(decision, item) {
|
|
@@ -51731,7 +52073,7 @@ function exampleDetailPreservationQuestion(input) {
|
|
|
51731
52073
|
type: "example_content_preservation",
|
|
51732
52074
|
...input.summary !== undefined ? { candidate_summary: { active: input.summary.active, archive: input.summary.archive } } : {},
|
|
51733
52075
|
...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
|
|
52076
|
+
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 prose-only content is acceptable and mark the decision decided_by: user. Auto mode or general permission to continue is not confirmation."
|
|
51735
52077
|
};
|
|
51736
52078
|
}
|
|
51737
52079
|
function sourceSupportFromDiagnostic(input) {
|
|
@@ -51739,6 +52081,7 @@ function sourceSupportFromDiagnostic(input) {
|
|
|
51739
52081
|
source_ref: input.sourceRef,
|
|
51740
52082
|
cited_text: input.citedText,
|
|
51741
52083
|
verdict: input.diagnostic.verdict,
|
|
52084
|
+
...input.diagnostic.checkedFields !== undefined ? { checked_fields: input.diagnostic.checkedFields } : {},
|
|
51742
52085
|
content_term_count: input.diagnostic.contentTermCount,
|
|
51743
52086
|
matched_term_count: input.diagnostic.matchedTermCount,
|
|
51744
52087
|
required_term_count: input.diagnostic.requiredTermCount,
|
|
@@ -56776,6 +57119,7 @@ init_cliFeedback();
|
|
|
56776
57119
|
init_agentHints();
|
|
56777
57120
|
init_exitCode();
|
|
56778
57121
|
init_compile();
|
|
57122
|
+
init_compileDraftSession();
|
|
56779
57123
|
init_currentWorkflow();
|
|
56780
57124
|
init_workflowPayloadStore();
|
|
56781
57125
|
function compileChangesFormat(value) {
|
|
@@ -57100,13 +57444,17 @@ function compileDraftRevisionHints(slug, digest2) {
|
|
|
57100
57444
|
code: "compile-draft-patch-ready",
|
|
57101
57445
|
severity: "info",
|
|
57102
57446
|
message: "Current draft can be revised with a node-scoped patch instead of resubmitting all actions.",
|
|
57103
|
-
next_action: "Replace, add, or remove only the affected action; the CLI resolves the current draft payload automatically.",
|
|
57447
|
+
next_action: "Replace, add, or remove only the affected action; schema_version may be omitted, and the CLI resolves the current draft payload automatically.",
|
|
57104
57448
|
command: `context compile --draft-patch ${slug} --input - --plan`,
|
|
57449
|
+
patch_schema_version: COMPILE_DRAFT_PATCH_SCHEMA_VERSION,
|
|
57105
57450
|
diagnostics: { optional_payload_digest: digest2 }
|
|
57106
57451
|
}];
|
|
57107
57452
|
}
|
|
57108
57453
|
function writeCompileDraftStatus(input) {
|
|
57109
|
-
const actions =
|
|
57454
|
+
const actions = compileDraftStatusActions({
|
|
57455
|
+
session: input.session,
|
|
57456
|
+
...input.preparedReconcile !== undefined ? { preparedItems: input.preparedReconcile.items } : {}
|
|
57457
|
+
});
|
|
57110
57458
|
const hints = [
|
|
57111
57459
|
...compileDraftRevisionHints(input.session.node, input.digest),
|
|
57112
57460
|
...input.session.agent_hints ?? []
|
|
@@ -57115,9 +57463,11 @@ function writeCompileDraftStatus(input) {
|
|
|
57115
57463
|
writeJson3({
|
|
57116
57464
|
node: input.session.node,
|
|
57117
57465
|
draft_digest: input.digest,
|
|
57466
|
+
patch_schema_version: COMPILE_DRAFT_PATCH_SCHEMA_VERSION,
|
|
57118
57467
|
show_command: input.showCommand,
|
|
57119
57468
|
next_command: input.showCommand,
|
|
57120
57469
|
action_count: actions.length,
|
|
57470
|
+
...input.preparedReconcile !== undefined ? { reconcile_prepare: { digest: input.preparedReconcile.digest, item_count: input.preparedReconcile.items.length } } : {},
|
|
57121
57471
|
actions,
|
|
57122
57472
|
agent_hints: hints
|
|
57123
57473
|
});
|
|
@@ -57128,17 +57478,38 @@ function writeCompileDraftStatus(input) {
|
|
|
57128
57478
|
`digest: ${input.digest}`,
|
|
57129
57479
|
`show: ${input.showCommand}`,
|
|
57130
57480
|
`actions: ${actions.length}`,
|
|
57481
|
+
...input.preparedReconcile !== undefined ? [`reconcile prepare: ${input.preparedReconcile.digest} (${input.preparedReconcile.items.length} item(s))`] : [],
|
|
57131
57482
|
"",
|
|
57132
|
-
"| action_id | op | kind | source_refs | preview |",
|
|
57133
|
-
"
|
|
57483
|
+
"| action_id | claim_id | op | kind | source_refs | preview |",
|
|
57484
|
+
"|-----------|----------|----|------|-------------|---------|"
|
|
57134
57485
|
];
|
|
57135
57486
|
for (const action of actions) {
|
|
57136
|
-
lines.push(`| ${action.action_id} | ${action.op} | ${action.kind ?? ""} | ${action.source_ref_count} | ${(action.content_preview ?? "").replace(/\|/g, "\\|")} |`);
|
|
57487
|
+
lines.push(`| ${action.action_id} | ${action.reconcile_item_id ?? ""} | ${action.op} | ${action.kind ?? ""} | ${action.source_ref_count} | ${(action.content_preview ?? "").replace(/\|/g, "\\|")} |`);
|
|
57137
57488
|
}
|
|
57138
57489
|
lines.push("", `next: ${hints[0].command}`);
|
|
57139
57490
|
process.stdout.write(lines.join(`
|
|
57140
57491
|
`));
|
|
57141
57492
|
}
|
|
57493
|
+
function claimIdForActionIndex(index) {
|
|
57494
|
+
return `claim-${String(index + 1).padStart(3, "0")}`;
|
|
57495
|
+
}
|
|
57496
|
+
function compileDraftStatusActions(input) {
|
|
57497
|
+
const itemsById = new Map((input.preparedItems ?? []).map((item) => [item.item_id, item]));
|
|
57498
|
+
const itemsByActionId = new Map((input.preparedItems ?? []).filter((item) => typeof item.draft_action_id === "string").map((item) => [item.draft_action_id, item]));
|
|
57499
|
+
const hasActionIdMapping = itemsByActionId.size > 0;
|
|
57500
|
+
return summarizeCompileDraftSession(input.session).map((action, index) => {
|
|
57501
|
+
const itemId = claimIdForActionIndex(index);
|
|
57502
|
+
const item = itemsByActionId.get(action.action_id) ?? (hasActionIdMapping ? undefined : itemsById.get(itemId));
|
|
57503
|
+
if (item === undefined)
|
|
57504
|
+
return action;
|
|
57505
|
+
return {
|
|
57506
|
+
...action,
|
|
57507
|
+
reconcile_item_id: item.item_id,
|
|
57508
|
+
reconcile_status: item.status ?? "pending",
|
|
57509
|
+
...item.source_support?.verdict !== undefined ? { source_support: item.source_support.verdict } : {}
|
|
57510
|
+
};
|
|
57511
|
+
});
|
|
57512
|
+
}
|
|
57142
57513
|
function rejectSourceRefTextMainPath(draft) {
|
|
57143
57514
|
const unsupportedEvidenceFieldNames = ["source_ref_text", "evidence_refs"];
|
|
57144
57515
|
const hasUnsupportedEvidenceField = (value) => unsupportedEvidenceFieldNames.some((field) => (field in value));
|
|
@@ -57938,25 +58309,29 @@ function normalizeAlignCoarseReadPayloads(value) {
|
|
|
57938
58309
|
reject("$", "align-coarse-read payload must be an object");
|
|
57939
58310
|
if (Array.isArray(value.coarse_reads)) {
|
|
57940
58311
|
walkForbidden(value, "$");
|
|
57941
|
-
if (value.schema_version !== undefined && value.schema_version !== ALIGN_COARSE_READ_BATCH_SCHEMA_VERSION) {
|
|
57942
|
-
reject("schema_version", `schema_version must be ${ALIGN_COARSE_READ_BATCH_SCHEMA_VERSION} for a coarse_reads envelope`);
|
|
58312
|
+
if (value.schema_version !== undefined && value.schema_version !== ALIGN_COARSE_READ_BATCH_SCHEMA_VERSION && value.schema_version !== ALIGN_COARSE_READ_SCHEMA_VERSION) {
|
|
58313
|
+
reject("schema_version", `schema_version must be omitted or be ${ALIGN_COARSE_READ_BATCH_SCHEMA_VERSION} for a coarse_reads envelope`);
|
|
57943
58314
|
}
|
|
57944
58315
|
if (value.coarse_reads.length === 0) {
|
|
57945
58316
|
reject("coarse_reads", "coarse_reads must contain at least one coarse-read record");
|
|
57946
58317
|
}
|
|
57947
58318
|
return value.coarse_reads.map((record, index) => {
|
|
57948
|
-
const
|
|
58319
|
+
const normalized2 = isRecord25(record) ? {
|
|
57949
58320
|
...record,
|
|
57950
58321
|
schema_version: record.schema_version ?? ALIGN_COARSE_READ_SCHEMA_VERSION,
|
|
57951
58322
|
reading_anchors: record.reading_anchors ?? [],
|
|
57952
58323
|
section_proposals: record.section_proposals ?? []
|
|
57953
58324
|
} : record;
|
|
57954
|
-
validateAlignCoarseReadPayload(
|
|
57955
|
-
return
|
|
58325
|
+
validateAlignCoarseReadPayload(normalized2, `coarse_reads[${index}]`);
|
|
58326
|
+
return normalized2;
|
|
57956
58327
|
});
|
|
57957
58328
|
}
|
|
57958
|
-
|
|
57959
|
-
|
|
58329
|
+
const normalized = {
|
|
58330
|
+
...value,
|
|
58331
|
+
schema_version: value.schema_version ?? ALIGN_COARSE_READ_SCHEMA_VERSION
|
|
58332
|
+
};
|
|
58333
|
+
validateAlignCoarseReadPayload(normalized);
|
|
58334
|
+
return [normalized];
|
|
57960
58335
|
}
|
|
57961
58336
|
|
|
57962
58337
|
// src/workflow/alignCandidateLedger.ts
|
|
@@ -59295,6 +59670,8 @@ var termTags = TERM_TAG_VALUES;
|
|
|
59295
59670
|
var entityTags = [...ENTITY_TAG_A_VALUES, ...ENTITY_TAG_B_VALUES, ...termTags];
|
|
59296
59671
|
var TERM_ENTITY_NOTES = [
|
|
59297
59672
|
"Node type order: action first only when scale plus process evidence both pass; otherwise concrete/term entity; otherwise child-bearing domain; otherwise no Node.",
|
|
59673
|
+
"Classify the Node by evidence referent, not by source title or heading. Source title/heading is ordinary evidence and does not automatically become node.title, aliases[], or slug.",
|
|
59674
|
+
"After node_type is chosen, generate node.title to fit that type: entity titles name concrete objects or atomic terms; domain titles name grouping scopes with child refs; action titles name executable processes. Scope/process words such as 方案, 架构, 体系, 演练, 流程, 策略, 能力, 机制, framework, architecture, system, strategy, process, or drill in an Entity title require review.",
|
|
59298
59675
|
"Action scale means at least two planned Section kinds or a child Action; process evidence means steps, phases, trigger->handling->result, role collaboration, or repeatable plan. Parallel options/config lists are not action evidence.",
|
|
59299
59676
|
"Entity tag term is for a pure stable named definition only. term is mutually exclusive with A/B concrete tags; React is [lib], not [lib, term]. Split a separate [term] Entity when both identities matter.",
|
|
59300
59677
|
"Legal Entity tag shapes: one A tag, one B tag, one A plus one B, or only [term]. A+A, B+B, term+A/B, and empty entity tags are invalid.",
|
|
@@ -59473,7 +59850,7 @@ var SCHEMAS = {
|
|
|
59473
59850
|
},
|
|
59474
59851
|
"align-coarse-read": {
|
|
59475
59852
|
schema: "align-coarse-read",
|
|
59476
|
-
schema_version:
|
|
59853
|
+
schema_version: ALIGN_COARSE_READ_SCHEMA_VERSION,
|
|
59477
59854
|
producer: "LLM Pass 0 + CLI id normalizer",
|
|
59478
59855
|
consumer: "CLI storage / Discovery LLM",
|
|
59479
59856
|
role: "Whole-document reading anchors, section planning, neutral content signals, and density profile.",
|
|
@@ -59482,10 +59859,10 @@ var SCHEMAS = {
|
|
|
59482
59859
|
content_signal_key: ALIGN_CONTENT_SIGNAL_KEYS,
|
|
59483
59860
|
content_signal_level: ALIGN_CONTENT_SIGNAL_LEVELS
|
|
59484
59861
|
},
|
|
59485
|
-
required: ["
|
|
59862
|
+
required: ["source_id", "density_profile", "reading_anchors", "section_proposals"],
|
|
59486
59863
|
forbidden_fields: [...ALIGN_WORKFLOW_FORBIDDEN_FIELDS, "node_type", "tags", "recommended_node", "action_tag"],
|
|
59487
59864
|
example: {
|
|
59488
|
-
schema_version:
|
|
59865
|
+
schema_version: ALIGN_COARSE_READ_SCHEMA_VERSION,
|
|
59489
59866
|
artifact_kind: "cli_normalized_llm_output",
|
|
59490
59867
|
source_id: "local:demo",
|
|
59491
59868
|
density_profile: "meso",
|
|
@@ -59512,12 +59889,27 @@ var SCHEMAS = {
|
|
|
59512
59889
|
source_window_ids: ["w0001"]
|
|
59513
59890
|
}]
|
|
59514
59891
|
},
|
|
59892
|
+
batch_example: {
|
|
59893
|
+
coarse_reads: [{
|
|
59894
|
+
source_id: "local:demo-a",
|
|
59895
|
+
density_profile: "micro",
|
|
59896
|
+
reading_anchors: [],
|
|
59897
|
+
section_proposals: []
|
|
59898
|
+
}, {
|
|
59899
|
+
source_id: "local:demo-b",
|
|
59900
|
+
density_profile: "macro",
|
|
59901
|
+
reading_anchors: [],
|
|
59902
|
+
section_proposals: []
|
|
59903
|
+
}]
|
|
59904
|
+
},
|
|
59515
59905
|
notes: [
|
|
59906
|
+
"When submitting through context align --coarse-read, schema_version may be omitted; the CLI infers single-source vs batch from the presence of coarse_reads[].",
|
|
59907
|
+
"For batch input, prefer { coarse_reads: [...] } without a top-level schema_version. Each entry is a single-source coarse-read record.",
|
|
59516
59908
|
"density_profile must be one of macro, meso, micro, or single_pass.",
|
|
59517
59909
|
"content_signals keys must be temporal_density, actor_density, step_density, or directive_density.",
|
|
59518
59910
|
"content_signals values must be high, med, or low. Use med, not medium.",
|
|
59519
59911
|
"content_signals describe text shape only; they are not action/type/tag hints.",
|
|
59520
|
-
`
|
|
59912
|
+
`If you include a top-level batch schema_version, use ${ALIGN_COARSE_READ_BATCH_SCHEMA_VERSION}; omitting it is simpler.`,
|
|
59521
59913
|
"align-coarse-read is the latest checkpoint. Durable multi-source recall lives in align-candidate-ledger.source_readings."
|
|
59522
59914
|
]
|
|
59523
59915
|
},
|
|
@@ -59528,7 +59920,7 @@ var SCHEMAS = {
|
|
|
59528
59920
|
consumer: "CLI ledger reducer",
|
|
59529
59921
|
role: "One transactional batch of candidate ledger operations.",
|
|
59530
59922
|
enums: enums(),
|
|
59531
|
-
required: ["
|
|
59923
|
+
required: ["batch_id", "sections_processed", "ops"],
|
|
59532
59924
|
forbidden_fields: ALIGN_WORKFLOW_FORBIDDEN_FIELDS,
|
|
59533
59925
|
example: {
|
|
59534
59926
|
schema_version: ALIGN_CANDIDATE_OPS_SCHEMA_VERSION,
|
|
@@ -59595,6 +59987,7 @@ var SCHEMAS = {
|
|
|
59595
59987
|
}]
|
|
59596
59988
|
},
|
|
59597
59989
|
notes: [
|
|
59990
|
+
"When submitting through context align --ops, schema_version may be omitted; the CLI normalizes it to the current align-candidate-ops schema.",
|
|
59598
59991
|
"add_candidate uses local:<name>; reducer assigns immutable candidate_id.",
|
|
59599
59992
|
...TERM_ENTITY_NOTES,
|
|
59600
59993
|
"Action candidates must include boolean action_probe gate fields and structured action_signals; do not use free-form steps[] in candidate ops.",
|
|
@@ -61739,6 +62132,12 @@ function validateCandidateOpsAgainstSegments(opsInput, segments) {
|
|
|
61739
62132
|
walk(opsInput.ops, "ops", "ops");
|
|
61740
62133
|
throwIfIssues();
|
|
61741
62134
|
}
|
|
62135
|
+
function normalizeCandidateOpsInput(value) {
|
|
62136
|
+
return {
|
|
62137
|
+
...value,
|
|
62138
|
+
schema_version: value.schema_version ?? ALIGN_CANDIDATE_OPS_SCHEMA_VERSION
|
|
62139
|
+
};
|
|
62140
|
+
}
|
|
61742
62141
|
async function readExistingLedger(input) {
|
|
61743
62142
|
try {
|
|
61744
62143
|
const record = await readWorkflowPayloadByDigest({
|
|
@@ -61757,12 +62156,13 @@ async function readExistingLedger(input) {
|
|
|
61757
62156
|
}
|
|
61758
62157
|
}
|
|
61759
62158
|
async function runAlignCandidateOpsCommand(input) {
|
|
61760
|
-
const
|
|
61761
|
-
if (typeof
|
|
62159
|
+
const rawOpsInput = await readStructuredInput2(resolveStdinOnlyInput(input.options.ops, "--ops"));
|
|
62160
|
+
if (typeof rawOpsInput !== "object" || rawOpsInput === null || Array.isArray(rawOpsInput)) {
|
|
61762
62161
|
throw new ContextError(ExitCode.UserError, "align candidate ops input must be an object", {
|
|
61763
62162
|
category: ErrorCategory.SchemaInvalid
|
|
61764
62163
|
});
|
|
61765
62164
|
}
|
|
62165
|
+
const opsInput = normalizeCandidateOpsInput(rawOpsInput);
|
|
61766
62166
|
const segmentsDigest = input.workflowState.input_digests["align-segments"];
|
|
61767
62167
|
if (segmentsDigest === undefined) {
|
|
61768
62168
|
throw alignSegmentsRequiredError("candidate-ops");
|
|
@@ -62140,7 +62540,8 @@ async function saveRecoverableCompileDraft(input) {
|
|
|
62140
62540
|
severity: "error",
|
|
62141
62541
|
message: "Compile draft parsed, but validation failed. A patchable draft session was saved.",
|
|
62142
62542
|
next_action: "Read draft status, patch only the failed action(s), then rerun compile draft prepare.",
|
|
62143
|
-
command: `context compile --draft-status ${input.slug} --format json
|
|
62543
|
+
command: `context compile --draft-status ${input.slug} --format json`,
|
|
62544
|
+
patch_schema_version: COMPILE_DRAFT_PATCH_SCHEMA_VERSION
|
|
62144
62545
|
};
|
|
62145
62546
|
const session = createCompileDraftSession({
|
|
62146
62547
|
node: input.slug,
|
|
@@ -62172,6 +62573,7 @@ function throwCompileDraftRecoveredError(input) {
|
|
|
62172
62573
|
draft_digest: input.recovery.payload.digest,
|
|
62173
62574
|
draft_status_command: `context compile --draft-status ${input.slug} --format json`,
|
|
62174
62575
|
patch_command: `context compile --draft-patch ${input.slug} --input - --plan`,
|
|
62576
|
+
patch_schema_version: COMPILE_DRAFT_PATCH_SCHEMA_VERSION,
|
|
62175
62577
|
issues: input.recovery.issues,
|
|
62176
62578
|
agent_hints: input.recovery.agent_hints
|
|
62177
62579
|
});
|
|
@@ -62695,6 +63097,9 @@ async function prepareCompileDraftWorkflow(input) {
|
|
|
62695
63097
|
}
|
|
62696
63098
|
|
|
62697
63099
|
// src/commands/compileDraftCommand.ts
|
|
63100
|
+
function isRecord31(value) {
|
|
63101
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
63102
|
+
}
|
|
62698
63103
|
async function writeCompileDraftChallengePayloads2(input) {
|
|
62699
63104
|
const payloads = await compileDraftChallengePayloads({
|
|
62700
63105
|
ctxDir: input.ctxDir,
|
|
@@ -62722,6 +63127,24 @@ async function writeCompileDraftChallengePayloads2(input) {
|
|
|
62722
63127
|
});
|
|
62723
63128
|
}
|
|
62724
63129
|
}
|
|
63130
|
+
function preparedReconcileItems(value, slug) {
|
|
63131
|
+
if (!isRecord31(value) || !Array.isArray(value.items))
|
|
63132
|
+
return [];
|
|
63133
|
+
const target = isRecord31(value.target) ? value.target : undefined;
|
|
63134
|
+
if (target !== undefined && target.node !== slug)
|
|
63135
|
+
return [];
|
|
63136
|
+
return value.items.filter(isRecord31).flatMap((item) => {
|
|
63137
|
+
if (typeof item.item_id !== "string")
|
|
63138
|
+
return [];
|
|
63139
|
+
const sourceSupport = isRecord31(item.source_support) && typeof item.source_support.verdict === "string" ? { verdict: item.source_support.verdict } : undefined;
|
|
63140
|
+
return [{
|
|
63141
|
+
item_id: item.item_id,
|
|
63142
|
+
...typeof item.draft_action_id === "string" ? { draft_action_id: item.draft_action_id } : {},
|
|
63143
|
+
...typeof item.status === "string" ? { status: item.status } : {},
|
|
63144
|
+
...sourceSupport !== undefined ? { source_support: sourceSupport } : {}
|
|
63145
|
+
}];
|
|
63146
|
+
});
|
|
63147
|
+
}
|
|
62725
63148
|
async function runDraftStatus(input) {
|
|
62726
63149
|
const current = requireCurrentWorkflow(await readCurrentWorkflow(input.ctxDir));
|
|
62727
63150
|
if (current.family !== "compile") {
|
|
@@ -62738,11 +63161,22 @@ async function runDraftStatus(input) {
|
|
|
62738
63161
|
});
|
|
62739
63162
|
const session = parseCompileDraftSession(payload.value);
|
|
62740
63163
|
assertCompileDraftSessionNode(session, input.slug);
|
|
63164
|
+
const preparePayload = await readWorkflowPayloadByDigest({
|
|
63165
|
+
ctxDir: input.ctxDir,
|
|
63166
|
+
workflowId: current.workflow_id,
|
|
63167
|
+
scopeId: nodeRunIdForSlug(input.slug),
|
|
63168
|
+
payload: "prepare",
|
|
63169
|
+
fallbackToUniqueScope: true
|
|
63170
|
+
}).catch(() => {
|
|
63171
|
+
return;
|
|
63172
|
+
});
|
|
63173
|
+
const prepareItems = preparePayload === undefined ? [] : preparedReconcileItems(preparePayload.value, input.slug);
|
|
62741
63174
|
writeCompileDraftStatus({
|
|
62742
63175
|
session,
|
|
62743
63176
|
digest: payload.digest,
|
|
62744
63177
|
showCommand: workflowPayloadShowCommand(payload),
|
|
62745
|
-
format: compileChangesFormat(input.format)
|
|
63178
|
+
format: compileChangesFormat(input.format),
|
|
63179
|
+
...preparePayload !== undefined && prepareItems.length > 0 ? { preparedReconcile: { digest: preparePayload.digest, items: prepareItems } } : {}
|
|
62746
63180
|
});
|
|
62747
63181
|
}
|
|
62748
63182
|
async function runDraftPatch(input) {
|
|
@@ -62986,6 +63420,40 @@ function collectRequestedBlock(value, previous) {
|
|
|
62986
63420
|
function ignoredSourceIds(value) {
|
|
62987
63421
|
return Array.isArray(value) ? value.filter((item) => typeof item === "string" && item.length > 0) : [];
|
|
62988
63422
|
}
|
|
63423
|
+
function parseRequestFullTextRange(value) {
|
|
63424
|
+
if (value === undefined)
|
|
63425
|
+
return;
|
|
63426
|
+
if (typeof value !== "string") {
|
|
63427
|
+
throw new ContextError(ExitCode.UserError, "--request-full-text-range must be start:end", {
|
|
63428
|
+
category: ErrorCategory.UserInputInvalid,
|
|
63429
|
+
flag: "--request-full-text-range"
|
|
63430
|
+
});
|
|
63431
|
+
}
|
|
63432
|
+
const match = /^(\d+):(\d+)$/u.exec(value.trim());
|
|
63433
|
+
if (!match) {
|
|
63434
|
+
throw new ContextError(ExitCode.UserError, "--request-full-text-range must be start:end", {
|
|
63435
|
+
category: ErrorCategory.UserInputInvalid,
|
|
63436
|
+
flag: "--request-full-text-range",
|
|
63437
|
+
agent_hints: [{
|
|
63438
|
+
code: "compile-request-full-text-invalid",
|
|
63439
|
+
severity: "error",
|
|
63440
|
+
message: "request_full_text pagination uses block-relative line ranges such as 21:40.",
|
|
63441
|
+
path: "request_full_text.range",
|
|
63442
|
+
reason_code: "range-format-invalid",
|
|
63443
|
+
next_action: "Use raw_snippets[].full_text_page.next_range or omit --request-full-text-range."
|
|
63444
|
+
}]
|
|
63445
|
+
});
|
|
63446
|
+
}
|
|
63447
|
+
const start2 = Number(match[1]);
|
|
63448
|
+
const end = Number(match[2]);
|
|
63449
|
+
if (!Number.isSafeInteger(start2) || !Number.isSafeInteger(end) || start2 < 1 || end < start2) {
|
|
63450
|
+
throw new ContextError(ExitCode.UserError, "--request-full-text-range must be an increasing positive line range", {
|
|
63451
|
+
category: ErrorCategory.UserInputInvalid,
|
|
63452
|
+
flag: "--request-full-text-range"
|
|
63453
|
+
});
|
|
63454
|
+
}
|
|
63455
|
+
return { start: start2, end };
|
|
63456
|
+
}
|
|
62989
63457
|
function coverageSkipMissingOptionsError(missingFields, mode = "single") {
|
|
62990
63458
|
const flag = mode === "bulk" ? "--coverage-skip-unresolved" : "--coverage-skip";
|
|
62991
63459
|
const command = mode === "bulk" ? 'context compile --coverage-skip-unresolved --coverage-disposition-node <slug> --reason "<reason>"' : 'context compile --coverage-skip <candidate-id> --coverage-disposition-node <slug> --reason "<reason>"';
|
|
@@ -63029,7 +63497,7 @@ function compileScopeForOptions(options) {
|
|
|
63029
63497
|
function registerWorkflowCommands(program2) {
|
|
63030
63498
|
registerWorkflowStateCommands(program2);
|
|
63031
63499
|
registerAlignWorkflowCommand(program2);
|
|
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) => {
|
|
63500
|
+
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("--request-full-text-range <start:end>", "with --request-full-text, read a block-relative line page").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) => {
|
|
63033
63501
|
if (options.scan === true) {
|
|
63034
63502
|
throw new ContextError(ExitCode.UserError, "context compile --scan was removed; use context compile --scan-changes", {
|
|
63035
63503
|
category: ErrorCategory.UserInputInvalid,
|
|
@@ -63045,7 +63513,7 @@ function registerWorkflowCommands(program2) {
|
|
|
63045
63513
|
const wantsChanges = options.scanChanges === true;
|
|
63046
63514
|
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);
|
|
63047
63515
|
if (actionCount !== 1) {
|
|
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 });
|
|
63516
|
+
throw new ContextError(ExitCode.UserError, "usage: context compile --scan-changes [--delegated] | --context <slug> [--request-full-text <block-id> [--request-full-text-range <start:end>]] [--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 });
|
|
63049
63517
|
}
|
|
63050
63518
|
const viewWasExplicit = typeof options.view === "string";
|
|
63051
63519
|
const view = compileOutputView(options.view);
|
|
@@ -63073,6 +63541,7 @@ function registerWorkflowCommands(program2) {
|
|
|
63073
63541
|
}
|
|
63074
63542
|
}
|
|
63075
63543
|
const requestFullTextBlockIds = ignoredSourceIds(options.requestFullText);
|
|
63544
|
+
const requestFullTextRange = parseRequestFullTextRange(options.requestFullTextRange);
|
|
63076
63545
|
const coverUncoveredOnly = options.coverUncoveredOnly === true;
|
|
63077
63546
|
const delegated = options.delegated === true;
|
|
63078
63547
|
const delegatedAllowed = wantsChanges || typeof options.context === "string" || typeof options.nodeCycle === "string" || typeof options.draft === "string";
|
|
@@ -63111,6 +63580,20 @@ function registerWorkflowCommands(program2) {
|
|
|
63111
63580
|
flag: "--request-full-text"
|
|
63112
63581
|
});
|
|
63113
63582
|
}
|
|
63583
|
+
if (requestFullTextRange !== undefined && requestFullTextBlockIds.length !== 1) {
|
|
63584
|
+
throw new ContextError(ExitCode.UserError, "--request-full-text-range requires exactly one --request-full-text block id", {
|
|
63585
|
+
category: ErrorCategory.UserInputInvalid,
|
|
63586
|
+
flag: "--request-full-text-range",
|
|
63587
|
+
agent_hints: [{
|
|
63588
|
+
code: "compile-request-full-text-invalid",
|
|
63589
|
+
severity: "error",
|
|
63590
|
+
message: "request_full_text range continues one long block page at a time.",
|
|
63591
|
+
path: "request_full_text.range",
|
|
63592
|
+
reason_code: "range-requires-single-block",
|
|
63593
|
+
next_action: "Retry with one --request-full-text <block_id>, or omit --request-full-text-range."
|
|
63594
|
+
}]
|
|
63595
|
+
});
|
|
63596
|
+
}
|
|
63114
63597
|
if (coverUncoveredOnly && typeof options.context !== "string") {
|
|
63115
63598
|
throw new ContextError(ExitCode.UserError, "--cover-uncovered-only is only valid with --context", {
|
|
63116
63599
|
category: ErrorCategory.UserInputInvalid,
|
|
@@ -63229,7 +63712,8 @@ function registerWorkflowCommands(program2) {
|
|
|
63229
63712
|
if (typeof options.sourceRefs === "string") {
|
|
63230
63713
|
const format = compileChangesFormat(options.format);
|
|
63231
63714
|
const context = await getNodeContext(ctx.ctxDir, options.sourceRefs, {
|
|
63232
|
-
...requestFullTextBlockIds.length > 0 ? { requestFullTextBlockIds } : {}
|
|
63715
|
+
...requestFullTextBlockIds.length > 0 ? { requestFullTextBlockIds } : {},
|
|
63716
|
+
...requestFullTextRange !== undefined ? { requestFullTextRange } : {}
|
|
63233
63717
|
});
|
|
63234
63718
|
writeCompileSourceRefs(context, format);
|
|
63235
63719
|
return;
|
|
@@ -63247,7 +63731,8 @@ function registerWorkflowCommands(program2) {
|
|
|
63247
63731
|
let context = await getNodeContext(ctx.ctxDir, options.context, {
|
|
63248
63732
|
...view !== "source-refs" && !coverUncoveredOnly ? { mode: "changed-only" } : {},
|
|
63249
63733
|
...ignoreSourceIds.length > 0 ? { ignoreSourceIds } : {},
|
|
63250
|
-
...requestFullTextBlockIds.length > 0 ? { requestFullTextBlockIds } : {}
|
|
63734
|
+
...requestFullTextBlockIds.length > 0 ? { requestFullTextBlockIds } : {},
|
|
63735
|
+
...requestFullTextRange !== undefined ? { requestFullTextRange } : {}
|
|
63251
63736
|
});
|
|
63252
63737
|
const sourceFinalize = await readCurrentSourceOwnershipRecord(ctx.ctxDir).then((record) => record === null ? undefined : publishedSourceOwnershipSummary(record));
|
|
63253
63738
|
const selectedCoverageStatus = coverUncoveredOnly ? await readCoverageWorkspaceStatus(ctx.ctxDir) : undefined;
|
|
@@ -63334,13 +63819,15 @@ function registerWorkflowCommands(program2) {
|
|
|
63334
63819
|
scopeId,
|
|
63335
63820
|
payload: "coverage-candidates",
|
|
63336
63821
|
...requestedDigest !== undefined ? { digest: requestedDigest } : {},
|
|
63337
|
-
fallbackToUniqueScope:
|
|
63822
|
+
fallbackToUniqueScope: requestedNode === undefined
|
|
63338
63823
|
});
|
|
63339
63824
|
if (requestedNode === undefined)
|
|
63340
63825
|
inferred.push(`node/scope: ${payload.scope_id}`);
|
|
63341
63826
|
if (requestedDigest === undefined)
|
|
63342
63827
|
inferred.push("coverage payload digest");
|
|
63343
63828
|
const value = payload.value;
|
|
63829
|
+
const subjectNode = requestedNode ?? value.node ?? scopeId;
|
|
63830
|
+
const nodeMetadataWarning = requestedNode !== undefined && value.node !== undefined && value.node !== requestedNode ? `coverage payload node metadata was ${value.node}; using requested node ${requestedNode}` : undefined;
|
|
63344
63831
|
const candidates = Array.isArray(value.candidates) ? value.candidates : [];
|
|
63345
63832
|
const patchInput = typeof options.coverageSkip === "string" ? coverageSkipPatch({ candidateId: options.coverageSkip, reason: String(options.reason).trim() }) : options.coverageSkipUnresolved === true ? coverageSkipUnresolvedPatch({ candidates, reason: String(options.reason).trim() }) : await readStructuredInput2(resolveStdinOnlyInput(options.coverageDisposition, "--coverage-disposition"));
|
|
63346
63833
|
const patch = await validateCoverageDispositions({ ctxDir: ctx.ctxDir, candidates, patch: patchInput });
|
|
@@ -63354,10 +63841,11 @@ function registerWorkflowCommands(program2) {
|
|
|
63354
63841
|
process.stdout.write(formatFeedback({
|
|
63355
63842
|
symbol: status.high_signal_unresolved > 0 ? "⚠" : "✓",
|
|
63356
63843
|
action: wantsCoverageSkip ? "skipped" : "applied",
|
|
63357
|
-
subject: typeof options.coverageSkip === "string" ? `coverage candidate ${options.coverageSkip}` : options.coverageSkipUnresolved === true ? `${skippedCount} unresolved coverage candidate(s) for ${
|
|
63844
|
+
subject: typeof options.coverageSkip === "string" ? `coverage candidate ${options.coverageSkip}` : options.coverageSkipUnresolved === true ? `${skippedCount} unresolved coverage candidate(s) for ${subjectNode}` : `coverage disposition ${options.coverageDispositionNode}`,
|
|
63358
63845
|
headline: formatCoverageSummary(status),
|
|
63359
63846
|
body: [
|
|
63360
63847
|
workflowSummaryLine(workflowState),
|
|
63848
|
+
nodeMetadataWarning,
|
|
63361
63849
|
...inferred.length > 0 ? [`inferred from current workflow: ${inferred.join("; ")}`] : [],
|
|
63362
63850
|
`payload digest: ${payload.digest} (optional stale guard)`
|
|
63363
63851
|
],
|
|
@@ -64742,7 +65230,7 @@ function reconcileSchemaExample(name) {
|
|
|
64742
65230
|
"Run context reconcile review before apply. Review persists the ready artifact; apply reads it from the current workflow scope.",
|
|
64743
65231
|
"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.",
|
|
64744
65232
|
"Do not use decisions: [] to accept all defaults; an empty decisions array means no decisions were made.",
|
|
64745
|
-
"Keep proposed.content as the user-facing Section text.
|
|
65233
|
+
"Keep proposed.content as the user-facing Section text. Include proposed.summary only when it helps reader scanability or query output; do not emit retired long-form fields.",
|
|
64746
65234
|
"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
65235
|
"For kind=example, preserving the cited fenced code/config/command block in proposed.content is active example knowledge, not raw-evidence echo.",
|
|
64748
65236
|
'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.',
|
|
@@ -64846,6 +65334,7 @@ function compileSchemaExample(name) {
|
|
|
64846
65334
|
"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.",
|
|
64847
65335
|
"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
65336
|
"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.",
|
|
65337
|
+
"source_support hard-term matching checks content (and legacy detail when present), not summary. Keep summary faithful to content, but do not add raw-only keywords just to satisfy source_support.",
|
|
64849
65338
|
"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.",
|
|
64850
65339
|
"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.",
|
|
64851
65340
|
"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.",
|
|
@@ -64967,12 +65456,13 @@ function compileSchemaExample(name) {
|
|
|
64967
65456
|
consumed_by: [
|
|
64968
65457
|
"context compile --draft-patch <slug> --input - --plan"
|
|
64969
65458
|
],
|
|
64970
|
-
required: ["
|
|
65459
|
+
required: ["operations"],
|
|
64971
65460
|
enums: {
|
|
64972
65461
|
op: ["replace_action", "remove_action", "add_action"]
|
|
64973
65462
|
},
|
|
64974
65463
|
notes: [
|
|
64975
65464
|
"Read the current draft with context compile --draft-status <slug> --format json.",
|
|
65465
|
+
"schema_version may be omitted; when present it must match the schema_version shown here or draft-status.patch_schema_version.",
|
|
64976
65466
|
"The CLI reads the current draft session by default; add --payload-digest only when an explicit stale guard is needed.",
|
|
64977
65467
|
"replace_action keeps the same action_id; add_action receives a new CLI-owned action_id.",
|
|
64978
65468
|
"The CLI validates the whole patched draft before saving it, so failed patches do not corrupt the current draft session."
|
|
@@ -65044,7 +65534,7 @@ function compileSchemaExample(name) {
|
|
|
65044
65534
|
"section.content",
|
|
65045
65535
|
"user_facing_report"
|
|
65046
65536
|
],
|
|
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
|
|
65537
|
+
instruction: "Generate knowledge titles, summaries, and user-facing reports in Chinese; keep node.summary concise (target <15 tokens, never >30 tokens); section.summary is optional reader/query aid when useful; 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."
|
|
65048
65538
|
},
|
|
65049
65539
|
existing: {
|
|
65050
65540
|
sections: [{
|