@deftai/directive-core 0.103.0 → 0.104.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authz/classify.js +167 -4
- package/dist/check/gate-lists.d.ts +3 -2
- package/dist/check/gate-lists.js +5 -2
- package/dist/check/index.d.ts +1 -0
- package/dist/check/index.js +1 -0
- package/dist/check/session-completed-ac.d.ts +39 -0
- package/dist/check/session-completed-ac.js +198 -0
- package/dist/doctor/main.js +12 -7
- package/dist/fs/contained-write.js +2 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/intake/clause-derivation.d.ts +37 -0
- package/dist/intake/clause-derivation.js +207 -0
- package/dist/intake/index.d.ts +1 -0
- package/dist/intake/index.js +1 -0
- package/dist/intake/issue-ingest.js +2 -38
- package/dist/preflight/evaluate.d.ts +5 -0
- package/dist/preflight/evaluate.js +14 -0
- package/dist/preflight/index.d.ts +1 -1
- package/dist/product-first-done-gate/empty-resolution.d.ts +1 -1
- package/dist/product-first-done-gate/empty-resolution.js +1 -1
- package/dist/product-first-done-gate/evaluate.d.ts +17 -0
- package/dist/product-first-done-gate/evaluate.js +61 -10
- package/dist/product-first-done-gate/index.d.ts +1 -1
- package/dist/product-first-done-gate/index.js +1 -1
- package/dist/run-summary/emit.d.ts +42 -2
- package/dist/run-summary/emit.js +250 -25
- package/dist/run-summary/index.d.ts +1 -1
- package/dist/run-summary/index.js +1 -1
- package/dist/run-summary/share.d.ts +1 -1
- package/dist/run-summary/share.js +2 -2
- package/dist/run-summary/types.d.ts +10 -3
- package/dist/scope/acceptance-activate-gate.d.ts +1 -1
- package/dist/scope/acceptance-activate-gate.js +4 -4
- package/dist/scope/acceptance-evidence.d.ts +15 -0
- package/dist/scope/acceptance-evidence.js +39 -0
- package/dist/scope/capacity-stamp.d.ts +2 -0
- package/dist/scope/capacity-stamp.js +4 -0
- package/dist/scope/delivery-evidence.d.ts +6 -0
- package/dist/scope/delivery-evidence.js +17 -0
- package/dist/scope/transition.js +66 -4
- package/dist/session/ceremony-dial-evidence.d.ts +42 -0
- package/dist/session/ceremony-dial-evidence.js +194 -0
- package/dist/session/index.d.ts +1 -0
- package/dist/session/index.js +1 -0
- package/dist/session/session-start.js +21 -2
- package/dist/slice/existing.js +12 -1
- package/dist/slice/record.d.ts +8 -5
- package/dist/slice/record.js +21 -13
- package/dist/telemetry-coverage/evaluate.d.ts +42 -0
- package/dist/telemetry-coverage/evaluate.js +148 -0
- package/dist/telemetry-coverage/fake-trial.d.ts +45 -0
- package/dist/telemetry-coverage/fake-trial.js +194 -0
- package/dist/telemetry-coverage/index.d.ts +5 -0
- package/dist/telemetry-coverage/index.js +5 -0
- package/dist/telemetry-coverage/kinds.d.ts +19 -0
- package/dist/telemetry-coverage/kinds.js +52 -0
- package/dist/telemetry-coverage/scan-callers.d.ts +25 -0
- package/dist/telemetry-coverage/scan-callers.js +168 -0
- package/dist/vbrief-reconcile/index.d.ts +2 -0
- package/dist/vbrief-reconcile/index.js +1 -0
- package/dist/vbrief-reconcile/origin-freshness.d.ts +44 -0
- package/dist/vbrief-reconcile/origin-freshness.js +221 -0
- package/dist/verify-source/index.d.ts +1 -0
- package/dist/verify-source/index.js +1 -0
- package/package.json +3 -3
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { depResolved, graphOutcomeToJson, RESOLVED_FOLDERS, reconcileGraph, renderGraphReport, } from "./graph.js";
|
|
2
2
|
export { computeDesiredLabels, labelsOutcomeToJson, MANAGED_LABELS, reconcileLabels, renderLabelsReport, SCAN_FOLDERS, ScmLabelClient, ScmLabelError, } from "./labels.js";
|
|
3
3
|
export { cmdVbriefReconcile, run, usage } from "./main.js";
|
|
4
|
+
export { briefUpdatedOf, compareOriginFreshness, evaluateOriginFreshness, extractGithubIssueOrigin, extractGithubIssueOrigins, fetchGithubIssueUpdatedAt, formatOriginStaleMessage, ORIGIN_FRESHNESS_REMEDIATION, } from "./origin-freshness.js";
|
|
4
5
|
export { PARITY_SCENARIO_NAMES, renderScenarioOutput, runParityScenario, } from "./parity-scenarios.js";
|
|
5
6
|
export { pyRepr } from "./py-repr.js";
|
|
6
7
|
export { buildSpecTaskIndex, detectStatusMarker, folderFromStatus, formatReconciliationMarkdown, hasDisagreement, loadOverrides, normalizeTaskId, OVERRIDES_FILENAME, parseOverridesYaml, reconcileScopeItems, writeReconciliationReport, } from "./reconciliation.js";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type CallOptions, type CompletedProcess } from "../scm/call.js";
|
|
2
|
+
export declare const ORIGIN_FRESHNESS_REMEDIATION = "Re-read the issue body and comments (#2143), then either refresh the brief or record intentional divergence and bump xBRIEFInfo.updated. Do not auto-write origin text onto the brief (#309 D12).";
|
|
3
|
+
export type OriginFreshnessKind = "no-origin" | "current" | "stale" | "uncomparable";
|
|
4
|
+
export interface GithubIssueOrigin {
|
|
5
|
+
readonly owner: string;
|
|
6
|
+
readonly repo: string;
|
|
7
|
+
readonly number: number;
|
|
8
|
+
readonly uri: string;
|
|
9
|
+
readonly type: string;
|
|
10
|
+
}
|
|
11
|
+
export type FetchOriginUpdatedAt = (origin: GithubIssueOrigin) => {
|
|
12
|
+
updatedAt: string;
|
|
13
|
+
} | {
|
|
14
|
+
error: string;
|
|
15
|
+
};
|
|
16
|
+
export interface EvaluateOriginFreshnessOptions {
|
|
17
|
+
readonly fetchOriginUpdatedAt?: FetchOriginUpdatedAt;
|
|
18
|
+
readonly cwd?: string;
|
|
19
|
+
readonly skip?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export type OriginFreshnessResult = {
|
|
22
|
+
readonly ok: true;
|
|
23
|
+
readonly kind: OriginFreshnessKind;
|
|
24
|
+
} | {
|
|
25
|
+
readonly ok: false;
|
|
26
|
+
readonly kind: OriginFreshnessKind;
|
|
27
|
+
readonly message: string;
|
|
28
|
+
};
|
|
29
|
+
export type ScmCallFn = (source: string, verb: string, args: readonly string[] | null, options?: CallOptions) => CompletedProcess;
|
|
30
|
+
export declare function briefUpdatedOf(payload: Record<string, unknown>): string | null;
|
|
31
|
+
export declare function extractGithubIssueOrigins(payload: Record<string, unknown>): GithubIssueOrigin[];
|
|
32
|
+
export declare function extractGithubIssueOrigin(payload: Record<string, unknown>): GithubIssueOrigin | null;
|
|
33
|
+
export declare function compareOriginFreshness(briefUpdated: string | null, originUpdatedAt: string | null): OriginFreshnessKind;
|
|
34
|
+
export declare function formatOriginStaleMessage(origin: GithubIssueOrigin, originUpdatedAt: string, briefUpdated: string | null): string;
|
|
35
|
+
export declare function fetchGithubIssueUpdatedAt(origin: GithubIssueOrigin, options?: {
|
|
36
|
+
scmCall?: ScmCallFn;
|
|
37
|
+
cwd?: string;
|
|
38
|
+
}): {
|
|
39
|
+
updatedAt: string;
|
|
40
|
+
} | {
|
|
41
|
+
error: string;
|
|
42
|
+
};
|
|
43
|
+
export declare function evaluateOriginFreshness(payload: Record<string, unknown>, options?: EvaluateOriginFreshnessOptions): OriginFreshnessResult;
|
|
44
|
+
//# sourceMappingURL=origin-freshness.d.ts.map
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { extractReferencesFromVbrief, GITHUB_ISSUE_REF_TYPES, parseIssueNumber, } from "../intake/reconcile-issues.js";
|
|
2
|
+
import { call } from "../scm/call.js";
|
|
3
|
+
const ISSUE_URL_PATTERN = /https:\/\/github\.com\/([^/\s]+)\/([^/\s]+)\/issues\/(\d+)/g;
|
|
4
|
+
const ISSUE_API_URL_PATTERN = /https:\/\/api\.github\.com\/repos\/([^/\s]+)\/([^/\s]+)\/issues\/(\d+)/g;
|
|
5
|
+
export const ORIGIN_FRESHNESS_REMEDIATION = "Re-read the issue body and comments (#2143), then either refresh the brief or record intentional divergence and bump xBRIEFInfo.updated. Do not auto-write origin text onto the brief (#309 D12).";
|
|
6
|
+
export function briefUpdatedOf(payload) {
|
|
7
|
+
const info = payload.xBRIEFInfo;
|
|
8
|
+
if (info !== null && typeof info === "object" && !Array.isArray(info)) {
|
|
9
|
+
const updated = info.updated;
|
|
10
|
+
if (typeof updated === "string" && updated.trim().length > 0) {
|
|
11
|
+
return updated.trim();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const plan = payload.plan;
|
|
15
|
+
if (plan !== null && typeof plan === "object" && !Array.isArray(plan)) {
|
|
16
|
+
const updated = plan.updated;
|
|
17
|
+
if (typeof updated === "string" && updated.trim().length > 0) {
|
|
18
|
+
return updated.trim();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
export function extractGithubIssueOrigins(payload) {
|
|
24
|
+
const origins = [];
|
|
25
|
+
const seen = new Set();
|
|
26
|
+
const add = (origin) => {
|
|
27
|
+
const key = `${origin.owner}/${origin.repo}#${origin.number}`;
|
|
28
|
+
if (seen.has(key)) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
seen.add(key);
|
|
32
|
+
origins.push(origin);
|
|
33
|
+
};
|
|
34
|
+
for (const rec of extractReferencesFromVbrief(payload)) {
|
|
35
|
+
const type = String(rec.type ?? "");
|
|
36
|
+
if (!GITHUB_ISSUE_REF_TYPES.has(type)) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const fromUri = originFromUri(rec);
|
|
40
|
+
let origin = fromUri !== null ? { ...fromUri, type } : null;
|
|
41
|
+
if (origin === null) {
|
|
42
|
+
const number = parseIssueNumber(rec);
|
|
43
|
+
if (number === null) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
origin = {
|
|
47
|
+
owner: "",
|
|
48
|
+
repo: "",
|
|
49
|
+
number,
|
|
50
|
+
uri: typeof rec.uri === "string" ? rec.uri : "",
|
|
51
|
+
type,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
add(origin);
|
|
55
|
+
}
|
|
56
|
+
for (const text of textualOriginFields(payload)) {
|
|
57
|
+
for (const fromText of originsFromText(text)) {
|
|
58
|
+
add({ ...fromText, type: "x-xbrief/github-issue" });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return origins;
|
|
62
|
+
}
|
|
63
|
+
export function extractGithubIssueOrigin(payload) {
|
|
64
|
+
return extractGithubIssueOrigins(payload)[0] ?? null;
|
|
65
|
+
}
|
|
66
|
+
function originFromUri(ref) {
|
|
67
|
+
for (const key of ["uri", "url"]) {
|
|
68
|
+
const value = ref[key];
|
|
69
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const parsed = originFromText(value);
|
|
73
|
+
if (parsed !== null) {
|
|
74
|
+
return parsed;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
function originsFromText(text) {
|
|
80
|
+
const origins = [];
|
|
81
|
+
const seen = new Set();
|
|
82
|
+
for (const pattern of [ISSUE_URL_PATTERN, ISSUE_API_URL_PATTERN]) {
|
|
83
|
+
for (const match of text.matchAll(pattern)) {
|
|
84
|
+
if (!match[1] || !match[2] || !match[3]) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const owner = match[1];
|
|
88
|
+
const repo = match[2];
|
|
89
|
+
const number = Number.parseInt(match[3], 10);
|
|
90
|
+
const key = `${owner}/${repo}#${number}`;
|
|
91
|
+
if (seen.has(key)) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
seen.add(key);
|
|
95
|
+
origins.push({
|
|
96
|
+
owner,
|
|
97
|
+
repo,
|
|
98
|
+
number,
|
|
99
|
+
uri: `https://github.com/${owner}/${repo}/issues/${number}`,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return origins;
|
|
104
|
+
}
|
|
105
|
+
function originFromText(text) {
|
|
106
|
+
return originsFromText(text)[0] ?? null;
|
|
107
|
+
}
|
|
108
|
+
function textualOriginFields(payload) {
|
|
109
|
+
const texts = [];
|
|
110
|
+
const plan = payload.plan;
|
|
111
|
+
if (plan !== null && typeof plan === "object" && !Array.isArray(plan)) {
|
|
112
|
+
const narratives = plan.narratives;
|
|
113
|
+
if (narratives !== null && typeof narratives === "object" && !Array.isArray(narratives)) {
|
|
114
|
+
const origin = narratives.Origin;
|
|
115
|
+
if (typeof origin === "string" && origin.length > 0) {
|
|
116
|
+
texts.push(origin);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
for (const key of ["xBRIEFInfo", "vBRIEFInfo"]) {
|
|
121
|
+
const info = payload[key];
|
|
122
|
+
if (info !== null && typeof info === "object" && !Array.isArray(info)) {
|
|
123
|
+
const description = info.description;
|
|
124
|
+
if (typeof description === "string" && description.length > 0) {
|
|
125
|
+
texts.push(description);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return texts;
|
|
130
|
+
}
|
|
131
|
+
export function compareOriginFreshness(briefUpdated, originUpdatedAt) {
|
|
132
|
+
if (originUpdatedAt === null || originUpdatedAt.trim().length === 0) {
|
|
133
|
+
return "uncomparable";
|
|
134
|
+
}
|
|
135
|
+
if (briefUpdated === null || briefUpdated.trim().length === 0) {
|
|
136
|
+
return "stale";
|
|
137
|
+
}
|
|
138
|
+
const briefMs = Date.parse(briefUpdated);
|
|
139
|
+
const originMs = Date.parse(originUpdatedAt);
|
|
140
|
+
if (Number.isNaN(briefMs) || Number.isNaN(originMs)) {
|
|
141
|
+
return "uncomparable";
|
|
142
|
+
}
|
|
143
|
+
return originMs > briefMs ? "stale" : "current";
|
|
144
|
+
}
|
|
145
|
+
export function formatOriginStaleMessage(origin, originUpdatedAt, briefUpdated) {
|
|
146
|
+
const slug = origin.owner.length > 0 ? `${origin.owner}/${origin.repo}` : "origin";
|
|
147
|
+
const briefStamp = briefUpdated ?? "(missing)";
|
|
148
|
+
return (`Origin GitHub issue #${origin.number} (${slug}) is newer than this xBRIEF ` +
|
|
149
|
+
`(origin updated_at=${originUpdatedAt}, brief updated=${briefStamp}). ` +
|
|
150
|
+
ORIGIN_FRESHNESS_REMEDIATION);
|
|
151
|
+
}
|
|
152
|
+
export function fetchGithubIssueUpdatedAt(origin, options = {}) {
|
|
153
|
+
if (origin.owner.length === 0 || origin.repo.length === 0) {
|
|
154
|
+
return { error: "origin reference is missing owner/repo in the GitHub issue URI" };
|
|
155
|
+
}
|
|
156
|
+
const scmCall = options.scmCall ?? call;
|
|
157
|
+
let result;
|
|
158
|
+
try {
|
|
159
|
+
result = scmCall("github-issue", "api", [`repos/${origin.owner}/${origin.repo}/issues/${origin.number}`], { timeout: 30, cwd: options.cwd });
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
163
|
+
return { error: `gh CLI not available (${message})` };
|
|
164
|
+
}
|
|
165
|
+
if (result.returncode !== 0) {
|
|
166
|
+
const stderr = result.stderr.trim();
|
|
167
|
+
return { error: stderr.length > 0 ? stderr : `gh api exited ${result.returncode}` };
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
const payload = JSON.parse(result.stdout);
|
|
171
|
+
const updatedAt = payload.updated_at;
|
|
172
|
+
if (typeof updatedAt !== "string" || updatedAt.trim().length === 0) {
|
|
173
|
+
return { error: "origin issue payload lacks updated_at" };
|
|
174
|
+
}
|
|
175
|
+
return { updatedAt: updatedAt.trim() };
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return { error: "origin issue payload is not valid JSON" };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
export function evaluateOriginFreshness(payload, options = {}) {
|
|
182
|
+
if (options.skip === true) {
|
|
183
|
+
return { ok: true, kind: "no-origin" };
|
|
184
|
+
}
|
|
185
|
+
const origins = extractGithubIssueOrigins(payload);
|
|
186
|
+
if (origins.length === 0) {
|
|
187
|
+
return { ok: true, kind: "no-origin" };
|
|
188
|
+
}
|
|
189
|
+
const fetch = options.fetchOriginUpdatedAt ??
|
|
190
|
+
((next) => fetchGithubIssueUpdatedAt(next, { cwd: options.cwd }));
|
|
191
|
+
const briefUpdated = briefUpdatedOf(payload);
|
|
192
|
+
for (const origin of origins) {
|
|
193
|
+
const fetched = fetch(origin);
|
|
194
|
+
if ("error" in fetched) {
|
|
195
|
+
return {
|
|
196
|
+
ok: false,
|
|
197
|
+
kind: "uncomparable",
|
|
198
|
+
message: `Could not fetch origin GitHub issue #${origin.number} for freshness check: ${fetched.error}. ` +
|
|
199
|
+
ORIGIN_FRESHNESS_REMEDIATION,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
const kind = compareOriginFreshness(briefUpdated, fetched.updatedAt);
|
|
203
|
+
if (kind === "stale") {
|
|
204
|
+
return {
|
|
205
|
+
ok: false,
|
|
206
|
+
kind,
|
|
207
|
+
message: formatOriginStaleMessage(origin, fetched.updatedAt, briefUpdated),
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
if (kind === "uncomparable") {
|
|
211
|
+
return {
|
|
212
|
+
ok: false,
|
|
213
|
+
kind,
|
|
214
|
+
message: `Could not compare origin GitHub issue #${origin.number} updated_at=${fetched.updatedAt} ` +
|
|
215
|
+
`to brief updated=${briefUpdated ?? "(missing)"}. ${ORIGIN_FRESHNESS_REMEDIATION}`,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return { ok: true, kind: "current" };
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=origin-freshness.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deftai/directive-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.104.0",
|
|
4
4
|
"description": "TypeScript engine core for the Directive framework.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -382,8 +382,8 @@
|
|
|
382
382
|
"provenance": true
|
|
383
383
|
},
|
|
384
384
|
"dependencies": {
|
|
385
|
-
"@deftai/directive-content": "^0.
|
|
386
|
-
"@deftai/directive-types": "^0.
|
|
385
|
+
"@deftai/directive-content": "^0.104.0",
|
|
386
|
+
"@deftai/directive-types": "^0.104.0",
|
|
387
387
|
"archiver": "^8.0.0"
|
|
388
388
|
},
|
|
389
389
|
"scripts": {
|