@deftai/directive-core 0.70.0 → 0.71.1

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.
Files changed (79) hide show
  1. package/dist/branch/evaluate.js +7 -0
  2. package/dist/doctor/doctor-state.js +2 -2
  3. package/dist/eval/crud-telemetry.d.ts +59 -0
  4. package/dist/eval/crud-telemetry.js +307 -0
  5. package/dist/eval/health.d.ts +52 -0
  6. package/dist/eval/health.js +240 -0
  7. package/dist/eval/readback.d.ts +38 -0
  8. package/dist/eval/readback.js +209 -0
  9. package/dist/eval/report.d.ts +53 -0
  10. package/dist/eval/report.js +161 -0
  11. package/dist/eval/run.d.ts +79 -0
  12. package/dist/eval/run.js +309 -0
  13. package/dist/events/attribution-constants.d.ts +13 -0
  14. package/dist/events/attribution-constants.js +18 -0
  15. package/dist/events/attribution-ledger.d.ts +43 -0
  16. package/dist/events/attribution-ledger.js +61 -0
  17. package/dist/index.d.ts +5 -0
  18. package/dist/index.js +5 -0
  19. package/dist/init-deposit/gitignore.js +15 -5
  20. package/dist/intake/candidates-log.d.ts +0 -1
  21. package/dist/intake/candidates-log.js +5 -2
  22. package/dist/intake/issue-ingest.d.ts +8 -0
  23. package/dist/intake/issue-ingest.js +19 -1
  24. package/dist/intake/reconcile-issues.js +9 -2
  25. package/dist/layout/resolve.d.ts +2 -2
  26. package/dist/layout/resolve.js +2 -2
  27. package/dist/lifecycle/events.js +2 -0
  28. package/dist/orchestration/subagent-monitor.js +2 -2
  29. package/dist/policy/index.d.ts +2 -1
  30. package/dist/policy/index.js +15 -2
  31. package/dist/policy/value-feedback.d.ts +56 -0
  32. package/dist/policy/value-feedback.js +284 -0
  33. package/dist/preflight-cache/evaluate.js +4 -3
  34. package/dist/scope/audit-log.js +3 -3
  35. package/dist/scope/transition.js +16 -5
  36. package/dist/session/session-start.js +20 -0
  37. package/dist/slice/record.js +3 -3
  38. package/dist/task-surface/index.js +4 -1
  39. package/dist/triage/actions/candidates-log.d.ts +4 -4
  40. package/dist/triage/actions/candidates-log.js +4 -7
  41. package/dist/triage/actions/index.js +8 -32
  42. package/dist/triage/bootstrap/gitignore.d.ts +9 -3
  43. package/dist/triage/bootstrap/gitignore.js +77 -40
  44. package/dist/triage/bootstrap/index.d.ts +1 -1
  45. package/dist/triage/bootstrap/index.js +4 -3
  46. package/dist/triage/bulk/index.js +2 -2
  47. package/dist/triage/cache-path.d.ts +41 -0
  48. package/dist/triage/cache-path.js +115 -0
  49. package/dist/triage/help/registry-data.d.ts +48 -15
  50. package/dist/triage/help/registry-data.js +86 -15
  51. package/dist/triage/index.d.ts +2 -0
  52. package/dist/triage/index.js +2 -0
  53. package/dist/triage/queue/audit.js +2 -2
  54. package/dist/triage/queue/cache.js +2 -2
  55. package/dist/triage/reconcile/reconcile.js +4 -3
  56. package/dist/triage/scope/mutations-core.js +3 -2
  57. package/dist/triage/subscribe/index.d.ts +1 -1
  58. package/dist/triage/subscribe/index.js +4 -3
  59. package/dist/triage/summary/index.d.ts +2 -2
  60. package/dist/triage/summary/index.js +4 -3
  61. package/dist/triage/summary/reconcilable.d.ts +1 -1
  62. package/dist/triage/summary/reconcilable.js +3 -2
  63. package/dist/triage/welcome/constants.d.ts +2 -2
  64. package/dist/triage/welcome/constants.js +2 -2
  65. package/dist/triage/welcome/prior-state.js +3 -2
  66. package/dist/triage/welcome/summary.js +5 -4
  67. package/dist/value/adoption-emit.d.ts +14 -0
  68. package/dist/value/adoption-emit.js +67 -0
  69. package/dist/value/adoption-registry.d.ts +62 -0
  70. package/dist/value/adoption-registry.js +214 -0
  71. package/dist/value/feedback-file.d.ts +67 -0
  72. package/dist/value/feedback-file.js +353 -0
  73. package/dist/value/friction-emit.d.ts +10 -0
  74. package/dist/value/friction-emit.js +24 -0
  75. package/dist/value/readback.d.ts +86 -0
  76. package/dist/value/readback.js +503 -0
  77. package/dist/vbrief-validate/decomposition.js +1 -1
  78. package/dist/wip-cap/evaluate.js +3 -0
  79. package/package.json +35 -3
