@deftai/directive-core 0.69.0 → 0.71.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/branch/evaluate.js +7 -0
- package/dist/deposit/contain.d.ts +41 -0
- package/dist/deposit/contain.js +113 -0
- package/dist/deposit/copy-tree.js +8 -2
- package/dist/doctor/checks.d.ts +11 -0
- package/dist/doctor/checks.js +75 -2
- package/dist/doctor/doctor-state.js +2 -2
- package/dist/doctor/main.js +54 -1
- package/dist/doctor/manifest.d.ts +20 -0
- package/dist/doctor/manifest.js +22 -0
- package/dist/doctor/types.d.ts +8 -0
- package/dist/eval/crud-telemetry.d.ts +59 -0
- package/dist/eval/crud-telemetry.js +307 -0
- package/dist/eval/health.d.ts +52 -0
- package/dist/eval/health.js +240 -0
- package/dist/eval/readback.d.ts +38 -0
- package/dist/eval/readback.js +209 -0
- package/dist/eval/report.d.ts +53 -0
- package/dist/eval/report.js +161 -0
- package/dist/eval/run.d.ts +79 -0
- package/dist/eval/run.js +309 -0
- package/dist/events/attribution-constants.d.ts +13 -0
- package/dist/events/attribution-constants.js +18 -0
- package/dist/events/attribution-ledger.d.ts +43 -0
- package/dist/events/attribution-ledger.js +61 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/init-deposit/gitignore.js +5 -5
- package/dist/init-deposit/init-deposit.js +6 -0
- package/dist/init-deposit/refresh.js +5 -0
- package/dist/intake/issue-ingest.d.ts +11 -0
- package/dist/intake/issue-ingest.js +86 -11
- package/dist/layout/resolve.d.ts +2 -2
- package/dist/layout/resolve.js +2 -2
- package/dist/lifecycle/events.js +2 -0
- package/dist/policy/index.d.ts +2 -1
- package/dist/policy/index.js +15 -2
- package/dist/policy/plan-extensions.d.ts +31 -0
- package/dist/policy/plan-extensions.js +45 -0
- package/dist/policy/value-feedback.d.ts +56 -0
- package/dist/policy/value-feedback.js +284 -0
- package/dist/policy/wip.d.ts +2 -2
- package/dist/policy/wip.js +2 -2
- package/dist/preflight-cache/evaluate.js +4 -3
- package/dist/scope/audit-log.js +3 -3
- package/dist/scope/transition.js +16 -5
- package/dist/session/session-start.js +20 -0
- package/dist/slice/record.js +3 -3
- package/dist/swarm/routing.js +10 -3
- package/dist/triage/actions/candidates-log.d.ts +4 -4
- package/dist/triage/actions/candidates-log.js +4 -7
- package/dist/triage/bootstrap/gitignore.d.ts +7 -3
- package/dist/triage/bootstrap/gitignore.js +67 -37
- package/dist/triage/bootstrap/index.d.ts +1 -1
- package/dist/triage/bootstrap/index.js +4 -3
- package/dist/triage/bulk/index.d.ts +11 -2
- package/dist/triage/bulk/index.js +43 -6
- package/dist/triage/cache-path.d.ts +39 -0
- package/dist/triage/cache-path.js +98 -0
- package/dist/triage/help/registry-data.d.ts +53 -20
- package/dist/triage/help/registry-data.js +104 -20
- package/dist/triage/index.d.ts +2 -0
- package/dist/triage/index.js +2 -0
- package/dist/triage/queue/audit.js +2 -2
- package/dist/triage/queue/cache.js +2 -2
- package/dist/triage/reconcile/reconcile.js +4 -3
- package/dist/triage/scope/cli.d.ts +2 -1
- package/dist/triage/scope/cli.js +30 -6
- package/dist/triage/scope/mutations-core.js +3 -2
- package/dist/triage/scope/mutations.d.ts +10 -0
- package/dist/triage/scope/mutations.js +22 -0
- package/dist/triage/subscribe/index.d.ts +1 -1
- package/dist/triage/subscribe/index.js +4 -3
- package/dist/triage/summary/index.d.ts +2 -2
- package/dist/triage/summary/index.js +4 -3
- package/dist/triage/summary/reconcilable.d.ts +1 -1
- package/dist/triage/summary/reconcilable.js +3 -2
- package/dist/triage/welcome/constants.d.ts +3 -4
- package/dist/triage/welcome/constants.js +3 -4
- package/dist/triage/welcome/index.d.ts +1 -0
- package/dist/triage/welcome/index.js +1 -0
- package/dist/triage/welcome/onboard.d.ts +35 -0
- package/dist/triage/welcome/onboard.js +94 -0
- package/dist/triage/welcome/prior-state.js +3 -2
- package/dist/triage/welcome/summary.js +5 -4
- package/dist/umbrella-current-shape/index.d.ts +25 -1
- package/dist/umbrella-current-shape/index.js +84 -4
- package/dist/value/adoption-emit.d.ts +14 -0
- package/dist/value/adoption-emit.js +67 -0
- package/dist/value/adoption-registry.d.ts +62 -0
- package/dist/value/adoption-registry.js +214 -0
- package/dist/value/feedback-file.d.ts +67 -0
- package/dist/value/feedback-file.js +353 -0
- package/dist/value/friction-emit.d.ts +10 -0
- package/dist/value/friction-emit.js +24 -0
- package/dist/value/readback.d.ts +86 -0
- package/dist/value/readback.js +503 -0
- package/dist/vbrief-build/project-definition-io.d.ts +6 -0
- package/dist/vbrief-build/project-definition-io.js +7 -2
- package/dist/vbrief-validate/decomposition.js +1 -1
- package/dist/vbrief-validate/precutover.js +7 -3
- package/dist/wip-cap/evaluate.js +3 -0
- package/package.json +35 -3
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { recordAdoptionSignal } from "../events/attribution-ledger.js";
|
|
3
|
+
import { isValueFeedbackPathAllowed, resolveValueFeedback, } from "../policy/value-feedback.js";
|
|
4
|
+
import { detectApplicableButUnusedGated } from "./adoption-registry.js";
|
|
5
|
+
/** Best-effort WorkContext snapshot from git porcelain status (#2339). */
|
|
6
|
+
export function buildWorkContextFromGit(projectRoot) {
|
|
7
|
+
try {
|
|
8
|
+
const porcelain = execFileSync("git", ["status", "--porcelain"], {
|
|
9
|
+
cwd: projectRoot,
|
|
10
|
+
encoding: "utf8",
|
|
11
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
12
|
+
});
|
|
13
|
+
const paths = new Set();
|
|
14
|
+
for (const line of porcelain.split("\n")) {
|
|
15
|
+
if (line.length < 4) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
let path = line.slice(3).trim();
|
|
19
|
+
if (path.startsWith('"') && path.endsWith('"')) {
|
|
20
|
+
path = path.slice(1, -1);
|
|
21
|
+
}
|
|
22
|
+
if (path.length > 0) {
|
|
23
|
+
paths.add(path);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const modules = new Set();
|
|
27
|
+
for (const filePath of paths) {
|
|
28
|
+
const segment = filePath.split("/")[0];
|
|
29
|
+
if (segment !== undefined && segment.length > 0) {
|
|
30
|
+
modules.add(segment);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
filesTouched: paths.size,
|
|
35
|
+
distinctModuleGlobs: modules.size,
|
|
36
|
+
usedCapabilities: [],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return { filesTouched: 0, distinctModuleGlobs: 0, usedCapabilities: [] };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Record adoption signals for applicable-but-unused capabilities (#2339). */
|
|
44
|
+
export function recordAdoptionSignalsFromWorkContext(projectRoot, ctx, options = {}) {
|
|
45
|
+
const policy = options.policyOverride ?? resolveValueFeedback(projectRoot);
|
|
46
|
+
if (!isValueFeedbackPathAllowed("emitEvents", policy)) {
|
|
47
|
+
return 0;
|
|
48
|
+
}
|
|
49
|
+
const signals = detectApplicableButUnusedGated(ctx, policy);
|
|
50
|
+
let recorded = 0;
|
|
51
|
+
for (const signal of signals) {
|
|
52
|
+
const record = recordAdoptionSignal(projectRoot, signal.capabilityId, signal.message, {
|
|
53
|
+
logPath: options.logPath,
|
|
54
|
+
policyOverride: policy,
|
|
55
|
+
});
|
|
56
|
+
if (record !== null) {
|
|
57
|
+
recorded += 1;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return recorded;
|
|
61
|
+
}
|
|
62
|
+
/** Session/work-boundary adoption probe — builds WorkContext when omitted (#2339). */
|
|
63
|
+
export function probeAdoptionAtWorkBoundary(projectRoot, options = {}) {
|
|
64
|
+
const ctx = options.workContext ?? buildWorkContextFromGit(projectRoot);
|
|
65
|
+
return recordAdoptionSignalsFromWorkContext(projectRoot, ctx, options);
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=adoption-emit.js.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type ValueFeedbackResolved } from "../policy/value-feedback.js";
|
|
2
|
+
/** Canonical directive capabilities tracked for underutilization nudges (#1709). */
|
|
3
|
+
export type CapabilityId = "planning" | "cost" | "decompose" | "swarm" | "pre-pr" | "debug" | "glossary" | "lessons";
|
|
4
|
+
/** How downstream instrumentation knows a capability was exercised. */
|
|
5
|
+
export type UsageSignalSource = "command:/deft:directive:run:interview" | "command:/deft:directive:run:speckit" | "command:task capacity:show" | "command:split-to-prs" | "command:task swarm:launch" | "skill:deft-directive-pre-pr" | "skill:debug-mode" | "command:/deft:glossary" | "command:deft packs:slice";
|
|
6
|
+
export interface CapabilityRecord {
|
|
7
|
+
readonly id: CapabilityId;
|
|
8
|
+
readonly label: string;
|
|
9
|
+
readonly description: string;
|
|
10
|
+
readonly usageSignals: readonly UsageSignalSource[];
|
|
11
|
+
readonly nudgeHint: string;
|
|
12
|
+
}
|
|
13
|
+
/** Work snapshot supplied by callers when evaluating adoption heuristics. */
|
|
14
|
+
export interface WorkContext {
|
|
15
|
+
readonly filesTouched: number;
|
|
16
|
+
/** Distinct module globs from the codebase map (parallelizability proxy). */
|
|
17
|
+
readonly distinctModuleGlobs: number;
|
|
18
|
+
readonly usedCapabilities: readonly CapabilityId[];
|
|
19
|
+
readonly isBuildIntent?: boolean;
|
|
20
|
+
readonly isPrOpening?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface ApplicabilityVerdict {
|
|
23
|
+
readonly applicable: boolean;
|
|
24
|
+
readonly reason: string;
|
|
25
|
+
}
|
|
26
|
+
export interface AdoptionSignal {
|
|
27
|
+
readonly signalClass: "adoption";
|
|
28
|
+
readonly event: string;
|
|
29
|
+
readonly capabilityId: CapabilityId;
|
|
30
|
+
readonly message: string;
|
|
31
|
+
readonly evidence: Readonly<Record<string, unknown>>;
|
|
32
|
+
}
|
|
33
|
+
/** Conservative thresholds — adoption nudges fire only above these bars (#1709). */
|
|
34
|
+
export declare const ADOPTION_THRESHOLDS: {
|
|
35
|
+
readonly smallWorkMaxFiles: 2;
|
|
36
|
+
readonly planningMinFiles: 4;
|
|
37
|
+
readonly costMinFiles: 3;
|
|
38
|
+
readonly largeMultiFileMinFiles: 5;
|
|
39
|
+
readonly largeMultiFileMinModules: 2;
|
|
40
|
+
readonly swarmMinFiles: 8;
|
|
41
|
+
readonly swarmMinModules: 3;
|
|
42
|
+
readonly glossaryMinFiles: 6;
|
|
43
|
+
readonly lessonsMinFiles: 5;
|
|
44
|
+
};
|
|
45
|
+
export declare const ADOPTION_SIGNAL_CLASS: "adoption";
|
|
46
|
+
/** Event name for the attribution ledger (`adoption:<capability>`). */
|
|
47
|
+
export declare function formatAdoptionEventName(id: CapabilityId): string;
|
|
48
|
+
/** True when work is too small for any adoption nudge (#1709-adoption-registry-a3). */
|
|
49
|
+
export declare function isWorkTooSmallForAdoptionNudges(ctx: WorkContext): boolean;
|
|
50
|
+
/** Evaluate whether a capability's conservative heuristic applies to the work snapshot. */
|
|
51
|
+
export declare function evaluateApplicability(id: CapabilityId, ctx: WorkContext): ApplicabilityVerdict;
|
|
52
|
+
/**
|
|
53
|
+
* Detect applicable-but-unused capabilities (#1709-adoption-registry-a2).
|
|
54
|
+
* Does not consult the value-feedback policy — use `detectApplicableButUnusedGated`.
|
|
55
|
+
*/
|
|
56
|
+
export declare function detectApplicableButUnused(ctx: WorkContext): AdoptionSignal[];
|
|
57
|
+
/**
|
|
58
|
+
* Policy-gated adoption detection — returns signals only when value feedback
|
|
59
|
+
* is enabled and the emitEvents path is allowed (#1709 opt-in gate).
|
|
60
|
+
*/
|
|
61
|
+
export declare function detectApplicableButUnusedGated(ctx: WorkContext, policy: ValueFeedbackResolved): AdoptionSignal[];
|
|
62
|
+
//# sourceMappingURL=adoption-registry.d.ts.map
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { isValueFeedbackPathAllowed, } from "../policy/value-feedback.js";
|
|
2
|
+
/** Conservative thresholds — adoption nudges fire only above these bars (#1709). */
|
|
3
|
+
export const ADOPTION_THRESHOLDS = {
|
|
4
|
+
smallWorkMaxFiles: 2,
|
|
5
|
+
planningMinFiles: 4,
|
|
6
|
+
costMinFiles: 3,
|
|
7
|
+
largeMultiFileMinFiles: 5,
|
|
8
|
+
largeMultiFileMinModules: 2,
|
|
9
|
+
swarmMinFiles: 8,
|
|
10
|
+
swarmMinModules: 3,
|
|
11
|
+
glossaryMinFiles: 6,
|
|
12
|
+
lessonsMinFiles: 5,
|
|
13
|
+
};
|
|
14
|
+
export const ADOPTION_SIGNAL_CLASS = "adoption";
|
|
15
|
+
const CAPABILITY_CATALOG = [
|
|
16
|
+
{
|
|
17
|
+
id: "planning",
|
|
18
|
+
label: "Planning",
|
|
19
|
+
description: "Structured spec interview or speckit planning before implementation.",
|
|
20
|
+
usageSignals: ["command:/deft:directive:run:interview", "command:/deft:directive:run:speckit"],
|
|
21
|
+
nudgeHint: "Consider `/deft:directive:run:interview` or `/deft:directive:run:speckit` before a multi-file build.",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: "cost",
|
|
25
|
+
label: "Cost awareness",
|
|
26
|
+
description: "Capacity/cost phase before committing to a build.",
|
|
27
|
+
usageSignals: ["command:task capacity:show"],
|
|
28
|
+
nudgeHint: "Run `task capacity:show` before a build to surface allocation targets.",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: "decompose",
|
|
32
|
+
label: "Decompose",
|
|
33
|
+
description: "Split large multi-file work into reviewable PRs.",
|
|
34
|
+
usageSignals: ["command:split-to-prs"],
|
|
35
|
+
nudgeHint: "Large multi-file work may benefit from split-to-prs decomposition.",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "swarm",
|
|
39
|
+
label: "Swarm",
|
|
40
|
+
description: "Parallel agent dispatch for disjoint multi-story cohorts.",
|
|
41
|
+
usageSignals: ["command:task swarm:launch"],
|
|
42
|
+
nudgeHint: "Disjoint multi-story work may benefit from `task swarm:launch`.",
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: "pre-pr",
|
|
46
|
+
label: "Pre-PR loop",
|
|
47
|
+
description: "Iterative pre-PR quality loop before opening a pull request.",
|
|
48
|
+
usageSignals: ["skill:deft-directive-pre-pr"],
|
|
49
|
+
nudgeHint: "Run the deft-directive-pre-pr skill before opening a PR.",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "debug",
|
|
53
|
+
label: "Debug mode",
|
|
54
|
+
description: "Systematic debug workflow for failures and regressions.",
|
|
55
|
+
usageSignals: ["skill:debug-mode"],
|
|
56
|
+
nudgeHint: "Switch to debug mode when chasing a failure systematically.",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: "glossary",
|
|
60
|
+
label: "Glossary",
|
|
61
|
+
description: "Project glossary for unfamiliar domain terms.",
|
|
62
|
+
usageSignals: ["command:/deft:glossary"],
|
|
63
|
+
nudgeHint: "Consult `/deft:glossary` when domain terms are ambiguous.",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: "lessons",
|
|
67
|
+
label: "Lessons packs",
|
|
68
|
+
description: "Prior-art slices from directive content packs.",
|
|
69
|
+
usageSignals: ["command:deft packs:slice"],
|
|
70
|
+
nudgeHint: "Load a lessons pack slice before improvising on a novel problem.",
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
function usedSet(ctx) {
|
|
74
|
+
return new Set(ctx.usedCapabilities);
|
|
75
|
+
}
|
|
76
|
+
function verdict(applicable, reason) {
|
|
77
|
+
return { applicable, reason };
|
|
78
|
+
}
|
|
79
|
+
const APPLICABILITY_RULES = {
|
|
80
|
+
planning(ctx) {
|
|
81
|
+
if (ctx.isPrOpening) {
|
|
82
|
+
return verdict(false, "at PR-open boundary — planning phase is past");
|
|
83
|
+
}
|
|
84
|
+
if (ctx.filesTouched < ADOPTION_THRESHOLDS.planningMinFiles) {
|
|
85
|
+
return verdict(false, "scope below planning threshold");
|
|
86
|
+
}
|
|
87
|
+
return verdict(true, "multi-file scope without a planning pass");
|
|
88
|
+
},
|
|
89
|
+
cost(ctx) {
|
|
90
|
+
if (!ctx.isBuildIntent) {
|
|
91
|
+
return verdict(false, "not a build-intent session");
|
|
92
|
+
}
|
|
93
|
+
if (ctx.filesTouched < ADOPTION_THRESHOLDS.costMinFiles) {
|
|
94
|
+
return verdict(false, "build scope below cost threshold");
|
|
95
|
+
}
|
|
96
|
+
return verdict(true, "build intent without a cost phase");
|
|
97
|
+
},
|
|
98
|
+
decompose(ctx) {
|
|
99
|
+
if (ctx.filesTouched < ADOPTION_THRESHOLDS.largeMultiFileMinFiles) {
|
|
100
|
+
return verdict(false, "file count below large multi-file threshold");
|
|
101
|
+
}
|
|
102
|
+
if (ctx.distinctModuleGlobs < ADOPTION_THRESHOLDS.largeMultiFileMinModules) {
|
|
103
|
+
return verdict(false, "work is not parallelizable across modules");
|
|
104
|
+
}
|
|
105
|
+
return verdict(true, "large multi-file parallelizable work");
|
|
106
|
+
},
|
|
107
|
+
swarm(ctx) {
|
|
108
|
+
if (ctx.filesTouched < ADOPTION_THRESHOLDS.swarmMinFiles) {
|
|
109
|
+
return verdict(false, "file count below swarm threshold");
|
|
110
|
+
}
|
|
111
|
+
if (ctx.distinctModuleGlobs < ADOPTION_THRESHOLDS.swarmMinModules) {
|
|
112
|
+
return verdict(false, "insufficient module breadth for swarm cohort");
|
|
113
|
+
}
|
|
114
|
+
return verdict(true, "broad parallelizable cohort scope");
|
|
115
|
+
},
|
|
116
|
+
"pre-pr"(ctx) {
|
|
117
|
+
if (!ctx.isPrOpening) {
|
|
118
|
+
return verdict(false, "not at PR-open boundary");
|
|
119
|
+
}
|
|
120
|
+
return verdict(true, "PR opening without pre-PR loop");
|
|
121
|
+
},
|
|
122
|
+
debug(_ctx) {
|
|
123
|
+
return verdict(false, "debug nudges require an explicit failure signal");
|
|
124
|
+
},
|
|
125
|
+
glossary(ctx) {
|
|
126
|
+
if (ctx.filesTouched < ADOPTION_THRESHOLDS.glossaryMinFiles) {
|
|
127
|
+
return verdict(false, "scope below glossary threshold");
|
|
128
|
+
}
|
|
129
|
+
return verdict(true, "broad unfamiliar scope");
|
|
130
|
+
},
|
|
131
|
+
lessons(ctx) {
|
|
132
|
+
if (ctx.filesTouched < ADOPTION_THRESHOLDS.lessonsMinFiles) {
|
|
133
|
+
return verdict(false, "scope below lessons threshold");
|
|
134
|
+
}
|
|
135
|
+
return verdict(true, "novel multi-file scope");
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
/** Return the full capability catalog (#1709-adoption-registry-a1). */
|
|
139
|
+
function listCapabilities() {
|
|
140
|
+
return CAPABILITY_CATALOG;
|
|
141
|
+
}
|
|
142
|
+
/** Lookup a single catalog entry by id. */
|
|
143
|
+
function getCapability(id) {
|
|
144
|
+
return CAPABILITY_CATALOG.find((entry) => entry.id === id);
|
|
145
|
+
}
|
|
146
|
+
/** Event name for the attribution ledger (`adoption:<capability>`). */
|
|
147
|
+
export function formatAdoptionEventName(id) {
|
|
148
|
+
return `${ADOPTION_SIGNAL_CLASS}:${id}`;
|
|
149
|
+
}
|
|
150
|
+
/** True when work is too small for any adoption nudge (#1709-adoption-registry-a3). */
|
|
151
|
+
export function isWorkTooSmallForAdoptionNudges(ctx) {
|
|
152
|
+
return ctx.filesTouched <= ADOPTION_THRESHOLDS.smallWorkMaxFiles;
|
|
153
|
+
}
|
|
154
|
+
/** Evaluate whether a capability's conservative heuristic applies to the work snapshot. */
|
|
155
|
+
export function evaluateApplicability(id, ctx) {
|
|
156
|
+
if (isWorkTooSmallForAdoptionNudges(ctx)) {
|
|
157
|
+
return verdict(false, "small work — adoption nudges suppressed");
|
|
158
|
+
}
|
|
159
|
+
return APPLICABILITY_RULES[id](ctx);
|
|
160
|
+
}
|
|
161
|
+
function buildAdoptionSignal(id, ctx, applicability) {
|
|
162
|
+
const record = getCapability(id);
|
|
163
|
+
if (record === undefined) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
signalClass: ADOPTION_SIGNAL_CLASS,
|
|
168
|
+
event: formatAdoptionEventName(record.id),
|
|
169
|
+
capabilityId: record.id,
|
|
170
|
+
message: record.nudgeHint,
|
|
171
|
+
evidence: {
|
|
172
|
+
filesTouched: ctx.filesTouched,
|
|
173
|
+
distinctModuleGlobs: ctx.distinctModuleGlobs,
|
|
174
|
+
usageSignals: record.usageSignals,
|
|
175
|
+
applicabilityReason: applicability.reason,
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Detect applicable-but-unused capabilities (#1709-adoption-registry-a2).
|
|
181
|
+
* Does not consult the value-feedback policy — use `detectApplicableButUnusedGated`.
|
|
182
|
+
*/
|
|
183
|
+
export function detectApplicableButUnused(ctx) {
|
|
184
|
+
if (isWorkTooSmallForAdoptionNudges(ctx)) {
|
|
185
|
+
return [];
|
|
186
|
+
}
|
|
187
|
+
const used = usedSet(ctx);
|
|
188
|
+
const signals = [];
|
|
189
|
+
for (const record of listCapabilities()) {
|
|
190
|
+
if (used.has(record.id)) {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const applicability = evaluateApplicability(record.id, ctx);
|
|
194
|
+
if (!applicability.applicable) {
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
const signal = buildAdoptionSignal(record.id, ctx, applicability);
|
|
198
|
+
if (signal !== null) {
|
|
199
|
+
signals.push(signal);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return signals;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Policy-gated adoption detection — returns signals only when value feedback
|
|
206
|
+
* is enabled and the emitEvents path is allowed (#1709 opt-in gate).
|
|
207
|
+
*/
|
|
208
|
+
export function detectApplicableButUnusedGated(ctx, policy) {
|
|
209
|
+
if (!isValueFeedbackPathAllowed("emitEvents", policy)) {
|
|
210
|
+
return [];
|
|
211
|
+
}
|
|
212
|
+
return detectApplicableButUnused(ctx);
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=adoption-registry.js.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type GhRestSeams } from "../scm/gh-rest.js";
|
|
2
|
+
export declare const DEFAULT_UPSTREAM_REPO = "deftai/directive";
|
|
3
|
+
export declare const FRAMEWORK_GAP_TITLE_PREFIX = "[framework-gap]";
|
|
4
|
+
export type FeedbackFileOutcome = "draft" | "filed" | "skipped-maintainer" | "blocked-policy" | "blocked-duplicate" | "blocked-no-confirm" | "error-bad-args" | "error-config" | "error-network";
|
|
5
|
+
export interface FeedbackGapInput {
|
|
6
|
+
readonly summary: string;
|
|
7
|
+
readonly context?: string;
|
|
8
|
+
readonly expected?: string;
|
|
9
|
+
readonly actual?: string;
|
|
10
|
+
readonly sessionNotes?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface FeedbackFileOptions extends FeedbackGapInput {
|
|
13
|
+
readonly projectRoot?: string | null;
|
|
14
|
+
readonly repo?: string;
|
|
15
|
+
readonly confirm?: boolean;
|
|
16
|
+
readonly dryRun?: boolean;
|
|
17
|
+
readonly json?: boolean;
|
|
18
|
+
readonly seams?: GhRestSeams;
|
|
19
|
+
}
|
|
20
|
+
export interface FeedbackFileResult {
|
|
21
|
+
readonly outcome: FeedbackFileOutcome;
|
|
22
|
+
readonly exitCode: 0 | 1 | 2;
|
|
23
|
+
readonly title: string;
|
|
24
|
+
readonly body: string;
|
|
25
|
+
readonly repo: string;
|
|
26
|
+
readonly issueUrl?: string | null;
|
|
27
|
+
readonly duplicateUrl?: string | null;
|
|
28
|
+
readonly message: string;
|
|
29
|
+
}
|
|
30
|
+
/** True when the resolved project root is the directive maintainer source checkout. */
|
|
31
|
+
export declare function isMaintainerFrameworkRepo(projectRoot: string): boolean;
|
|
32
|
+
/** Normalize a title for duplicate comparison (#1709). */
|
|
33
|
+
export declare function normalizeForDedup(title: string): string;
|
|
34
|
+
/** Build the upstream issue title for a framework-gap report. */
|
|
35
|
+
export declare function buildFrameworkGapTitle(summary: string): string;
|
|
36
|
+
/** Build the structured framework-gap issue body. */
|
|
37
|
+
export declare function buildFrameworkGapBody(input: FeedbackGapInput): string;
|
|
38
|
+
export interface DuplicateMatch {
|
|
39
|
+
readonly url: string;
|
|
40
|
+
readonly title: string;
|
|
41
|
+
}
|
|
42
|
+
/** Search open upstream issues for a normalized title match. */
|
|
43
|
+
export declare function findDuplicateIssue(repo: string, title: string, seams?: GhRestSeams): DuplicateMatch | null;
|
|
44
|
+
/** Core feedback:file workflow (#1709 gap escalation). */
|
|
45
|
+
export declare function runFeedbackFile(options: FeedbackFileOptions): FeedbackFileResult;
|
|
46
|
+
export interface FeedbackFileCliArgs {
|
|
47
|
+
summary?: string;
|
|
48
|
+
context?: string;
|
|
49
|
+
expected?: string;
|
|
50
|
+
actual?: string;
|
|
51
|
+
sessionNotes?: string;
|
|
52
|
+
confirm?: boolean;
|
|
53
|
+
dryRun?: boolean;
|
|
54
|
+
json?: boolean;
|
|
55
|
+
repo?: string;
|
|
56
|
+
projectRoot?: string;
|
|
57
|
+
error?: string;
|
|
58
|
+
}
|
|
59
|
+
/** Parse argv for feedback:file. */
|
|
60
|
+
export declare function parseFeedbackFileArgs(argv: readonly string[]): FeedbackFileCliArgs;
|
|
61
|
+
/** CLI entry for feedback:file. */
|
|
62
|
+
export declare function feedbackFileMain(argv: readonly string[]): number;
|
|
63
|
+
/** CLI module entrypoint for dispatch (#1709). */
|
|
64
|
+
export declare function mainEntry(argv?: string[]): number;
|
|
65
|
+
/** Convenience probe used in tests for project-root sentinel presence. */
|
|
66
|
+
export declare function projectRootLooksLikeConsumer(projectRoot: string): boolean;
|
|
67
|
+
//# sourceMappingURL=feedback-file.d.ts.map
|