@deftai/directive-core 0.105.0 → 0.107.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 +591 -34
- package/dist/check/gate-lists.js +2 -0
- package/dist/check/named-cause.js +1 -1
- package/dist/design-critique/exclusive-chip.d.ts +33 -0
- package/dist/design-critique/exclusive-chip.js +68 -0
- package/dist/design-critique/parent-audit.d.ts +59 -0
- package/dist/design-critique/parent-audit.js +121 -0
- package/dist/doctor/checks.d.ts +6 -0
- package/dist/doctor/checks.js +35 -0
- package/dist/forward-coverage/diff-coverage.d.ts +39 -0
- package/dist/forward-coverage/diff-coverage.js +112 -0
- package/dist/forward-coverage/diff-lines.d.ts +19 -0
- package/dist/forward-coverage/diff-lines.js +173 -0
- package/dist/forward-coverage/evaluate.d.ts +24 -9
- package/dist/forward-coverage/evaluate.js +125 -19
- package/dist/hooks/dest-form.d.ts +46 -0
- package/dist/hooks/dest-form.js +575 -0
- package/dist/hooks/dispatcher.d.ts +17 -1
- package/dist/hooks/dispatcher.js +82 -11
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +1 -0
- package/dist/init-deposit/agent-hooks.d.ts +1 -1
- package/dist/init-deposit/agent-hooks.js +1 -1
- package/dist/intake/clause-derivation.d.ts +9 -0
- package/dist/intake/clause-derivation.js +30 -3
- package/dist/intake/github-auth-modes-cli.js +14 -2
- package/dist/intake/github-auth-modes.d.ts +54 -9
- package/dist/intake/github-auth-modes.js +326 -123
- package/dist/lifecycle/completed-tracked-on-delivery.d.ts +26 -0
- package/dist/lifecycle/completed-tracked-on-delivery.js +37 -14
- package/dist/lifecycle/completed-write-guard.d.ts +48 -0
- package/dist/lifecycle/completed-write-guard.js +373 -0
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.js +1 -0
- package/dist/lifecycle-visible/evaluate.d.ts +98 -0
- package/dist/lifecycle-visible/evaluate.js +710 -0
- package/dist/lifecycle-visible/index.d.ts +2 -0
- package/dist/lifecycle-visible/index.js +2 -0
- package/dist/literal-acceptance/capture.d.ts +16 -0
- package/dist/literal-acceptance/capture.js +78 -10
- package/dist/literal-acceptance/evaluate.js +25 -3
- package/dist/literal-acceptance/index.d.ts +2 -2
- package/dist/literal-acceptance/index.js +2 -2
- package/dist/literal-acceptance/run.js +9 -3
- package/dist/literal-acceptance/types.d.ts +6 -0
- package/dist/literal-acceptance/types.js +6 -0
- package/dist/orchestration/judgment-policy.d.ts +13 -0
- package/dist/orchestration/judgment-policy.js +15 -0
- package/dist/orchestration/probe-session.js +13 -8
- package/dist/orchestration/verify-judgment-gates.d.ts +4 -0
- package/dist/orchestration/verify-judgment-gates.js +43 -11
- package/dist/policy/ceremony-dial.js +7 -7
- package/dist/policy/host-hooks.d.ts +20 -0
- package/dist/policy/host-hooks.js +121 -2
- package/dist/policy/org-force-on-migration.js +2 -1
- package/dist/policy/plan-extensions.d.ts +1 -1
- package/dist/policy/plan-extensions.js +2 -0
- package/dist/policy/product-signal.js +6 -7
- package/dist/policy/require-human-merge.js +8 -6
- package/dist/policy/resolve.d.ts +7 -2
- package/dist/policy/resolve.js +25 -8
- package/dist/policy/runtime-authority.d.ts +18 -0
- package/dist/policy/runtime-authority.js +11 -0
- package/dist/policy/value-feedback.js +7 -8
- package/dist/policy/write-fence.js +3 -0
- package/dist/preflight-cache/evaluate.d.ts +12 -0
- package/dist/preflight-cache/evaluate.js +24 -4
- package/dist/preflight-cache/index.d.ts +1 -1
- package/dist/preflight-cache/index.js +1 -1
- package/dist/product-first-done-gate/evaluate.d.ts +4 -0
- package/dist/product-first-done-gate/evaluate.js +82 -10
- package/dist/release/closed-verb-gate.d.ts +12 -0
- package/dist/release/closed-verb-gate.js +51 -0
- package/dist/release/index.d.ts +1 -0
- package/dist/release/index.js +1 -0
- package/dist/release/pipeline.js +7 -0
- package/dist/release/types.d.ts +12 -0
- package/dist/render/constants.d.ts +2 -1
- package/dist/render/constants.js +2 -1
- package/dist/render/framework-commands.js +4 -0
- package/dist/render/spec-validate.js +23 -12
- package/dist/run-summary/types.d.ts +4 -0
- package/dist/scm/design-critique-chip.d.ts +37 -0
- package/dist/scm/design-critique-chip.js +171 -0
- package/dist/scm/index.d.ts +1 -0
- package/dist/scm/index.js +1 -0
- package/dist/scm/main.d.ts +3 -0
- package/dist/scm/main.js +15 -1
- package/dist/scm/readiness-cli.d.ts +2 -0
- package/dist/scm/readiness-cli.js +42 -1
- package/dist/scm/readiness.d.ts +2 -1
- package/dist/scm/readiness.js +7 -1
- package/dist/scope/decompose.js +2 -1
- package/dist/scope/delivery-evidence.d.ts +27 -1
- package/dist/scope/index.d.ts +1 -0
- package/dist/scope/index.js +1 -0
- package/dist/scope/lifecycle-write.d.ts +24 -0
- package/dist/scope/lifecycle-write.js +64 -0
- package/dist/scope/main.js +18 -6
- package/dist/scope/promote-from-issue.js +5 -5
- package/dist/scope/transition.js +90 -11
- package/dist/scope-provenance/evaluate.js +8 -4
- package/dist/session/ac-pass-banking.d.ts +5 -0
- package/dist/session/ac-pass-banking.js +3 -2
- package/dist/session/git.d.ts +18 -0
- package/dist/session/git.js +81 -1
- package/dist/session/occupancy.d.ts +2 -1
- package/dist/session/occupancy.js +11 -4
- package/dist/session/process-cost.d.ts +32 -10
- package/dist/session/process-cost.js +189 -1
- package/dist/session/product-state-hash.js +41 -24
- package/dist/session/ritual-entrypoint.js +16 -1
- package/dist/session/session-start.d.ts +18 -0
- package/dist/session/session-start.js +49 -2
- package/dist/session/verify-session-ritual.d.ts +46 -4
- package/dist/session/verify-session-ritual.js +118 -10
- package/dist/swarm/finalize-cohort-cli.d.ts +7 -2
- package/dist/swarm/finalize-cohort-cli.js +165 -35
- package/dist/swarm/finalize-cohort.d.ts +1 -0
- package/dist/swarm/finalize-cohort.js +14 -2
- package/dist/swarm/launch.d.ts +69 -0
- package/dist/swarm/launch.js +191 -1
- package/dist/swarm/routing-set-cli.js +2 -0
- package/dist/swarm/routing-verify.d.ts +1 -1
- package/dist/swarm/routing-verify.js +2 -2
- package/dist/triage/actions/index.d.ts +4 -0
- package/dist/triage/actions/index.js +6 -0
- package/dist/triage/bootstrap/index.js +6 -6
- package/dist/triage/evaluate/evaluate.d.ts +11 -0
- package/dist/triage/evaluate/evaluate.js +169 -0
- package/dist/triage/evaluate/github.d.ts +16 -0
- package/dist/triage/evaluate/github.js +153 -0
- package/dist/triage/evaluate/index.d.ts +9 -0
- package/dist/triage/evaluate/index.js +8 -0
- package/dist/triage/evaluate/paths.d.ts +7 -0
- package/dist/triage/evaluate/paths.js +25 -0
- package/dist/triage/evaluate/sink.d.ts +5 -0
- package/dist/triage/evaluate/sink.js +52 -0
- package/dist/triage/evaluate/types.d.ts +93 -0
- package/dist/triage/evaluate/types.js +13 -0
- package/dist/triage/evaluate/validity.d.ts +8 -0
- package/dist/triage/evaluate/validity.js +87 -0
- package/dist/triage/evaluate/value.d.ts +12 -0
- package/dist/triage/evaluate/value.js +33 -0
- package/dist/triage/evaluate/wip-census.d.ts +5 -0
- package/dist/triage/evaluate/wip-census.js +39 -0
- package/dist/triage/evaluate/worktrees.d.ts +8 -0
- package/dist/triage/evaluate/worktrees.js +68 -0
- package/dist/triage/evaluate/xbrief-refs.d.ts +8 -0
- package/dist/triage/evaluate/xbrief-refs.js +60 -0
- package/dist/triage/help/registry-data.d.ts +22 -8
- package/dist/triage/help/registry-data.js +54 -6
- package/dist/triage/index.d.ts +1 -0
- package/dist/triage/index.js +1 -0
- package/dist/triage/welcome/writers.d.ts +1 -1
- package/dist/triage/welcome/writers.js +10 -5
- package/dist/value/feedback-file.d.ts +17 -2
- package/dist/value/feedback-file.js +80 -6
- package/dist/value/readback.d.ts +4 -1
- package/dist/value/readback.js +51 -12
- package/dist/vbrief-reconcile/labels.d.ts +1 -0
- package/dist/vbrief-reconcile/labels.js +30 -0
- package/dist/vbrief-validate/schema.d.ts +4 -0
- package/dist/vbrief-validate/schema.js +1 -1
- package/dist/vbrief-validation/story-quality.d.ts +7 -0
- package/dist/vbrief-validation/story-quality.js +8 -1
- package/dist/verify-env/agent-hook-readiness.d.ts +2 -2
- package/dist/verify-env/agent-hook-readiness.js +12 -8
- package/dist/verify-env/agent-hooks-live-probe.d.ts +5 -1
- package/dist/verify-env/agent-hooks-live-probe.js +26 -5
- package/dist/verify-env/agent-hooks.js +3 -4
- package/dist/xbrief-migrate/agents-header.js +69 -7
- package/package.json +7 -3
|
@@ -7,6 +7,21 @@ import { GhRestError, restCreateIssue, restIssueListPaginated, } from "../scm/gh
|
|
|
7
7
|
import { resolveProjectRoot } from "../scope/project-context.js";
|
|
8
8
|
export const DEFAULT_UPSTREAM_REPO = "deftai/directive";
|
|
9
9
|
export const FRAMEWORK_GAP_TITLE_PREFIX = "[framework-gap]";
|
|
10
|
+
/** Sole sanctioned title classification (#3713). Does not write `adoption-blocker`. */
|
|
11
|
+
export const ADOPTION_BLOCKER_TITLE_TOKEN = "BLOCKER";
|
|
12
|
+
const FRAMEWORK_GAP_PREFIX_RE = /^\[framework-gap\]\s*/i;
|
|
13
|
+
const BLOCKER_TITLE_TOKEN_RE = /^BLOCKER\b[:\s-]*/i;
|
|
14
|
+
/** Strip source prefix and the optional BLOCKER token so marked/unmarked titles dedup. */
|
|
15
|
+
export function stripTitleClassificationTokens(title) {
|
|
16
|
+
let rest = title.trim();
|
|
17
|
+
let previous = "";
|
|
18
|
+
while (rest !== previous) {
|
|
19
|
+
previous = rest;
|
|
20
|
+
rest = rest.replace(FRAMEWORK_GAP_PREFIX_RE, "").trim();
|
|
21
|
+
rest = rest.replace(BLOCKER_TITLE_TOKEN_RE, "").trim();
|
|
22
|
+
}
|
|
23
|
+
return rest;
|
|
24
|
+
}
|
|
10
25
|
function sanitizeOneLine(value) {
|
|
11
26
|
return value.replace(/\r?\n/g, " ").trim();
|
|
12
27
|
}
|
|
@@ -18,23 +33,54 @@ function sectionOrPlaceholder(value, placeholder) {
|
|
|
18
33
|
export function isMaintainerFrameworkRepo(projectRoot) {
|
|
19
34
|
return isFrameworkRepoRoot(resolve(projectRoot));
|
|
20
35
|
}
|
|
21
|
-
/** Normalize a title for duplicate comparison (#1709). */
|
|
36
|
+
/** Normalize a title for duplicate comparison (#1709 / #3713). */
|
|
22
37
|
export function normalizeForDedup(title) {
|
|
23
|
-
return title
|
|
24
|
-
.trim()
|
|
25
|
-
.replace(/^\[framework-gap\]\s*/i, "")
|
|
38
|
+
return stripTitleClassificationTokens(title)
|
|
26
39
|
.toLowerCase()
|
|
27
40
|
.replace(/[^\p{L}\p{N}]+/gu, " ")
|
|
28
41
|
.trim();
|
|
29
42
|
}
|
|
30
43
|
/** Build the upstream issue title for a framework-gap report. */
|
|
31
|
-
export function buildFrameworkGapTitle(summary) {
|
|
44
|
+
export function buildFrameworkGapTitle(summary, options) {
|
|
32
45
|
const clean = sanitizeOneLine(summary);
|
|
46
|
+
if (options?.adoptionBlocker) {
|
|
47
|
+
const rest = stripTitleClassificationTokens(clean);
|
|
48
|
+
return `${FRAMEWORK_GAP_TITLE_PREFIX} ${ADOPTION_BLOCKER_TITLE_TOKEN} ${rest}`;
|
|
49
|
+
}
|
|
33
50
|
if (clean.toLowerCase().startsWith(FRAMEWORK_GAP_TITLE_PREFIX.toLowerCase())) {
|
|
34
51
|
return clean;
|
|
35
52
|
}
|
|
36
53
|
return `${FRAMEWORK_GAP_TITLE_PREFIX} ${clean}`;
|
|
37
54
|
}
|
|
55
|
+
function buildAdoptionImpactSection(input) {
|
|
56
|
+
if (!input.adoptionBlocker) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
return [
|
|
60
|
+
"## Adoption impact",
|
|
61
|
+
"",
|
|
62
|
+
"This report is a consumer hard-stop: the consumer cannot complete an intended Directive flow and has no reasonable workaround.",
|
|
63
|
+
"",
|
|
64
|
+
`Title token: \`${ADOPTION_BLOCKER_TITLE_TOKEN}\`. This token does not apply the \`adoption-blocker\` ranking label. A privileged actor applies that label after the body-evidence test.`,
|
|
65
|
+
"",
|
|
66
|
+
"### Affected consumer flow and version",
|
|
67
|
+
"",
|
|
68
|
+
sectionOrPlaceholder(input.flowAndVersion, "_(not provided)_"),
|
|
69
|
+
"",
|
|
70
|
+
"### Documented alternatives attempted",
|
|
71
|
+
"",
|
|
72
|
+
sectionOrPlaceholder(input.alternatives, "_(not provided — why documented alternatives are not a reasonable workaround)_"),
|
|
73
|
+
"",
|
|
74
|
+
"### Observed recovery cost",
|
|
75
|
+
"",
|
|
76
|
+
sectionOrPlaceholder(input.recoveryCost, "_(not provided)_"),
|
|
77
|
+
"",
|
|
78
|
+
"### Triage owner and date",
|
|
79
|
+
"",
|
|
80
|
+
"_(to be filled by a privileged actor when applying `adoption-blocker`)_",
|
|
81
|
+
"",
|
|
82
|
+
];
|
|
83
|
+
}
|
|
38
84
|
/** Build the structured framework-gap issue body. */
|
|
39
85
|
export function buildFrameworkGapBody(input) {
|
|
40
86
|
const summary = sanitizeOneLine(input.summary);
|
|
@@ -59,6 +105,7 @@ export function buildFrameworkGapBody(input) {
|
|
|
59
105
|
"",
|
|
60
106
|
sectionOrPlaceholder(input.sessionNotes, "_(not provided)_"),
|
|
61
107
|
"",
|
|
108
|
+
...buildAdoptionImpactSection(input),
|
|
62
109
|
"---",
|
|
63
110
|
"_Filed via `task feedback:file` from a directive consumer project (Refs #1709 value-feedback gap escalation)._",
|
|
64
111
|
"",
|
|
@@ -126,7 +173,7 @@ export function runFeedbackFile(options) {
|
|
|
126
173
|
}
|
|
127
174
|
const projectRoot = resolve(projectRootRaw);
|
|
128
175
|
const repo = resolveRepo(options);
|
|
129
|
-
const title = buildFrameworkGapTitle(summary);
|
|
176
|
+
const title = buildFrameworkGapTitle(summary, { adoptionBlocker: options.adoptionBlocker });
|
|
130
177
|
const body = buildFrameworkGapBody(options);
|
|
131
178
|
if (isMaintainerFrameworkRepo(projectRoot)) {
|
|
132
179
|
return {
|
|
@@ -254,6 +301,8 @@ export function parseFeedbackFileArgs(argv) {
|
|
|
254
301
|
out.dryRun = true;
|
|
255
302
|
else if (arg === "--json")
|
|
256
303
|
out.json = true;
|
|
304
|
+
else if (arg === "--blocker")
|
|
305
|
+
out.adoptionBlocker = true;
|
|
257
306
|
else if (arg === "--summary") {
|
|
258
307
|
out.summary = argv[++i];
|
|
259
308
|
}
|
|
@@ -287,6 +336,27 @@ export function parseFeedbackFileArgs(argv) {
|
|
|
287
336
|
else if (arg?.startsWith("--session-notes=")) {
|
|
288
337
|
out.sessionNotes = arg.slice("--session-notes=".length);
|
|
289
338
|
}
|
|
339
|
+
else if (arg === "--flow" || arg === "--flow-and-version") {
|
|
340
|
+
out.flowAndVersion = argv[++i];
|
|
341
|
+
}
|
|
342
|
+
else if (arg?.startsWith("--flow=")) {
|
|
343
|
+
out.flowAndVersion = arg.slice("--flow=".length);
|
|
344
|
+
}
|
|
345
|
+
else if (arg?.startsWith("--flow-and-version=")) {
|
|
346
|
+
out.flowAndVersion = arg.slice("--flow-and-version=".length);
|
|
347
|
+
}
|
|
348
|
+
else if (arg === "--alternatives") {
|
|
349
|
+
out.alternatives = argv[++i];
|
|
350
|
+
}
|
|
351
|
+
else if (arg?.startsWith("--alternatives=")) {
|
|
352
|
+
out.alternatives = arg.slice("--alternatives=".length);
|
|
353
|
+
}
|
|
354
|
+
else if (arg === "--recovery-cost") {
|
|
355
|
+
out.recoveryCost = argv[++i];
|
|
356
|
+
}
|
|
357
|
+
else if (arg?.startsWith("--recovery-cost=")) {
|
|
358
|
+
out.recoveryCost = arg.slice("--recovery-cost=".length);
|
|
359
|
+
}
|
|
290
360
|
else if (arg === "--repo") {
|
|
291
361
|
out.repo = argv[++i];
|
|
292
362
|
}
|
|
@@ -327,6 +397,10 @@ export function feedbackFileMain(argv) {
|
|
|
327
397
|
expected: args.expected,
|
|
328
398
|
actual: args.actual,
|
|
329
399
|
sessionNotes: args.sessionNotes,
|
|
400
|
+
adoptionBlocker: args.adoptionBlocker,
|
|
401
|
+
flowAndVersion: args.flowAndVersion,
|
|
402
|
+
alternatives: args.alternatives,
|
|
403
|
+
recoveryCost: args.recoveryCost,
|
|
330
404
|
confirm: args.confirm,
|
|
331
405
|
dryRun: args.dryRun,
|
|
332
406
|
json: args.json,
|
package/dist/value/readback.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type BehavioralEventRecord } from "../lifecycle/events.js";
|
|
2
2
|
import { type ValueFeedbackResolved } from "../policy/value-feedback.js";
|
|
3
|
+
import { type CeremonyCostRollup } from "../session/process-cost.js";
|
|
3
4
|
/** Repeat-suppression window for the budgeted session readback (#1709 / #1279 parity). */
|
|
4
5
|
export declare const VALUE_READBACK_SUPPRESSION_HOURS = 4;
|
|
5
6
|
export declare const VALUE_READBACK_HISTORY_REL: string;
|
|
@@ -24,6 +25,8 @@ export interface ValueShowResult {
|
|
|
24
25
|
readonly empty: boolean;
|
|
25
26
|
readonly text: string;
|
|
26
27
|
readonly trend: ValueShowTrend | null;
|
|
28
|
+
/** Composed #3508 ceremony-cost rollup (CLI process time, not turn clock). */
|
|
29
|
+
readonly ceremonyCost: CeremonyCostRollup | null;
|
|
27
30
|
}
|
|
28
31
|
export interface SessionReadbackResult {
|
|
29
32
|
readonly line: string | null;
|
|
@@ -64,7 +67,7 @@ export declare function computeValueShowTrend(projectRoot: string, options?: {
|
|
|
64
67
|
now?: Date;
|
|
65
68
|
}): ValueShowTrend;
|
|
66
69
|
export declare function formatValueShowReport(trend: ValueShowTrend): string;
|
|
67
|
-
/** Pull-based value:show CLI core (#1709). */
|
|
70
|
+
/** Pull-based value:show CLI core (#1709) with composed ceremony-cost reader (#3508). */
|
|
68
71
|
export declare function runValueShow(options: {
|
|
69
72
|
projectRoot?: string | null;
|
|
70
73
|
window?: string;
|
package/dist/value/readback.js
CHANGED
|
@@ -8,6 +8,7 @@ import { DEFAULT_EVENT_LOG, readEvents } from "../lifecycle/events.js";
|
|
|
8
8
|
import { policyColonInvocation } from "../policy/policy-invocation.js";
|
|
9
9
|
import { isValueFeedbackPathAllowed, resolveValueFeedback, } from "../policy/value-feedback.js";
|
|
10
10
|
import { resolveProjectRoot } from "../scope/project-context.js";
|
|
11
|
+
import { computeCeremonyCostRollup, formatCeremonyCostReport, PROCESS_COST_EVENT_NAMES, } from "../session/process-cost.js";
|
|
11
12
|
import { MAX_LINE_CHARS } from "../triage/welcome/constants.js";
|
|
12
13
|
import { probeAdoptionAtWorkBoundary } from "./adoption-emit.js";
|
|
13
14
|
import { probeFrictionAtWorkBoundary } from "./friction-emit.js";
|
|
@@ -391,7 +392,36 @@ export function formatValueShowReport(trend) {
|
|
|
391
392
|
];
|
|
392
393
|
return `${lines.join("\n")}\n`;
|
|
393
394
|
}
|
|
394
|
-
|
|
395
|
+
function attachCeremonyCost(result, ceremonyCost, format) {
|
|
396
|
+
if (format === "json") {
|
|
397
|
+
const payload = result.trend !== null
|
|
398
|
+
? {
|
|
399
|
+
...result.trend,
|
|
400
|
+
ceremonyCost,
|
|
401
|
+
process_cost_events: PROCESS_COST_EVENT_NAMES,
|
|
402
|
+
gated: result.gated,
|
|
403
|
+
attribution_gated: result.gated,
|
|
404
|
+
}
|
|
405
|
+
: {
|
|
406
|
+
ceremonyCost,
|
|
407
|
+
process_cost_events: PROCESS_COST_EVENT_NAMES,
|
|
408
|
+
gated: result.gated,
|
|
409
|
+
attribution_gated: result.gated,
|
|
410
|
+
empty: result.empty,
|
|
411
|
+
};
|
|
412
|
+
return {
|
|
413
|
+
...result,
|
|
414
|
+
ceremonyCost,
|
|
415
|
+
text: `${JSON.stringify(payload, null, 2)}\n`,
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
return {
|
|
419
|
+
...result,
|
|
420
|
+
ceremonyCost,
|
|
421
|
+
text: `${result.text}${formatCeremonyCostReport(ceremonyCost)}`,
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
/** Pull-based value:show CLI core (#1709) with composed ceremony-cost reader (#3508). */
|
|
395
425
|
export function runValueShow(options) {
|
|
396
426
|
const rootRaw = resolveProjectRoot(options.projectRoot ?? undefined);
|
|
397
427
|
if (rootRaw === null) {
|
|
@@ -401,30 +431,39 @@ export function runValueShow(options) {
|
|
|
401
431
|
empty: true,
|
|
402
432
|
text: "Error: could not resolve project root.\n",
|
|
403
433
|
trend: null,
|
|
434
|
+
ceremonyCost: null,
|
|
404
435
|
};
|
|
405
436
|
}
|
|
406
437
|
const root = resolve(rootRaw);
|
|
438
|
+
const windowMs = parseWindowMs(options.window);
|
|
439
|
+
const ceremonyCost = computeCeremonyCostRollup({
|
|
440
|
+
projectRoot: root,
|
|
441
|
+
logPath: options.logPath,
|
|
442
|
+
windowMs,
|
|
443
|
+
now: options.now,
|
|
444
|
+
windowLabel: formatWindowLabel(windowMs),
|
|
445
|
+
});
|
|
407
446
|
if (maintainerReadbackDisabled(root)) {
|
|
408
|
-
return {
|
|
447
|
+
return attachCeremonyCost({
|
|
409
448
|
exitCode: 0,
|
|
410
|
-
gated:
|
|
449
|
+
gated: false,
|
|
411
450
|
empty: true,
|
|
412
|
-
text: "[value]
|
|
451
|
+
text: "[value] Attribution skipped: maintainer framework repo " +
|
|
452
|
+
"(set DEFT_VALUE_SELF_DOGFOOD=1 to dogfood).\n",
|
|
413
453
|
trend: null,
|
|
414
|
-
};
|
|
454
|
+
}, ceremonyCost, options.format);
|
|
415
455
|
}
|
|
416
456
|
const policy = options.policyOverride ?? resolveValueFeedback(root);
|
|
417
457
|
if (!policy.enabled) {
|
|
418
|
-
return {
|
|
458
|
+
return attachCeremonyCost({
|
|
419
459
|
exitCode: 1,
|
|
420
460
|
gated: true,
|
|
421
461
|
empty: true,
|
|
422
462
|
text: "[value] Blocked: plan.policy.valueFeedback is OFF. " +
|
|
423
463
|
`Enable with \`${policyColonInvocation("enable-value-feedback", " -- --confirm")}\`.\n`,
|
|
424
464
|
trend: null,
|
|
425
|
-
};
|
|
465
|
+
}, ceremonyCost, options.format);
|
|
426
466
|
}
|
|
427
|
-
const windowMs = parseWindowMs(options.window);
|
|
428
467
|
const trend = computeValueShowTrend(root, {
|
|
429
468
|
windowMs,
|
|
430
469
|
logPath: options.logPath,
|
|
@@ -432,21 +471,21 @@ export function runValueShow(options) {
|
|
|
432
471
|
});
|
|
433
472
|
const empty = trend.total === 0;
|
|
434
473
|
if (options.format === "json") {
|
|
435
|
-
return {
|
|
474
|
+
return attachCeremonyCost({
|
|
436
475
|
exitCode: 0,
|
|
437
476
|
gated: false,
|
|
438
477
|
empty,
|
|
439
478
|
text: `${JSON.stringify(trend, null, 2)}\n`,
|
|
440
479
|
trend,
|
|
441
|
-
};
|
|
480
|
+
}, ceremonyCost, "json");
|
|
442
481
|
}
|
|
443
|
-
return {
|
|
482
|
+
return attachCeremonyCost({
|
|
444
483
|
exitCode: 0,
|
|
445
484
|
gated: false,
|
|
446
485
|
empty,
|
|
447
486
|
text: formatValueShowReport(trend),
|
|
448
487
|
trend,
|
|
449
|
-
};
|
|
488
|
+
}, ceremonyCost, "text");
|
|
450
489
|
}
|
|
451
490
|
export function parseValueShowArgs(argv) {
|
|
452
491
|
const out = {};
|
|
@@ -9,6 +9,7 @@ export declare function computeDesiredLabels(plan: Record<string, unknown>, unre
|
|
|
9
9
|
export declare class ScmLabelClient implements LabelClient {
|
|
10
10
|
fetchLabels(repo: string, issueNumber: number): string[];
|
|
11
11
|
apply(repo: string, issueNumber: number, add: readonly string[], remove: readonly string[]): void;
|
|
12
|
+
private applyMut;
|
|
12
13
|
}
|
|
13
14
|
export interface ReconcileLabelsOptions {
|
|
14
15
|
readonly repo?: string | null;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
|
+
import { applyDesignCritiqueCatalogChip, isDesignCritiqueCatalogChip, } from "../design-critique/exclusive-chip.js";
|
|
3
4
|
import { hasArtifactSuffix, resolveLifecycleRoot, stripArtifactSuffix } from "../layout/resolve.js";
|
|
4
5
|
import { call } from "../scm/call.js";
|
|
5
6
|
import { extractIssueRef } from "../triage/reconcile/parse-uri.js";
|
|
@@ -69,6 +70,35 @@ export class ScmLabelClient {
|
|
|
69
70
|
return names;
|
|
70
71
|
}
|
|
71
72
|
apply(repo, issueNumber, add, remove) {
|
|
73
|
+
const catalogAdds = add.filter(isDesignCritiqueCatalogChip);
|
|
74
|
+
if (catalogAdds.length > 0) {
|
|
75
|
+
const nextChip = catalogAdds[catalogAdds.length - 1];
|
|
76
|
+
const restAdd = add.filter((name) => !isDesignCritiqueCatalogChip(name));
|
|
77
|
+
const restRemove = remove.filter((name) => !isDesignCritiqueCatalogChip(name));
|
|
78
|
+
let applied = false;
|
|
79
|
+
const inner = {
|
|
80
|
+
fetchLabels: (r, n) => this.fetchLabels(r, n),
|
|
81
|
+
apply: (r, n, a, rem) => {
|
|
82
|
+
applied = true;
|
|
83
|
+
const addSet = new Set([...a, ...restAdd]);
|
|
84
|
+
const removeSet = new Set([...rem, ...restRemove]);
|
|
85
|
+
for (const name of addSet)
|
|
86
|
+
removeSet.delete(name);
|
|
87
|
+
this.applyMut(r, n, [...addSet], [...removeSet]);
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
applyDesignCritiqueCatalogChip(inner, repo, issueNumber, nextChip);
|
|
91
|
+
if (!applied && (restAdd.length > 0 || restRemove.length > 0)) {
|
|
92
|
+
this.applyMut(repo, issueNumber, restAdd, restRemove);
|
|
93
|
+
}
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
this.applyMut(repo, issueNumber, add, remove);
|
|
97
|
+
}
|
|
98
|
+
applyMut(repo, issueNumber, add, remove) {
|
|
99
|
+
if (add.length === 0 && remove.length === 0) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
72
102
|
const args = ["edit", String(issueNumber), "--repo", repo];
|
|
73
103
|
for (const name of add)
|
|
74
104
|
args.push("--add-label", name);
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export type JsonObject = Record<string, unknown>;
|
|
2
|
+
export declare function resolveInfoBlock(data: JsonObject): {
|
|
3
|
+
key: "vBRIEFInfo" | "xBRIEFInfo";
|
|
4
|
+
info: JsonObject;
|
|
5
|
+
} | null;
|
|
2
6
|
/** Validate vBRIEF/xBRIEF structural requirements (v0.6 + v0.8 additive). */
|
|
3
7
|
export declare function validateVbriefSchema(data: JsonObject, filepath: string): string[];
|
|
4
8
|
/** Normalize a narrative key for D3 comparison. */
|
|
@@ -25,5 +25,12 @@ export interface StoryQualityParams {
|
|
|
25
25
|
readonly swarm: JsonObject;
|
|
26
26
|
readonly concurrentReady?: boolean;
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Shared Gate A text for `readiness=ready` + `parallel_safe: false` (#3666 / #3252).
|
|
30
|
+
* Authoring (`scope:decompose`) and launch (`swarm:readiness` / `swarm:launch`)
|
|
31
|
+
* both emit this string. It must not recommend `readiness=sequential` as a
|
|
32
|
+
* launch remediation — Gate B rejects that value on the same call.
|
|
33
|
+
*/
|
|
34
|
+
export declare const READY_REQUIRES_PARALLEL_SAFE = "readiness=ready requires parallel_safe=true. This story is not eligible for concurrent swarm:launch; dispatch non-concurrent work via the interactive swarm-skill solo-worker path (that path is not gated by swarm:readiness exiting 0; exit 0 gates concurrent workers only; see #3669)";
|
|
28
35
|
export declare function storyQualityIssues(params: StoryQualityParams): string[];
|
|
29
36
|
//# sourceMappingURL=story-quality.d.ts.map
|
|
@@ -266,6 +266,13 @@ export function deprecatedSubitemsIssues(items, prefix = "plan.items") {
|
|
|
266
266
|
visit(items, prefix);
|
|
267
267
|
return issues;
|
|
268
268
|
}
|
|
269
|
+
/**
|
|
270
|
+
* Shared Gate A text for `readiness=ready` + `parallel_safe: false` (#3666 / #3252).
|
|
271
|
+
* Authoring (`scope:decompose`) and launch (`swarm:readiness` / `swarm:launch`)
|
|
272
|
+
* both emit this string. It must not recommend `readiness=sequential` as a
|
|
273
|
+
* launch remediation — Gate B rejects that value on the same call.
|
|
274
|
+
*/
|
|
275
|
+
export const READY_REQUIRES_PARALLEL_SAFE = "readiness=ready requires parallel_safe=true. This story is not eligible for concurrent swarm:launch; dispatch non-concurrent work via the interactive swarm-skill solo-worker path (that path is not gated by swarm:readiness exiting 0; exit 0 gates concurrent workers only; see #3669)";
|
|
269
276
|
export function storyQualityIssues(params) {
|
|
270
277
|
const issues = [];
|
|
271
278
|
const concurrentReady = params.concurrentReady ?? true;
|
|
@@ -304,7 +311,7 @@ export function storyQualityIssues(params) {
|
|
|
304
311
|
issues.push(...fileScopeIssues(params.swarm));
|
|
305
312
|
issues.push(...verifyCommandIssues(params.swarm));
|
|
306
313
|
if (params.swarm.parallel_safe === false) {
|
|
307
|
-
issues.push(
|
|
314
|
+
issues.push(READY_REQUIRES_PARALLEL_SAFE);
|
|
308
315
|
}
|
|
309
316
|
if (params.swarm.file_scope_confidence === "low") {
|
|
310
317
|
issues.push("readiness=ready requires file_scope_confidence above low");
|
|
@@ -5,10 +5,10 @@ import { type AgentHookHealthResult } from "./agent-hooks.js";
|
|
|
5
5
|
import { type AgentHookLiveProbeResult, type AgentHookLiveProbeSeams } from "./agent-hooks-live-probe.js";
|
|
6
6
|
import type { OutputStream } from "./verify-hooks-installed.js";
|
|
7
7
|
export type AgentHookReadinessRegistration = "registered" | "disabled" | "missing" | "drifted" | "not-applicable";
|
|
8
|
-
export type AgentHookReadinessFunctionality = "functional" | "non-functional" | "unavailable" | "not-run" | "disabled" | "not-applicable";
|
|
8
|
+
export type AgentHookReadinessFunctionality = "functional" | "non-functional" | "unavailable" | "timed-out" | "not-run" | "disabled" | "not-applicable";
|
|
9
9
|
export type AgentHookReadinessTrust = "manual-review-required" | "not-applicable" | "disabled";
|
|
10
10
|
export type AgentHookReadinessInterception = "not-directly-verified" | "not-applicable" | "disabled";
|
|
11
|
-
export type AgentHookReadinessLiveStatus = "functional" | "non-functional" | "unavailable" | "not-run" | "disabled" | "skipped";
|
|
11
|
+
export type AgentHookReadinessLiveStatus = "functional" | "non-functional" | "unavailable" | "timed-out" | "not-run" | "disabled" | "skipped";
|
|
12
12
|
export interface AgentHookReadinessHostResult {
|
|
13
13
|
readonly host: HookHost;
|
|
14
14
|
readonly registration: AgentHookReadinessRegistration;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
2
|
import { resolveFrameworkRootForProject } from "../doctor/paths.js";
|
|
3
|
-
import { loadHostHooksPolicyFromProject } from "../policy/host-hooks.js";
|
|
3
|
+
import { loadHostHooksPolicyFromProject, UNUSED_HOST_HOOKS_RECOVERY, } from "../policy/host-hooks.js";
|
|
4
4
|
import { evaluateAgentHooks } from "./agent-hooks.js";
|
|
5
5
|
import { probeAgentHooksLive, } from "./agent-hooks-live-probe.js";
|
|
6
6
|
/** Stable CLI JSON projection; keep the four readiness dimensions orthogonal. */
|
|
@@ -114,31 +114,35 @@ export function evaluateAgentHookReadiness(projectRoot, options = {}) {
|
|
|
114
114
|
? "functional"
|
|
115
115
|
: liveStatus === "unavailable"
|
|
116
116
|
? "unavailable"
|
|
117
|
-
: liveStatus === "
|
|
118
|
-
? "
|
|
119
|
-
: "
|
|
117
|
+
: liveStatus === "timed-out"
|
|
118
|
+
? "timed-out"
|
|
119
|
+
: liveStatus === "non-functional"
|
|
120
|
+
? "non-functional"
|
|
121
|
+
: "not-run",
|
|
120
122
|
};
|
|
121
123
|
});
|
|
122
124
|
const allDisabled = enabledHosts.length === 0;
|
|
125
|
+
const timeoutOnly = liveProbe.cases.length > 0 && liveProbe.cases.every((entry) => entry.issue === "timed-out");
|
|
123
126
|
const liveStatus = allDisabled
|
|
124
127
|
? "disabled"
|
|
125
128
|
: liveProbe.code === 0
|
|
126
129
|
? "functional"
|
|
127
130
|
: liveProbe.code === 2
|
|
128
131
|
? "unavailable"
|
|
129
|
-
:
|
|
132
|
+
: timeoutOnly
|
|
133
|
+
? "timed-out"
|
|
134
|
+
: "non-functional";
|
|
130
135
|
const trustReview = policy.codex
|
|
131
136
|
? "\n Codex trust: manual-review-required. Open `/hooks` and approve the exact project hook commands. " +
|
|
132
137
|
"The live probe validates the shim and codec, not host interception."
|
|
133
138
|
: "";
|
|
139
|
+
const unusedHostRecovery = liveProbe.code === 0 || timeoutOnly ? "" : `\n ${UNUSED_HOST_HOOKS_RECOVERY}`;
|
|
134
140
|
return {
|
|
135
141
|
code: liveProbe.code,
|
|
136
142
|
message: `${liveProbe.code === 0 ? "✓" : "❌"} deft agent hook readiness: ${liveProbe.message}\n` +
|
|
137
143
|
renderHosts(evaluatedHosts) +
|
|
138
144
|
trustReview +
|
|
139
|
-
|
|
140
|
-
? ""
|
|
141
|
-
: "\n If an affected host is unused, inspect `deft policy:show --field=hostHooks`, set `plan.policy.hostHooks.<host> = false`, and run `deft update`."),
|
|
145
|
+
unusedHostRecovery,
|
|
142
146
|
stream: liveProbe.code === 0 ? "stdout" : "stderr",
|
|
143
147
|
skipped: false,
|
|
144
148
|
liveStatus,
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { type HookEvent, type HookHost } from "../hooks/dispatcher.js";
|
|
2
2
|
export declare const LIVE_PROBE_CASE_TIMEOUT_MS = 1500;
|
|
3
|
+
/** Extra attempts after a timeout. One retry keeps 4×2×1.5s×2 = 24s under Cursor 30s (#3570). */
|
|
4
|
+
export declare const LIVE_PROBE_CASE_RETRY_COUNT = 1;
|
|
5
|
+
export declare const LIVE_PROBE_TIMEOUT_RECOVERY = "Recovery: retry the gated ritual when load is lower. Do not reinstall @deftai/directive or disable hostHooks for a timeout.";
|
|
6
|
+
export declare const LIVE_PROBE_BROKEN_RECOVERY = "Recovery: reinstall @deftai/directive and run `deft update`.";
|
|
3
7
|
export type AgentHookLiveProbeIssue = "hook-command-missing" | "spawn-failed" | "timed-out" | "empty-stdout" | "unparseable-json" | "missing-allow" | "missing-deny";
|
|
4
8
|
export interface AgentHookLiveProbeCase {
|
|
5
9
|
readonly host: HookHost;
|
|
@@ -8,7 +12,7 @@ export interface AgentHookLiveProbeCase {
|
|
|
8
12
|
readonly issue: AgentHookLiveProbeIssue;
|
|
9
13
|
readonly detail: string;
|
|
10
14
|
}
|
|
11
|
-
export type AgentHookLiveProbeHostStatus = "functional" | "non-functional" | "unavailable";
|
|
15
|
+
export type AgentHookLiveProbeHostStatus = "functional" | "non-functional" | "unavailable" | "timed-out";
|
|
12
16
|
export interface AgentHookLiveProbeHostResult {
|
|
13
17
|
readonly host: HookHost;
|
|
14
18
|
readonly status: AgentHookLiveProbeHostStatus;
|
|
@@ -6,6 +6,10 @@ import { DEFT_HOOK_COMMAND_MARKER } from "../init-deposit/agent-hooks.js";
|
|
|
6
6
|
import { SUBPROCESS_MAX_BUFFER } from "../subprocess/max-buffer.js";
|
|
7
7
|
import { quoteWin32CommandForShell, resolveCommandOnPath, shouldUseShellForCommand, } from "./command-spawn.js";
|
|
8
8
|
export const LIVE_PROBE_CASE_TIMEOUT_MS = 1_500;
|
|
9
|
+
/** Extra attempts after a timeout. One retry keeps 4×2×1.5s×2 = 24s under Cursor 30s (#3570). */
|
|
10
|
+
export const LIVE_PROBE_CASE_RETRY_COUNT = 1;
|
|
11
|
+
export const LIVE_PROBE_TIMEOUT_RECOVERY = "Recovery: retry the gated ritual when load is lower. Do not reinstall @deftai/directive or disable hostHooks for a timeout.";
|
|
12
|
+
export const LIVE_PROBE_BROKEN_RECOVERY = "Recovery: reinstall @deftai/directive and run `deft update`.";
|
|
9
13
|
const LIVE_PROBE_EVENT = "tool.before";
|
|
10
14
|
function elapsedMs(started) {
|
|
11
15
|
return Math.max(0, Math.round(performance.now() - started));
|
|
@@ -122,21 +126,38 @@ function validateFixtureOutput(host, fixture, stdout) {
|
|
|
122
126
|
? { ok: true }
|
|
123
127
|
: { ok: false, issue: "missing-deny", detail: `expected ${host} deny envelope` };
|
|
124
128
|
}
|
|
129
|
+
function liveProbeRecovery(cases) {
|
|
130
|
+
if (cases.length > 0 && cases.every((entry) => entry.issue === "timed-out")) {
|
|
131
|
+
return LIVE_PROBE_TIMEOUT_RECOVERY;
|
|
132
|
+
}
|
|
133
|
+
return LIVE_PROBE_BROKEN_RECOVERY;
|
|
134
|
+
}
|
|
135
|
+
function hostStatusFromFailure(hostFailure) {
|
|
136
|
+
if (hostFailure === null)
|
|
137
|
+
return "functional";
|
|
138
|
+
if (hostFailure.issue === "timed-out")
|
|
139
|
+
return "timed-out";
|
|
140
|
+
return "non-functional";
|
|
141
|
+
}
|
|
125
142
|
function runFixtureProbe(command, host, projectRoot, fixture, spawnHook) {
|
|
126
|
-
const
|
|
143
|
+
const input = {
|
|
127
144
|
command,
|
|
128
145
|
args: ["--host", host, "--event", LIVE_PROBE_EVENT, "--project-root", projectRoot],
|
|
129
146
|
stdin: fixture === "allow" ? allowFixture(projectRoot) : denyFixture(projectRoot),
|
|
130
147
|
cwd: projectRoot,
|
|
131
148
|
env: fixture === "allow" ? process.env : denyProbeEnv(),
|
|
132
|
-
}
|
|
149
|
+
};
|
|
150
|
+
let spawned = spawnHook(input);
|
|
151
|
+
for (let retry = 0; retry < LIVE_PROBE_CASE_RETRY_COUNT && spawned.timedOut === true; retry += 1) {
|
|
152
|
+
spawned = spawnHook(input);
|
|
153
|
+
}
|
|
133
154
|
if (spawned.timedOut === true) {
|
|
134
155
|
return {
|
|
135
156
|
host,
|
|
136
157
|
event: LIVE_PROBE_EVENT,
|
|
137
158
|
fixture,
|
|
138
159
|
issue: "timed-out",
|
|
139
|
-
detail: `hook command exceeded ${LIVE_PROBE_CASE_TIMEOUT_MS}ms`,
|
|
160
|
+
detail: `hook command exceeded ${LIVE_PROBE_CASE_TIMEOUT_MS}ms after ${LIVE_PROBE_CASE_RETRY_COUNT + 1} attempts`,
|
|
140
161
|
};
|
|
141
162
|
}
|
|
142
163
|
if (spawned.status !== 0) {
|
|
@@ -204,7 +225,7 @@ export function probeAgentHooksLive(projectRoot, seams = {}) {
|
|
|
204
225
|
break;
|
|
205
226
|
}
|
|
206
227
|
}
|
|
207
|
-
hostResults.push({ host, status: hostFailure
|
|
228
|
+
hostResults.push({ host, status: hostStatusFromFailure(hostFailure) });
|
|
208
229
|
}
|
|
209
230
|
if (failures.length === 0) {
|
|
210
231
|
return {
|
|
@@ -220,7 +241,7 @@ export function probeAgentHooksLive(projectRoot, seams = {}) {
|
|
|
220
241
|
.join("; ");
|
|
221
242
|
return {
|
|
222
243
|
code: 1,
|
|
223
|
-
message: `deft agent hooks live probe FAILED: ${summary}.
|
|
244
|
+
message: `deft agent hooks live probe FAILED: ${summary}. ${liveProbeRecovery(failures)}`,
|
|
224
245
|
cases: failures,
|
|
225
246
|
hosts: hostResults,
|
|
226
247
|
durationMs: elapsedMs(started),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { statSync } from "node:fs";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { inspectAgentHookDeposit } from "../init-deposit/agent-hooks.js";
|
|
4
|
-
import { loadHostHooksPolicyFromProject } from "../policy/host-hooks.js";
|
|
4
|
+
import { loadHostHooksPolicyFromProject, UNUSED_HOST_HOOKS_RECOVERY, } from "../policy/host-hooks.js";
|
|
5
5
|
function isDirectory(path) {
|
|
6
6
|
try {
|
|
7
7
|
return statSync(path).isDirectory();
|
|
@@ -30,9 +30,8 @@ export function evaluateAgentHooks(projectRoot, hostHooksPolicy = loadHostHooksP
|
|
|
30
30
|
unhealthy
|
|
31
31
|
.map((entry) => ` - ${entry.host}: ${entry.status} at ${entry.path} — ${entry.detail}`)
|
|
32
32
|
.join("\n") +
|
|
33
|
-
"\n Recovery: run `deft update` (or `directive init`) to refresh project hooks." +
|
|
34
|
-
|
|
35
|
-
"set `plan.policy.hostHooks.<host> = false`, and run `deft update` again.",
|
|
33
|
+
"\n Recovery: run `deft update` (or `directive init`) to refresh project hooks. " +
|
|
34
|
+
UNUSED_HOST_HOOKS_RECOVERY,
|
|
36
35
|
stream: "stderr",
|
|
37
36
|
registrations,
|
|
38
37
|
};
|