@@ -0,0 +1,61 @@
1
+ import { resolve } from "node:path";
2
+ import { DEFAULT_EVENT_LOG, emit } from "../lifecycle/events.js";
3
+ import { isValueFeedbackPathAllowed, resolveValueFeedback, } from "../policy/value-feedback.js";
4
+ import { ATTRIBUTION_EVENT_NAMES } from "./attribution-constants.js";
5
+ export { ALL_ATTRIBUTION_EVENT_NAMES, ATTRIBUTION_EVENT_NAMES, ATTRIBUTION_REQUIRED_PAYLOAD, } from "./attribution-constants.js";
6
+ function resolveLedgerLogPath(projectRoot, logPath) {
7
+ if (logPath !== undefined && logPath !== null) {
8
+ return resolve(logPath);
9
+ }
10
+ return resolve(projectRoot, DEFAULT_EVENT_LOG);
11
+ }
12
+ function signalClassForEvent(name) {
13
+ const prefix = name.split(":")[0];
14
+ if (prefix === "value" || prefix === "bypass" || prefix === "adoption" || prefix === "friction") {
15
+ return prefix;
16
+ }
17
+ throw new Error(`attribution event '${name}' has unknown signal-class prefix`);
18
+ }
19
+ /**
20
+ * Append an attribution ledger entry when valueFeedback emitEvents is allowed.
21
+ * Returns null when gated OFF (no disk write).
22
+ */
23
+ export function emitAttributionSignal(name, payload, options) {
24
+ try {
25
+ const policy = options.policyOverride ?? resolveValueFeedback(options.projectRoot);
26
+ if (!isValueFeedbackPathAllowed("emitEvents", policy)) {
27
+ return null;
28
+ }
29
+ const signalClass = signalClassForEvent(name);
30
+ const logPath = resolveLedgerLogPath(options.projectRoot, options.logPath);
31
+ return emit(name, {
32
+ signal_class: signalClass,
33
+ ...payload,
34
+ }, { logPath });
35
+ }
36
+ catch {
37
+ // Telemetry is best-effort; any failure must not interrupt gate callers (#1709).
38
+ return null;
39
+ }
40
+ }
41
+ /** Record a detection-bound gate catch (value class). */
42
+ export function recordGateCatch(projectRoot, source, detail, options = {}) {
43
+ return emitAttributionSignal(ATTRIBUTION_EVENT_NAMES.valueGateCatch, { source, detail }, { projectRoot, ...options });
44
+ }
45
+ /** Record a WIP-cap protect refusal (value class). */
46
+ export function recordWipCapProtect(projectRoot, count, cap, options = {}) {
47
+ return emitAttributionSignal(ATTRIBUTION_EVENT_NAMES.valueWipCapProtect, { source: "verify:wip-cap", count, cap }, { projectRoot, ...options });
48
+ }
49
+ /** Record a bypass/off-flow signal. */
50
+ export function recordBypassSignal(projectRoot, source, detail, options = {}) {
51
+ return emitAttributionSignal(ATTRIBUTION_EVENT_NAMES.bypassOffFlow, { source, detail }, { projectRoot, ...options });
52
+ }
53
+ /** Record an adoption/unused-capability signal. */
54
+ export function recordAdoptionSignal(projectRoot, capability, detail, options = {}) {
55
+ return emitAttributionSignal(ATTRIBUTION_EVENT_NAMES.adoptionUnusedCapability, { source: "adoption-registry", capability, detail }, { projectRoot, ...options });
56
+ }
57
+ /** Record a friction/directive-gap signal. */
58
+ export function recordFrictionSignal(projectRoot, source, detail, options = {}) {
59
+ return emitAttributionSignal(ATTRIBUTION_EVENT_NAMES.frictionDirectiveGap, { source, detail }, { projectRoot, ...options });
60
+ }
61
+ //# sourceMappingURL=attribution-ledger.js.map
package/dist/index.d.ts CHANGED
@@ -15,6 +15,11 @@ export * as capacity from "./capacity/index.js";
15
15
  export * as codebase from "./codebase/index.js";
16
16
  export * as doctor from "./doctor/index.js";
17
17
  export * from "./encoding/index.js";
18
+ export * as evalCrud from "./eval/crud-telemetry.js";
19
+ export * as evalHealth from "./eval/health.js";
20
+ export * as evalReport from "./eval/report.js";
21
+ export * as evalRun from "./eval/run.js";
22
+ export * as events from "./events/attribution-ledger.js";
18
23
  export * from "./forward-coverage/evaluate.js";
19
24
  export * as intake from "./intake/index.js";
20
25
  export * as layout from "./layout/index.js";
package/dist/index.js CHANGED
@@ -15,6 +15,11 @@ export * as capacity from "./capacity/index.js";
15
15
  export * as codebase from "./codebase/index.js";
16
16
  export * as doctor from "./doctor/index.js";
17
17
  export * from "./encoding/index.js";
18
+ export * as evalCrud from "./eval/crud-telemetry.js";
19
+ export * as evalHealth from "./eval/health.js";
20
+ export * as evalReport from "./eval/report.js";
21
+ export * as evalRun from "./eval/run.js";
22
+ export * as events from "./events/attribution-ledger.js";
18
23
  export * from "./forward-coverage/evaluate.js";
19
24
  export * as intake from "./intake/index.js";
20
25
  export * as layout from "./layout/index.js";
@@ -26,11 +26,21 @@ export const CANONICAL_GITIGNORE_BASELINE = [
26
26
  ".deft/ritual-state.json",
27
27
  ".deft/last-session.json",
28
28
  ".deft/routing.local.json",
29
- "vbrief/.eval/candidates.jsonl",
30
- "vbrief/.eval/summary-history.jsonl",
31
- "vbrief/.eval/scope-lifecycle.jsonl",
32
- "vbrief/.eval/decompositions/",
33
- "vbrief/.eval/doctor-state.json",
29
+ "vbrief/.triage-cache/candidates.jsonl",
30
+ "vbrief/.triage-cache/summary-history.jsonl",
31
+ "vbrief/.triage-cache/scope-lifecycle.jsonl",
32
+ "vbrief/.triage-cache/decompositions/",
33
+ "vbrief/.triage-cache/doctor-state.json",
34
+ // Symmetric `xbrief/` layout entries (#2348). On the migrated `xbrief/` tree
35
+ // the engine writes operator-private triage-cache files to
36
+ // `xbrief/.triage-cache/`; without these the paths are trackable, violating
37
+ // the #1144 hybrid policy. Both layouts are emitted (harmless extra lines on
38
+ // the layout not in use) to match the both-layout `.eval/` treatment.
39
+ "xbrief/.triage-cache/candidates.jsonl",
40
+ "xbrief/.triage-cache/summary-history.jsonl",
41
+ "xbrief/.triage-cache/scope-lifecycle.jsonl",
42
+ "xbrief/.triage-cache/decompositions/",
43
+ "xbrief/.triage-cache/doctor-state.json",
34
44
  "vbrief/*.lock",
35
45
  ".deft/core.bak-*/",
36
46
  ".deft/*.bak-*",
@@ -1,4 +1,3 @@
1
- export declare const DEFAULT_LOG_PATH: string;
2
1
  export declare class CandidatesLogError extends Error {
3
2
  constructor(message: string);
4
3
  }
@@ -2,7 +2,10 @@ import { randomUUID } from "node:crypto";
2
2
  import { closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, unlinkSync, writeSync, } from "node:fs";
3
3
  import { dirname, join, resolve } from "node:path";
4
4
  import { pyRepr } from "../scm/py-format.js";
5
- export const DEFAULT_LOG_PATH = resolve(import.meta.dirname, "..", "..", "..", "..", "vbrief", ".eval", "candidates.jsonl");
5
+ import { resolveCandidatesLogPath } from "../triage/cache-path.js";
6
+ function defaultLogPath() {
7
+ return resolveCandidatesLogPath(process.cwd());
8
+ }
6
9
  const VALID_DECISIONS = new Set([
7
10
  "accept",
8
11
  "reject",
@@ -105,7 +108,7 @@ function validateEntry(entry) {
105
108
  }
106
109
  }
107
110
  function resolvePath(path) {
108
- return path !== undefined && path !== null ? resolve(path) : DEFAULT_LOG_PATH;
111
+ return path !== undefined && path !== null ? resolve(path) : defaultLogPath();
109
112
  }
110
113
  function acquireAppendLock(logPath) {
111
114
  while (threadLocked) {
@@ -44,6 +44,14 @@ export interface FetchIssueOptions {
44
44
  readonly cacheRoot?: string | null;
45
45
  readonly scmCall?: ScmCallFn;
46
46
  }
47
+ /**
48
+ * Strip the `# #<number>: <title>` header that `renderContent` prepends when it
49
+ * materializes an issue's `content.md` at cache-put (#2314). The header is the
50
+ * only shape difference between the cache-read body and the live/raw-body path;
51
+ * removing it makes an ingested xBRIEF's `Overview` identical whether the source
52
+ * was a cache hit or a live fetch. A missing/older-shape header is left intact.
53
+ */
54
+ export declare function stripRenderedIssueHeader(content: string, number: number): string;
47
55
  export declare function fetchFromCache(repo: string, number: number, options?: FetchIssueOptions): Record<string, unknown> | null;
48
56
  export declare function fetchIssueComments(repo: string, number: number, options?: FetchIssueOptions): IssueComment[];
49
57
  export declare function attachIssueCommentThread(issue: Record<string, unknown>, comments: readonly IssueComment[]): Record<string, unknown>;
@@ -386,6 +386,20 @@ export function targetFilename(number, title, artifactSuffix = LEGACY_ARTIFACT_S
386
386
  const slug = slugify(title) || `issue-${number}`;
387
387
  return `${TODAY}-${number}-${slug}${artifactSuffix}`;
388
388
  }
389
+ /**
390
+ * Strip the `# #<number>: <title>` header that `renderContent` prepends when it
391
+ * materializes an issue's `content.md` at cache-put (#2314). The header is the
392
+ * only shape difference between the cache-read body and the live/raw-body path;
393
+ * removing it makes an ingested xBRIEF's `Overview` identical whether the source
394
+ * was a cache hit or a live fetch. A missing/older-shape header is left intact.
395
+ */
396
+ export function stripRenderedIssueHeader(content, number) {
397
+ if (!Number.isFinite(number)) {
398
+ return content;
399
+ }
400
+ const header = new RegExp(`^# #${number}:[^\\n]*\\n\\n`);
401
+ return content.replace(header, "");
402
+ }
389
403
  export function fetchFromCache(repo, number, options = {}) {
390
404
  const key = `${repo}/${number}`;
391
405
  try {
@@ -405,7 +419,11 @@ export function fetchFromCache(repo, number, options = {}) {
405
419
  // buildIssueVbrief.
406
420
  if (result.contentPath !== null) {
407
421
  try {
408
- issue.body = readFileSync(result.contentPath, "utf8");
422
+ // #2314: content.md is `renderContent`-prefixed with a `# #<n>: <title>`
423
+ // header at cache-put. Strip that header so the cache-read Overview
424
+ // matches the live/raw-body path (which has no header), keeping the
425
+ // durable xBRIEF identical for a cache hit vs a live fetch.
426
+ issue.body = stripRenderedIssueHeader(readFileSync(result.contentPath, "utf8"), Number(issue.number));
409
427
  }
410
428
  catch {
411
429
  // fall back to the raw body (re-scanned downstream)
@@ -6,6 +6,7 @@ import { call } from "../scm/call.js";
6
6
  import { updateDecomposedChildBackReferences } from "../scope/decomposed-refs.js";
7
7
  import { resolveProjectRoot } from "../scope/project-context.js";
8
8
  import { resolveProjectRepo } from "../slice/project-context.js";
9
+ import { LEGACY_INFO_ROOT_KEY, MIGRATED_INFO_ROOT_KEY } from "../xbrief-migrate/constants.js";
9
10
  export const LIFECYCLE_FOLDERS = [
10
11
  "proposed",
11
12
  "pending",
@@ -633,8 +634,14 @@ export function applyLifecycleFixes(vbriefDir, report, projectRoot = null) {
633
634
  const terminalStatus = destFolder === "cancelled" ? "cancelled" : "completed";
634
635
  plan.status = terminalStatus;
635
636
  const stamp = utcNowIso();
636
- const info = (data.vBRIEFInfo ?? {});
637
- data.vBRIEFInfo = info;
637
+ // Stamp `updated` into whichever info envelope the file already uses (#2346).
638
+ // Canonical v0.8 briefs use `xBRIEFInfo`; stamping `vBRIEFInfo` unconditionally
639
+ // appended a stray, version-less `vBRIEFInfo` block that then failed
640
+ // `vbrief:validate` ('vBRIEFInfo.version' must be one of ..., got 'undefined').
641
+ // Legacy briefs (or files without either envelope) keep the `vBRIEFInfo` key.
642
+ const infoKey = MIGRATED_INFO_ROOT_KEY in data ? MIGRATED_INFO_ROOT_KEY : LEGACY_INFO_ROOT_KEY;
643
+ const info = (data[infoKey] ?? {});
644
+ data[infoKey] = info;
638
645
  info.updated = stamp;
639
646
  plan.updated = stamp;
640
647
  propagateItemStatus(plan.items, terminalStatus, stamp);
@@ -51,9 +51,9 @@ export declare function resolveLifecycleRoot(projectRoot: string): string;
51
51
  * (e.g. `<root>/<xbrief|vbrief>/active`). Layout-aware (#2109 part 2a).
52
52
  */
53
53
  export declare function resolveLifecycleFolder(projectRoot: string, folder: string): string;
54
- /** Absolute path to the resolved lifecycle `.eval` cache directory (#2109 part 2a). */
54
+ /** Absolute path to the layout-aware `.eval/` directory for version-eval results (#1703). */
55
55
  export declare function resolveEvalDir(projectRoot: string): string;
56
- /** Absolute path to a file or subpath under the resolved `.eval` cache directory. */
56
+ /** Absolute path under `.eval/` for version-eval artefacts (not triage working-set). */
57
57
  export declare function resolveEvalPath(projectRoot: string, ...segments: string[]): string;
58
58
  /** Absolute path to the resolved lifecycle `.audit` directory (#2109 part 2a). */
59
59
  export declare function resolveAuditDir(projectRoot: string): string;
@@ -101,11 +101,11 @@ export function resolveLifecycleRoot(projectRoot) {
101
101
  export function resolveLifecycleFolder(projectRoot, folder) {
102
102
  return join(resolveLifecycleRoot(projectRoot), folder);
103
103
  }
104
- /** Absolute path to the resolved lifecycle `.eval` cache directory (#2109 part 2a). */
104
+ /** Absolute path to the layout-aware `.eval/` directory for version-eval results (#1703). */
105
105
  export function resolveEvalDir(projectRoot) {
106
106
  return join(resolveLifecycleRoot(projectRoot), ".eval");
107
107
  }
108
- /** Absolute path to a file or subpath under the resolved `.eval` cache directory. */
108
+ /** Absolute path under `.eval/` for version-eval artefacts (not triage working-set). */
109
109
  export function resolveEvalPath(projectRoot, ...segments) {
110
110
  return join(resolveEvalDir(projectRoot), ...segments);
111
111
  }
@@ -3,10 +3,12 @@ import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
3
3
  import { dirname, join, resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { contentRoot } from "../content-root.js";
6
+ import { ATTRIBUTION_REQUIRED_PAYLOAD } from "../events/attribution-constants.js";
6
7
  /** Default event log location (project-local). */
7
8
  export const DEFAULT_EVENT_LOG = join(".deft-cache", "events.jsonl");
8
9
  const BEHAVIORAL_CATEGORY = "behavioral";
9
10
  const REQUIRED_BEHAVIORAL_PAYLOAD = {
11
+ ...ATTRIBUTION_REQUIRED_PAYLOAD,
10
12
  "session:interrupted": ["session_id", "reason"],
11
13
  "session:resumed": ["session_id", "interrupted_id"],
12
14
  "plan:approved": ["plan_ref", "approver"],
@@ -379,8 +379,8 @@ export function cmdSubagentMonitor(argv, cwd = process.cwd()) {
379
379
  process.stderr.write(`Error: ${args.error}\n`);
380
380
  return EXIT_EXTERNAL_ERROR;
381
381
  }
382
- if (args.thresholdMinutes <= 0) {
383
- process.stderr.write(`Error: --threshold-minutes must be positive, got ${args.thresholdMinutes}\n`);
382
+ if (Number.isNaN(args.thresholdMinutes) || args.thresholdMinutes <= 0) {
383
+ process.stderr.write(`Error: --threshold-minutes must be a positive number, got ${args.thresholdMinutes}\n`);
384
384
  return EXIT_EXTERNAL_ERROR;
385
385
  }
386
386
  const scratchEntries = args.scratchDirs.length > 0
@@ -5,6 +5,7 @@ export * from "./decisions.js";
5
5
  export * from "./disclosure.js";
6
6
  export * from "./plan-extensions.js";
7
7
  export * from "./resolve.js";
8
+ export * from "./value-feedback.js";
8
9
  export * from "./wip.js";
9
10
  export declare const FIELD_ALLOW_DIRECT_COMMITS = "plan.policy.allowDirectCommitsToMaster";
10
11
  export declare const FIELD_WIP_CAP = "plan.policy.wipCap";
@@ -29,7 +30,7 @@ export interface PolicyField {
29
30
  }
30
31
  /** Walk registered inspectors and return one row per field (#1148). */
31
32
  export declare function inspectAllPolicies(projectRoot: string): PolicyField[];
32
- /** Look up a single registered field by canonical dotted-path name. */
33
+ /** Look up a single registered field by canonical dotted-path name (or CLI alias). */
33
34
  export declare function inspectOnePolicy(name: string, projectRoot: string): PolicyField | null;
34
35
  /** Return canonical names of every registered typed-policy field. */
35
36
  export declare function registeredPolicyNames(): string[];
@@ -1,5 +1,6 @@
1
1
  import { readPlanPolicy } from "./plan-extensions.js";
2
2
  import { coerceLegacyNarrative, LEGACY_NARRATIVE_KEY, loadProjectDefinition } from "./resolve.js";
3
+ import { FIELD_VALUE_FEEDBACK, FIELD_VALUE_FEEDBACK_CLI_ALIAS, inspectValueFeedback, } from "./value-feedback.js";
3
4
  import { DEFAULT_WIP_CAP } from "./wip.js";
4
5
  export * from "./agents-md-advisory.js";
5
6
  export * from "./autonomy.js";
@@ -8,6 +9,7 @@ export * from "./decisions.js";
8
9
  export * from "./disclosure.js";
9
10
  export * from "./plan-extensions.js";
10
11
  export * from "./resolve.js";
12
+ export * from "./value-feedback.js";
11
13
  export * from "./wip.js";
12
14
  export const FIELD_ALLOW_DIRECT_COMMITS = "plan.policy.allowDirectCommitsToMaster";
13
15
  export const FIELD_WIP_CAP = "plan.policy.wipCap";
@@ -213,6 +215,15 @@ function inspectSwarmSubagentBackend(data) {
213
215
  source: "default-on-error",
214
216
  };
215
217
  }
218
+ function inspectValueFeedbackField(data) {
219
+ const field = inspectValueFeedback(data);
220
+ return {
221
+ name: field.name,
222
+ current: field.current,
223
+ default: field.default,
224
+ source: field.source,
225
+ };
226
+ }
216
227
  const REGISTERED_POLICIES = [
217
228
  inspectAllowDirectCommits,
218
229
  inspectWipCap,
@@ -225,16 +236,18 @@ const REGISTERED_POLICIES = [
225
236
  emptyIsTyped: true,
226
237
  }),
227
238
  inspectSwarmSubagentBackend,
239
+ inspectValueFeedbackField,
228
240
  ];
229
241
  /** Walk registered inspectors and return one row per field (#1148). */
230
242
  export function inspectAllPolicies(projectRoot) {
231
243
  const [data] = loadProjectDefinition(projectRoot);
232
244
  return REGISTERED_POLICIES.map((inspect) => inspect(data));
233
245
  }
234
- /** Look up a single registered field by canonical dotted-path name. */
246
+ /** Look up a single registered field by canonical dotted-path name (or CLI alias). */
235
247
  export function inspectOnePolicy(name, projectRoot) {
248
+ const normalized = name === FIELD_VALUE_FEEDBACK_CLI_ALIAS ? FIELD_VALUE_FEEDBACK : name;
236
249
  for (const field of inspectAllPolicies(projectRoot)) {
237
- if (field.name === name)
250
+ if (field.name === normalized)
238
251
  return field;
239
252
  }
240
253
  return null;
@@ -0,0 +1,56 @@
1
+ /** Canonical registered policy field name (matches other FIELD_* dotted paths). */
2
+ export declare const FIELD_VALUE_FEEDBACK = "plan.policy.valueFeedback";
3
+ /** Short alias accepted by `policy:show --field=valueFeedback` (#1709). */
4
+ export declare const FIELD_VALUE_FEEDBACK_CLI_ALIAS = "valueFeedback";
5
+ export declare const DEFAULT_VALUE_FEEDBACK_ENABLED = false;
6
+ /** Sub-flag defaults applied when the master flag is enabled (#1709 tiered-cost decision). */
7
+ export declare const VALUE_FEEDBACK_SUBFLAG_DEFAULTS_WHEN_ENABLED: {
8
+ readonly emitEvents: true;
9
+ readonly sessionLine: true;
10
+ readonly upstreamPrompt: false;
11
+ };
12
+ export type ValueFeedbackSubFlag = keyof typeof VALUE_FEEDBACK_SUBFLAG_DEFAULTS_WHEN_ENABLED;
13
+ export interface ValueFeedbackConfig {
14
+ readonly enabled: boolean;
15
+ readonly emitEvents: boolean;
16
+ readonly sessionLine: boolean;
17
+ readonly upstreamPrompt: boolean;
18
+ }
19
+ export type ValueFeedbackSource = "typed" | "default" | "default-on-error";
20
+ export interface ValueFeedbackResolved extends ValueFeedbackConfig {
21
+ readonly source: ValueFeedbackSource;
22
+ readonly error: string | null;
23
+ }
24
+ export declare const VALUE_FEEDBACK_CAPABILITY_COST_DISCLOSURE: string;
25
+ /** Validate a `plan.policy.valueFeedback` payload. */
26
+ export declare function validateValueFeedback(value: unknown): string[];
27
+ /** Resolve `plan.policy.valueFeedback` from PROJECT-DEFINITION (#1709). */
28
+ export declare function resolveValueFeedback(projectRoot: string): ValueFeedbackResolved;
29
+ /** Master gate: when `enabled` is false, every downstream path is rejected. */
30
+ export declare function isValueFeedbackPathAllowed(path: ValueFeedbackSubFlag, policy: ValueFeedbackResolved): boolean;
31
+ /** Resolved per-path gate booleans for policy:show and enable status output. */
32
+ export declare function valueFeedbackPathGates(policy: ValueFeedbackResolved): Record<ValueFeedbackSubFlag, boolean>;
33
+ /** Human-readable status line for CLI enable/show surfaces. */
34
+ export declare function formatValueFeedbackStatusLine(policy: ValueFeedbackResolved): string;
35
+ export interface ValueFeedbackPolicyField {
36
+ readonly name: typeof FIELD_VALUE_FEEDBACK;
37
+ readonly current: ValueFeedbackConfig;
38
+ readonly default: ValueFeedbackConfig;
39
+ readonly source: string;
40
+ }
41
+ /** Inspector row for `policy:show --field=valueFeedback`. */
42
+ export declare function inspectValueFeedback(data: Record<string, unknown> | null): ValueFeedbackPolicyField;
43
+ export interface EnableValueFeedbackOptions {
44
+ readonly confirm: boolean;
45
+ readonly actor?: string;
46
+ readonly note?: string;
47
+ readonly subFlags?: Partial<Record<ValueFeedbackSubFlag, boolean>>;
48
+ }
49
+ export interface EnableValueFeedbackResult {
50
+ readonly exitCode: 0 | 1 | 2;
51
+ readonly stdout: string;
52
+ readonly changed: boolean;
53
+ }
54
+ /** Persist `valueFeedback.enabled=true` after capability-cost disclosure (#1709). */
55
+ export declare function enableValueFeedback(projectRoot: string, options: EnableValueFeedbackOptions): EnableValueFeedbackResult;
56
+ //# sourceMappingURL=value-feedback.d.ts.map