@deftai/directive-core 0.104.0 → 0.105.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 +526 -42
- package/dist/check/cached-orchestrator.d.ts +1 -1
- package/dist/check/cached-orchestrator.js +2 -2
- package/dist/check/named-cause.d.ts +1 -1
- package/dist/check/named-cause.js +33 -3
- package/dist/codebase/default-extractor.d.ts +5 -0
- package/dist/codebase/default-extractor.js +7 -15
- package/dist/deposit/copy-tree.js +60 -0
- package/dist/deposit/python-free.js +26 -18
- package/dist/doctor/checks.d.ts +8 -0
- package/dist/doctor/checks.js +37 -25
- package/dist/doctor/doctor-state.d.ts +4 -0
- package/dist/doctor/doctor-state.js +7 -1
- package/dist/doctor/main.js +9 -19
- package/dist/doctor/types.d.ts +9 -0
- package/dist/fs/contained-write.d.ts +115 -1
- package/dist/fs/contained-write.js +241 -5
- package/dist/fs/mutation-ledger.d.ts +54 -0
- package/dist/fs/mutation-ledger.js +133 -0
- package/dist/fs/non-product-dirs.d.ts +79 -0
- package/dist/fs/non-product-dirs.js +96 -0
- package/dist/hooks/dispatcher.d.ts +3 -1
- package/dist/hooks/dispatcher.js +14 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/init-deposit/agent-hooks.js +17 -15
- package/dist/init-deposit/core-guard-pin-content.d.ts +7 -0
- package/dist/init-deposit/core-guard-pin-content.js +393 -0
- package/dist/init-deposit/gitignore.js +9 -0
- package/dist/init-deposit/hygiene.d.ts +47 -11
- package/dist/init-deposit/hygiene.js +172 -37
- package/dist/init-deposit/legacy-detect.js +6 -2
- package/dist/init-deposit/refresh.d.ts +21 -1
- package/dist/init-deposit/refresh.js +106 -9
- package/dist/init-deposit/scaffold.js +28 -279
- package/dist/init-deposit/slash-deposit.js +13 -7
- package/dist/init-deposit/xbrief-projections.d.ts +8 -1
- package/dist/init-deposit/xbrief-projections.js +24 -11
- package/dist/intake/clause-derivation.d.ts +38 -1
- package/dist/intake/clause-derivation.js +211 -9
- package/dist/intake/issue-ingest.d.ts +3 -1
- package/dist/intake/issue-ingest.js +35 -6
- package/dist/lifecycle/completed-tracked-on-delivery.d.ts +5 -0
- package/dist/lifecycle/completed-tracked-on-delivery.js +85 -18
- package/dist/literal-acceptance/capture.d.ts +10 -0
- package/dist/literal-acceptance/capture.js +224 -75
- package/dist/literal-acceptance/evaluate.d.ts +29 -4
- package/dist/literal-acceptance/evaluate.js +70 -2
- package/dist/literal-acceptance/index.d.ts +3 -3
- package/dist/literal-acceptance/index.js +3 -3
- package/dist/literal-acceptance/safety.d.ts +41 -0
- package/dist/literal-acceptance/safety.js +126 -2
- package/dist/literal-acceptance/types.d.ts +8 -0
- package/dist/orphan-active/evaluate.d.ts +7 -1
- package/dist/orphan-active/evaluate.js +102 -23
- package/dist/platform/platform-capabilities.js +2 -3
- package/dist/policy/base-branch.d.ts +37 -0
- package/dist/policy/base-branch.js +114 -0
- package/dist/policy/branch-sync.d.ts +80 -0
- package/dist/policy/branch-sync.js +211 -0
- package/dist/policy/ceremony-dial-escalation.js +1 -0
- package/dist/policy/ceremony-dial.js +4 -14
- package/dist/policy/delivery-branch.d.ts +5 -3
- package/dist/policy/delivery-branch.js +7 -3
- package/dist/policy/file-size-thresholds.d.ts +24 -0
- package/dist/policy/file-size-thresholds.js +23 -0
- package/dist/policy/forge-outage-retry.d.ts +47 -0
- package/dist/policy/forge-outage-retry.js +157 -0
- package/dist/policy/index.d.ts +7 -0
- package/dist/policy/index.js +66 -7
- package/dist/policy/project-invariants.d.ts +50 -0
- package/dist/policy/project-invariants.js +205 -0
- package/dist/policy/sync-default.d.ts +129 -0
- package/dist/policy/sync-default.js +452 -0
- package/dist/policy/sync-max-files.d.ts +93 -0
- package/dist/policy/sync-max-files.js +192 -0
- package/dist/pr-monitor/absent-required.d.ts +11 -0
- package/dist/pr-monitor/absent-required.js +61 -0
- package/dist/pr-monitor/constants.d.ts +7 -0
- package/dist/pr-monitor/constants.js +7 -0
- package/dist/pr-monitor/index.d.ts +2 -1
- package/dist/pr-monitor/index.js +2 -1
- package/dist/pr-monitor/main.js +4 -0
- package/dist/pr-monitor/monitor.js +24 -1
- package/dist/pr-wait-mergeable/classify.js +6 -0
- package/dist/preflight/evaluate.d.ts +4 -0
- package/dist/preflight/evaluate.js +35 -1
- package/dist/preflight/index.d.ts +4 -0
- package/dist/preflight/index.js +2 -0
- package/dist/preflight/intended-placement.d.ts +62 -0
- package/dist/preflight/intended-placement.js +275 -0
- package/dist/preflight/project-invariants-gate.d.ts +29 -0
- package/dist/preflight/project-invariants-gate.js +82 -0
- package/dist/product-first-done-gate/acceptance-resolver.d.ts +128 -0
- package/dist/product-first-done-gate/acceptance-resolver.js +144 -0
- package/dist/product-first-done-gate/acceptance.d.ts +7 -4
- package/dist/product-first-done-gate/acceptance.js +79 -8
- package/dist/product-first-done-gate/empty-resolution.d.ts +4 -1
- package/dist/product-first-done-gate/empty-resolution.js +12 -1
- package/dist/product-first-done-gate/evaluate.d.ts +12 -0
- package/dist/product-first-done-gate/evaluate.js +254 -31
- package/dist/product-first-done-gate/index.d.ts +2 -0
- package/dist/product-first-done-gate/index.js +1 -0
- package/dist/release/build-dist.d.ts +101 -0
- package/dist/release/build-dist.js +428 -46
- package/dist/run-summary/emit.d.ts +16 -10
- package/dist/run-summary/emit.js +26 -15
- package/dist/run-summary/index.d.ts +3 -2
- package/dist/run-summary/index.js +2 -1
- package/dist/run-summary/session-id.d.ts +21 -0
- package/dist/run-summary/session-id.js +92 -0
- package/dist/run-summary/types.d.ts +29 -4
- package/dist/run-summary/types.js +1 -0
- package/dist/scope/acceptance-evidence.d.ts +19 -7
- package/dist/scope/acceptance-evidence.js +38 -11
- package/dist/scope/delivery-evidence.d.ts +3 -3
- package/dist/scope/delivery-evidence.js +22 -27
- package/dist/scope/index.d.ts +1 -0
- package/dist/scope/index.js +1 -0
- package/dist/scope/parent-lineage.js +7 -6
- package/dist/scope/project-invariant-coverage.d.ts +54 -0
- package/dist/scope/project-invariant-coverage.js +322 -0
- package/dist/scope/transition.js +1 -1
- package/dist/scope-provenance/compare-intent.d.ts +27 -0
- package/dist/scope-provenance/compare-intent.js +233 -0
- package/dist/scope-provenance/digest.d.ts +18 -1
- package/dist/scope-provenance/digest.js +16 -11
- package/dist/scope-provenance/evaluate.d.ts +5 -1
- package/dist/scope-provenance/evaluate.js +64 -4
- package/dist/scope-provenance/extract-intent.d.ts +43 -0
- package/dist/scope-provenance/extract-intent.js +262 -0
- package/dist/scope-provenance/index.d.ts +7 -1
- package/dist/scope-provenance/index.js +7 -1
- package/dist/scope-provenance/intent-digest.d.ts +12 -0
- package/dist/scope-provenance/intent-digest.js +33 -0
- package/dist/scope-provenance/intent-evaluate.d.ts +43 -0
- package/dist/scope-provenance/intent-evaluate.js +149 -0
- package/dist/scope-provenance/json-tokenizer.d.ts +19 -0
- package/dist/scope-provenance/json-tokenizer.js +225 -0
- package/dist/scope-provenance/known-machine.d.ts +38 -0
- package/dist/scope-provenance/known-machine.js +157 -0
- package/dist/scope-provenance/mint-artifacts.d.ts +102 -0
- package/dist/scope-provenance/mint-artifacts.js +425 -0
- package/dist/session/ac-pass-banking.d.ts +4 -36
- package/dist/session/ac-pass-banking.js +30 -77
- package/dist/session/ac-pass-reuse.d.ts +53 -0
- package/dist/session/ac-pass-reuse.js +95 -0
- package/dist/session/git.js +19 -4
- package/dist/session/index.d.ts +4 -0
- package/dist/session/index.js +4 -0
- package/dist/session/occupancy-stress-worker.d.ts +7 -0
- package/dist/session/occupancy-stress-worker.js +36 -0
- package/dist/session/occupancy.d.ts +97 -0
- package/dist/session/occupancy.js +422 -0
- package/dist/session/openclaw-soft-rebind-deposit.js +6 -6
- package/dist/session/product-state-hash.d.ts +26 -0
- package/dist/session/product-state-hash.js +683 -0
- package/dist/session/session-ready.d.ts +2 -0
- package/dist/session/session-ready.js +52 -30
- package/dist/session/session-start.d.ts +7 -0
- package/dist/session/session-start.js +71 -7
- package/dist/session/verify-ac-session-cache.d.ts +42 -0
- package/dist/session/verify-ac-session-cache.js +126 -0
- package/dist/session/verify-session-ritual.d.ts +5 -0
- package/dist/session/verify-session-ritual.js +9 -0
- package/dist/slash/openclaw-deposit.js +13 -9
- package/dist/slice/constants.d.ts +2 -2
- package/dist/slice/constants.js +2 -2
- package/dist/slice/existing.js +9 -3
- package/dist/slice/lock.d.ts +16 -1
- package/dist/slice/lock.js +137 -11
- package/dist/story-ready/evaluate.d.ts +2 -0
- package/dist/story-ready/evaluate.js +13 -0
- package/dist/swarm/complete-cohort.d.ts +3 -0
- package/dist/swarm/complete-cohort.js +59 -11
- package/dist/swarm/finalize-cohort.js +33 -2
- package/dist/swarm/launch.d.ts +22 -0
- package/dist/swarm/launch.js +155 -0
- package/dist/swarm/routing-set-cli.d.ts +11 -1
- package/dist/swarm/routing-set-cli.js +13 -3
- package/dist/swarm/routing-verify.d.ts +12 -0
- package/dist/swarm/routing-verify.js +59 -20
- package/dist/swarm/routing.d.ts +14 -0
- package/dist/swarm/routing.js +53 -3
- package/dist/telemetry-coverage/fake-trial.js +10 -0
- package/dist/telemetry-coverage/kinds.js +2 -0
- package/dist/triage/actions/index.js +4 -1
- package/dist/ts-check-lane/index.d.ts +3 -0
- package/dist/ts-check-lane/index.js +2 -0
- package/dist/ts-check-lane/progress-reporter.d.ts +17 -0
- package/dist/ts-check-lane/progress-reporter.js +38 -0
- package/dist/ts-check-lane/progress.d.ts +32 -0
- package/dist/ts-check-lane/progress.js +57 -0
- package/dist/ts-check-lane/run-lane.d.ts +3 -1
- package/dist/ts-check-lane/run-lane.js +8 -6
- package/dist/validate-content/validate-links.d.ts +8 -0
- package/dist/validate-content/validate-links.js +9 -15
- package/dist/value/feedback-file.js +12 -2
- package/dist/vbrief-build/index.d.ts +1 -0
- package/dist/vbrief-build/index.js +1 -0
- package/dist/vbrief-build/project-invariants-io.d.ts +16 -0
- package/dist/vbrief-build/project-invariants-io.js +41 -0
- package/dist/vbrief-reconcile/graph.js +18 -1
- package/dist/vbrief-reconcile/index.d.ts +1 -1
- package/dist/vbrief-reconcile/index.js +1 -1
- package/dist/vbrief-reconcile/types.d.ts +13 -0
- package/dist/vbrief-reconcile/umbrellas.d.ts +14 -0
- package/dist/vbrief-reconcile/umbrellas.js +261 -26
- package/dist/vbrief-validate/index.d.ts +1 -1
- package/dist/vbrief-validate/index.js +1 -1
- package/dist/vbrief-validate/plan-hooks.d.ts +4 -0
- package/dist/vbrief-validate/plan-hooks.js +68 -0
- package/dist/verify-ac/evaluate.d.ts +7 -1
- package/dist/verify-ac/evaluate.js +34 -26
- package/dist/verify-ac/flag.d.ts +4 -0
- package/dist/verify-ac/flag.js +16 -0
- package/dist/verify-ac/index.d.ts +2 -2
- package/dist/verify-ac/index.js +2 -2
- package/dist/verify-source/contained-writes.js +2 -0
- package/dist/verify-source/verify-stubs.d.ts +15 -1
- package/dist/verify-source/verify-stubs.js +20 -16
- package/dist/vitest-runner/win32-coverage-tmp-setup.d.ts +5 -6
- package/dist/vitest-runner/win32-coverage-tmp-setup.js +5 -6
- package/dist/xbrief-migrate/migrate-project.js +2 -5
- package/package.json +3 -3
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed plan.policy.syncMaxFiles (#3390 / #3377 Wave 2).
|
|
3
|
+
*
|
|
4
|
+
* One integer. Unset is 400. `--max-files` overrides one run and does not
|
|
5
|
+
* write policy. Set 100 if SLizard is a required check. Do not probe
|
|
6
|
+
* reviewer APIs and do not encode vendor limits as code constants.
|
|
7
|
+
*
|
|
8
|
+
* File-count warn uses the shared #3388 detector. Count is
|
|
9
|
+
* `git diff --name-only origin/<dest>...origin/<source>`. No warn when
|
|
10
|
+
* the detector says this is not a sync. The #3391 verb consumes
|
|
11
|
+
* evaluateSyncMaxFilesWarn and the maxFiles one-run override.
|
|
12
|
+
*/
|
|
13
|
+
import { defaultGitRunner } from "../session/git.js";
|
|
14
|
+
import { detectBranchSyncFromProject } from "./branch-sync.js";
|
|
15
|
+
import { readPlanPolicy } from "./plan-extensions.js";
|
|
16
|
+
import { loadProjectDefinition } from "./resolve.js";
|
|
17
|
+
export const FIELD_SYNC_MAX_FILES = "plan.policy.syncMaxFiles";
|
|
18
|
+
export const FIELD_SYNC_MAX_FILES_CLI_ALIAS = "syncMaxFiles";
|
|
19
|
+
/** Unset threshold. Not a vendor limit. */
|
|
20
|
+
export const DEFAULT_SYNC_MAX_FILES = 400;
|
|
21
|
+
/**
|
|
22
|
+
* Operator docs for the threshold. Recommendation only — not a coded
|
|
23
|
+
* Greptile or SLizard constant.
|
|
24
|
+
*/
|
|
25
|
+
export const SYNC_MAX_FILES_DOCS = "Unset is 400. Set plan.policy.syncMaxFiles to 100 if SLizard is a required check.";
|
|
26
|
+
function isValidMaxFiles(raw) {
|
|
27
|
+
return typeof raw === "number" && Number.isInteger(raw) && raw >= 0;
|
|
28
|
+
}
|
|
29
|
+
/** Parse `--max-files`. Invalid or absent values are ignored. */
|
|
30
|
+
export function parseMaxFilesFlag(raw) {
|
|
31
|
+
if (!isValidMaxFiles(raw))
|
|
32
|
+
return null;
|
|
33
|
+
return raw;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Resolve the file-count threshold.
|
|
37
|
+
*
|
|
38
|
+
* `--max-files` (maxFiles) wins for this call only and is never written.
|
|
39
|
+
*/
|
|
40
|
+
export function resolveSyncMaxFiles(projectRoot, maxFiles) {
|
|
41
|
+
const flag = parseMaxFilesFlag(maxFiles);
|
|
42
|
+
if (flag !== null) {
|
|
43
|
+
return {
|
|
44
|
+
maxFiles: flag,
|
|
45
|
+
source: "flag",
|
|
46
|
+
provenance: "flag",
|
|
47
|
+
error: null,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (projectRoot !== undefined && projectRoot !== null && projectRoot.length > 0) {
|
|
51
|
+
const [data, err] = loadProjectDefinition(projectRoot);
|
|
52
|
+
if (data !== null) {
|
|
53
|
+
const policyBlock = readPlanPolicy(data.plan);
|
|
54
|
+
if (typeof policyBlock === "object" &&
|
|
55
|
+
policyBlock !== null &&
|
|
56
|
+
!Array.isArray(policyBlock) &&
|
|
57
|
+
"syncMaxFiles" in policyBlock) {
|
|
58
|
+
const raw = policyBlock.syncMaxFiles;
|
|
59
|
+
if (isValidMaxFiles(raw)) {
|
|
60
|
+
return {
|
|
61
|
+
maxFiles: raw,
|
|
62
|
+
source: "typed",
|
|
63
|
+
provenance: "policy",
|
|
64
|
+
error: null,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
maxFiles: DEFAULT_SYNC_MAX_FILES,
|
|
69
|
+
source: "default-on-error",
|
|
70
|
+
provenance: "default",
|
|
71
|
+
error: `${FIELD_SYNC_MAX_FILES} must be a non-negative integer; got ${String(raw)}`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else if (err !== null && err.length > 0) {
|
|
76
|
+
return {
|
|
77
|
+
maxFiles: DEFAULT_SYNC_MAX_FILES,
|
|
78
|
+
source: "default",
|
|
79
|
+
provenance: "default",
|
|
80
|
+
error: err,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
maxFiles: DEFAULT_SYNC_MAX_FILES,
|
|
86
|
+
source: "default",
|
|
87
|
+
provenance: "default",
|
|
88
|
+
error: null,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** Inspector row for `task policy:show --field=syncMaxFiles`. */
|
|
92
|
+
export function inspectSyncMaxFiles(_data, projectRoot) {
|
|
93
|
+
const resolved = resolveSyncMaxFiles(projectRoot);
|
|
94
|
+
return {
|
|
95
|
+
name: FIELD_SYNC_MAX_FILES,
|
|
96
|
+
current: resolved.maxFiles,
|
|
97
|
+
default: DEFAULT_SYNC_MAX_FILES,
|
|
98
|
+
source: resolved.source === "flag" ? "default" : resolved.source,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/** Count files in `origin/<dest>...origin/<source>`. */
|
|
102
|
+
export function countSyncChangedFiles(options) {
|
|
103
|
+
const dest = options.dest.trim();
|
|
104
|
+
const source = options.source.trim();
|
|
105
|
+
if (dest.length === 0 || source.length === 0) {
|
|
106
|
+
return { count: null, error: "empty dest or source" };
|
|
107
|
+
}
|
|
108
|
+
const runGit = options.runGit ?? defaultGitRunner;
|
|
109
|
+
runGit(options.projectRoot, ["fetch", "--quiet", "origin", dest]);
|
|
110
|
+
const ranged = `origin/${dest}...origin/${source}`;
|
|
111
|
+
const diffed = runGit(options.projectRoot, ["diff", "--name-only", ranged]);
|
|
112
|
+
if (diffed.code !== 0) {
|
|
113
|
+
return { count: null, error: diffed.stderr || `git diff failed for ${ranged}` };
|
|
114
|
+
}
|
|
115
|
+
const files = diffed.stdout.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
116
|
+
return { count: files.length, error: null };
|
|
117
|
+
}
|
|
118
|
+
export function formatSyncMaxFilesWarn(options) {
|
|
119
|
+
return (`file-count warn: ${options.count} files origin/${options.dest}...origin/${options.source} ` +
|
|
120
|
+
`exceeds syncMaxFiles=${options.threshold} (${options.provenance})`);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Warn when a detected sync exceeds syncMaxFiles.
|
|
124
|
+
*
|
|
125
|
+
* No warn when the shared detector says this is not a sync.
|
|
126
|
+
*/
|
|
127
|
+
export function evaluateSyncMaxFilesWarn(input) {
|
|
128
|
+
const runGit = input.runGit ?? defaultGitRunner;
|
|
129
|
+
const sync = input.sync ??
|
|
130
|
+
detectBranchSyncFromProject({
|
|
131
|
+
projectRoot: input.projectRoot,
|
|
132
|
+
prBase: input.prBase,
|
|
133
|
+
headSha: input.headSha,
|
|
134
|
+
runGit,
|
|
135
|
+
});
|
|
136
|
+
const resolved = resolveSyncMaxFiles(input.projectRoot, input.maxFiles);
|
|
137
|
+
const empty = {
|
|
138
|
+
warn: false,
|
|
139
|
+
reason: "not-sync",
|
|
140
|
+
count: null,
|
|
141
|
+
threshold: resolved.maxFiles,
|
|
142
|
+
provenance: resolved.provenance,
|
|
143
|
+
dest: sync.dest,
|
|
144
|
+
source: sync.source,
|
|
145
|
+
message: "",
|
|
146
|
+
};
|
|
147
|
+
if (!sync.isSync) {
|
|
148
|
+
return empty;
|
|
149
|
+
}
|
|
150
|
+
const counted = countSyncChangedFiles({
|
|
151
|
+
dest: sync.dest,
|
|
152
|
+
source: sync.source,
|
|
153
|
+
projectRoot: input.projectRoot,
|
|
154
|
+
runGit,
|
|
155
|
+
});
|
|
156
|
+
if (counted.count === null) {
|
|
157
|
+
return {
|
|
158
|
+
...empty,
|
|
159
|
+
reason: "diff-failed",
|
|
160
|
+
message: counted.error ?? "git diff failed",
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
if (counted.count <= resolved.maxFiles) {
|
|
164
|
+
return {
|
|
165
|
+
warn: false,
|
|
166
|
+
reason: "within-limit",
|
|
167
|
+
count: counted.count,
|
|
168
|
+
threshold: resolved.maxFiles,
|
|
169
|
+
provenance: resolved.provenance,
|
|
170
|
+
dest: sync.dest,
|
|
171
|
+
source: sync.source,
|
|
172
|
+
message: "",
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
warn: true,
|
|
177
|
+
reason: "exceeds",
|
|
178
|
+
count: counted.count,
|
|
179
|
+
threshold: resolved.maxFiles,
|
|
180
|
+
provenance: resolved.provenance,
|
|
181
|
+
dest: sync.dest,
|
|
182
|
+
source: sync.source,
|
|
183
|
+
message: formatSyncMaxFilesWarn({
|
|
184
|
+
count: counted.count,
|
|
185
|
+
threshold: resolved.maxFiles,
|
|
186
|
+
provenance: resolved.provenance,
|
|
187
|
+
dest: sync.dest,
|
|
188
|
+
source: sync.source,
|
|
189
|
+
}),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=sync-max-files.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consume #3234 `ci_absent_required` from a readiness payload.
|
|
3
|
+
* Returns missing context names, or null when the poll is not absent-required.
|
|
4
|
+
* Pending required check-runs are a wait, not an absence.
|
|
5
|
+
*/
|
|
6
|
+
export declare function readAbsentRequiredContexts(payload: Record<string, unknown>): readonly string[] | null;
|
|
7
|
+
/** True once consecutive absent polls have passed the first-poll grace window. */
|
|
8
|
+
export declare function shouldEscalateAbsentRequired(consecutivePolls: number, gracePolls?: number): boolean;
|
|
9
|
+
/** Distinct exit naming that lists the missing required contexts. */
|
|
10
|
+
export declare function formatAbsentRequiredMessage(contexts: readonly string[]): string;
|
|
11
|
+
//# sourceMappingURL=absent-required.d.ts.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ABSENT_REQUIRED_GRACE_POLLS } from "./constants.js";
|
|
2
|
+
function asRecord(value) {
|
|
3
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
4
|
+
return null;
|
|
5
|
+
}
|
|
6
|
+
return value;
|
|
7
|
+
}
|
|
8
|
+
function ciFromPayload(payload) {
|
|
9
|
+
const partial = asRecord(payload.partial_data);
|
|
10
|
+
if (partial === null) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
return asRecord(partial.ci);
|
|
14
|
+
}
|
|
15
|
+
function stringList(value) {
|
|
16
|
+
if (!Array.isArray(value)) {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
return value.filter((item) => typeof item === "string");
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Consume #3234 `ci_absent_required` from a readiness payload.
|
|
23
|
+
* Returns missing context names, or null when the poll is not absent-required.
|
|
24
|
+
* Pending required check-runs are a wait, not an absence.
|
|
25
|
+
*/
|
|
26
|
+
export function readAbsentRequiredContexts(payload) {
|
|
27
|
+
const ci = ciFromPayload(payload);
|
|
28
|
+
if (ci !== null) {
|
|
29
|
+
const pending = stringList(ci.pending_required);
|
|
30
|
+
if (pending.length > 0) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const readyState = ci.ready_state;
|
|
34
|
+
if (readyState === "not_ready_yet") {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
if (readyState === "ci_absent_required") {
|
|
38
|
+
return stringList(ci.absent_required);
|
|
39
|
+
}
|
|
40
|
+
// Structured CI present but not absent-required (e.g. ci_failures).
|
|
41
|
+
// Do not let failure-text mention of ci_absent_required override it.
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
const failures = Array.isArray(payload.failures) ? payload.failures.map(String) : [];
|
|
45
|
+
if (failures.some((failure) => failure.includes("ci_absent_required"))) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
/** True once consecutive absent polls have passed the first-poll grace window. */
|
|
51
|
+
export function shouldEscalateAbsentRequired(consecutivePolls, gracePolls = ABSENT_REQUIRED_GRACE_POLLS) {
|
|
52
|
+
return consecutivePolls > gracePolls;
|
|
53
|
+
}
|
|
54
|
+
/** Distinct exit naming that lists the missing required contexts. */
|
|
55
|
+
export function formatAbsentRequiredMessage(contexts) {
|
|
56
|
+
if (contexts.length === 0) {
|
|
57
|
+
return "ABSENT-REQUIRED: required status-check context never appeared";
|
|
58
|
+
}
|
|
59
|
+
return `ABSENT-REQUIRED: ${contexts.join(", ")}`;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=absent-required.js.map
|
|
@@ -3,6 +3,13 @@ export declare const EXIT_CLEAN = 0;
|
|
|
3
3
|
export declare const EXIT_CAP_REACHED = 1;
|
|
4
4
|
export declare const EXIT_CONFIG_ERROR = 2;
|
|
5
5
|
export declare const EXIT_PR_TERMINAL = 3;
|
|
6
|
+
/** Sustained required-context absence (#3389). Distinct from CAP-REACHED. */
|
|
7
|
+
export declare const EXIT_ABSENT_REQUIRED = 4;
|
|
8
|
+
/**
|
|
9
|
+
* First-poll absence is normal (check-runs take time after a head push).
|
|
10
|
+
* Escalate on the next consecutive `ci_absent_required` poll (#3389).
|
|
11
|
+
*/
|
|
12
|
+
export declare const ABSENT_REQUIRED_GRACE_POLLS = 1;
|
|
6
13
|
/** Adaptive cadence (seconds, repeats). Last repeat is a soft ceiling. */
|
|
7
14
|
export declare const DEFAULT_CADENCE: ReadonlyArray<readonly [number, number]>;
|
|
8
15
|
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -3,6 +3,13 @@ export const EXIT_CLEAN = 0;
|
|
|
3
3
|
export const EXIT_CAP_REACHED = 1;
|
|
4
4
|
export const EXIT_CONFIG_ERROR = 2;
|
|
5
5
|
export const EXIT_PR_TERMINAL = 3;
|
|
6
|
+
/** Sustained required-context absence (#3389). Distinct from CAP-REACHED. */
|
|
7
|
+
export const EXIT_ABSENT_REQUIRED = 4;
|
|
8
|
+
/**
|
|
9
|
+
* First-poll absence is normal (check-runs take time after a head push).
|
|
10
|
+
* Escalate on the next consecutive `ci_absent_required` poll (#3389).
|
|
11
|
+
*/
|
|
12
|
+
export const ABSENT_REQUIRED_GRACE_POLLS = 1;
|
|
6
13
|
/** Adaptive cadence (seconds, repeats). Last repeat is a soft ceiling. */
|
|
7
14
|
export const DEFAULT_CADENCE = [
|
|
8
15
|
[60, 3],
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
export { formatAbsentRequiredMessage, readAbsentRequiredContexts, shouldEscalateAbsentRequired, } from "./absent-required.js";
|
|
1
2
|
export { cadenceIntervalAfterPoll, cadenceIntervals } from "./cadence.js";
|
|
2
|
-
export { DEFAULT_CADENCE, EXIT_CAP_REACHED, EXIT_CLEAN, EXIT_CONFIG_ERROR, EXIT_PR_TERMINAL, } from "./constants.js";
|
|
3
|
+
export { ABSENT_REQUIRED_GRACE_POLLS, DEFAULT_CADENCE, EXIT_ABSENT_REQUIRED, EXIT_CAP_REACHED, EXIT_CLEAN, EXIT_CONFIG_ERROR, EXIT_PR_TERMINAL, } from "./constants.js";
|
|
3
4
|
export { cmdPrMonitor, parseMonitorArgs, runMonitor } from "./main.js";
|
|
4
5
|
export { formatPollStatus, isTerminalPrState, mergeStateFromPayload, monitor, summaryLabelForExit, } from "./monitor.js";
|
|
5
6
|
export { callReadiness } from "./readiness.js";
|
package/dist/pr-monitor/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
export { formatAbsentRequiredMessage, readAbsentRequiredContexts, shouldEscalateAbsentRequired, } from "./absent-required.js";
|
|
1
2
|
export { cadenceIntervalAfterPoll, cadenceIntervals } from "./cadence.js";
|
|
2
|
-
export { DEFAULT_CADENCE, EXIT_CAP_REACHED, EXIT_CLEAN, EXIT_CONFIG_ERROR, EXIT_PR_TERMINAL, } from "./constants.js";
|
|
3
|
+
export { ABSENT_REQUIRED_GRACE_POLLS, DEFAULT_CADENCE, EXIT_ABSENT_REQUIRED, EXIT_CAP_REACHED, EXIT_CLEAN, EXIT_CONFIG_ERROR, EXIT_PR_TERMINAL, } from "./constants.js";
|
|
3
4
|
export { cmdPrMonitor, parseMonitorArgs, runMonitor } from "./main.js";
|
|
4
5
|
export { formatPollStatus, isTerminalPrState, mergeStateFromPayload, monitor, summaryLabelForExit, } from "./monitor.js";
|
|
5
6
|
export { callReadiness } from "./readiness.js";
|
package/dist/pr-monitor/main.js
CHANGED
|
@@ -183,6 +183,10 @@ export function runMonitor(argv, options = {}) {
|
|
|
183
183
|
if (typeof err === "string" && err.length > 0) {
|
|
184
184
|
lines.push(` error: ${err}`);
|
|
185
185
|
}
|
|
186
|
+
const missingRaw = payload.monitor_absent_required;
|
|
187
|
+
if (Array.isArray(missingRaw) && missingRaw.length > 0) {
|
|
188
|
+
lines.push(` missing: ${missingRaw.map(String).join(", ")}`);
|
|
189
|
+
}
|
|
186
190
|
const failuresRaw = payload.failures;
|
|
187
191
|
if (Array.isArray(failuresRaw)) {
|
|
188
192
|
failuresRaw.forEach((fail, index) => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { formatAbsentRequiredMessage, readAbsentRequiredContexts, shouldEscalateAbsentRequired, } from "./absent-required.js";
|
|
1
2
|
import { cadenceIntervalAfterPoll, cadenceIntervals } from "./cadence.js";
|
|
2
|
-
import { DEFAULT_CADENCE, EXIT_CAP_REACHED, EXIT_CLEAN, EXIT_CONFIG_ERROR, EXIT_PR_TERMINAL, } from "./constants.js";
|
|
3
|
+
import { DEFAULT_CADENCE, EXIT_ABSENT_REQUIRED, EXIT_CAP_REACHED, EXIT_CLEAN, EXIT_CONFIG_ERROR, EXIT_PR_TERMINAL, } from "./constants.js";
|
|
3
4
|
import { callReadiness } from "./readiness.js";
|
|
4
5
|
const systemMonotonicClock = {
|
|
5
6
|
now() {
|
|
@@ -141,6 +142,7 @@ export function monitor(prNumber, repo, options = {}) {
|
|
|
141
142
|
let lastPayload = {};
|
|
142
143
|
let lastExit = EXIT_CAP_REACHED;
|
|
143
144
|
let priorCadenceSeconds = cadenceIntervalAfterPoll(1, cadence);
|
|
145
|
+
let consecutiveAbsentRequired = 0;
|
|
144
146
|
while (true) {
|
|
145
147
|
pollIndex += 1;
|
|
146
148
|
if (pollIndex > maxPolls) {
|
|
@@ -166,6 +168,25 @@ export function monitor(prNumber, repo, options = {}) {
|
|
|
166
168
|
if (isTerminalPrState(lastPayload)) {
|
|
167
169
|
return { exitCode: EXIT_PR_TERMINAL, payload: lastPayload, pollCount: pollIndex };
|
|
168
170
|
}
|
|
171
|
+
const absentContexts = readAbsentRequiredContexts(lastPayload);
|
|
172
|
+
if (absentContexts !== null) {
|
|
173
|
+
consecutiveAbsentRequired += 1;
|
|
174
|
+
if (shouldEscalateAbsentRequired(consecutiveAbsentRequired)) {
|
|
175
|
+
const message = formatAbsentRequiredMessage(absentContexts);
|
|
176
|
+
process.stderr.write(`[monitor_pr] ${message}\n`);
|
|
177
|
+
return {
|
|
178
|
+
exitCode: EXIT_ABSENT_REQUIRED,
|
|
179
|
+
payload: {
|
|
180
|
+
...lastPayload,
|
|
181
|
+
monitor_absent_required: [...absentContexts],
|
|
182
|
+
},
|
|
183
|
+
pollCount: pollIndex,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
consecutiveAbsentRequired = 0;
|
|
189
|
+
}
|
|
169
190
|
const elapsedAfterPoll = clockFn.now() - startedAt;
|
|
170
191
|
const remaining = capSeconds - elapsedAfterPoll;
|
|
171
192
|
if (remaining <= 0) {
|
|
@@ -187,6 +208,8 @@ export const summaryLabelForExit = (exitCode) => {
|
|
|
187
208
|
return "PR-TERMINAL";
|
|
188
209
|
case EXIT_CONFIG_ERROR:
|
|
189
210
|
return "CONFIG-ERROR";
|
|
211
|
+
case EXIT_ABSENT_REQUIRED:
|
|
212
|
+
return "ABSENT-REQUIRED";
|
|
190
213
|
default:
|
|
191
214
|
return "UNKNOWN";
|
|
192
215
|
}
|
|
@@ -9,11 +9,17 @@ export function classifyMonitorOutcome(monitorReturncode, monitorPayload) {
|
|
|
9
9
|
if (monitorPayload.monitor_result === "CAP-REACHED") {
|
|
10
10
|
return ["cap-reached", EXIT_TIMEOUT_OR_ESCALATION];
|
|
11
11
|
}
|
|
12
|
+
if (monitorPayload.monitor_result === "ABSENT-REQUIRED") {
|
|
13
|
+
return ["absent-required", EXIT_TIMEOUT_OR_ESCALATION];
|
|
14
|
+
}
|
|
12
15
|
return ["config-error", EXIT_CONFIG_ERROR];
|
|
13
16
|
}
|
|
14
17
|
if (monitorReturncode === 2) {
|
|
15
18
|
return ["config-error", EXIT_CONFIG_ERROR];
|
|
16
19
|
}
|
|
20
|
+
if (monitorReturncode === 4) {
|
|
21
|
+
return ["absent-required", EXIT_TIMEOUT_OR_ESCALATION];
|
|
22
|
+
}
|
|
17
23
|
if (monitorReturncode === 3) {
|
|
18
24
|
const readiness = typeof monitorPayload.readiness === "object" &&
|
|
19
25
|
monitorPayload.readiness !== null &&
|
|
@@ -23,6 +23,10 @@ export interface EvaluateOptions {
|
|
|
23
23
|
readonly skipParentLineage?: boolean;
|
|
24
24
|
/** Skip origin timestamp freshness (#3363). Default false. */
|
|
25
25
|
readonly skipOriginFreshness?: boolean;
|
|
26
|
+
/** Skip project-invariant coverage (#3425). Default false. */
|
|
27
|
+
readonly skipProjectInvariants?: boolean;
|
|
28
|
+
/** Skip intended-placement size check (#3424). Default false. */
|
|
29
|
+
readonly skipIntendedPlacement?: boolean;
|
|
26
30
|
/** Injected origin fetch for tests. Default: live `gh api` REST. */
|
|
27
31
|
readonly fetchOriginUpdatedAt?: FetchOriginUpdatedAt;
|
|
28
32
|
}
|
|
@@ -3,6 +3,8 @@ import { basename, dirname } from "node:path";
|
|
|
3
3
|
import { evaluateIntentCeilingFromEnv } from "../policy/intent-ceiling.js";
|
|
4
4
|
import { evaluateParentLineage, formatParentLineageLine, } from "../scope/parent-lineage.js";
|
|
5
5
|
import { evaluateOriginFreshness, } from "../vbrief-reconcile/origin-freshness.js";
|
|
6
|
+
import { evaluateIntendedPlacement, resolveProjectRootFromBrief } from "./intended-placement.js";
|
|
7
|
+
import { evaluateProjectInvariantsGate, resolveProjectRootForInvariants, } from "./project-invariants-gate.js";
|
|
6
8
|
/** Canonical eligibility folder — only vbrief/active/ may spawn implementation. */
|
|
7
9
|
export const ACTIVE_FOLDER = "active";
|
|
8
10
|
/** Canonical eligibility status — only `running` signals an active handoff. */
|
|
@@ -168,8 +170,37 @@ export function evaluate(vbriefPath, options = {}) {
|
|
|
168
170
|
message: buildReject(path, originFreshness.message),
|
|
169
171
|
};
|
|
170
172
|
}
|
|
173
|
+
// #3425: fail closed when an applicable project invariant has no disposition.
|
|
174
|
+
const invariants = evaluateProjectInvariantsGate(record, {
|
|
175
|
+
projectRoot: resolveProjectRootForInvariants(path, options.projectRoot),
|
|
176
|
+
skip: options.skipProjectInvariants === true,
|
|
177
|
+
});
|
|
178
|
+
if (!invariants.ok) {
|
|
179
|
+
return {
|
|
180
|
+
exitCode: 1,
|
|
181
|
+
parentLineage: lineage,
|
|
182
|
+
message: buildReject(path, invariants.message),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
// #3424: declared files vs review-trigger SoT. Missing field is grandfathered
|
|
186
|
+
// (warning). Inspect anomalies fail closed. Size alone is not a hard cap (#1488).
|
|
187
|
+
let placementWarning;
|
|
188
|
+
if (options.skipIntendedPlacement !== true) {
|
|
189
|
+
const projectRoot = resolveProjectRootFromBrief(path, options.projectRoot);
|
|
190
|
+
const placement = evaluateIntendedPlacement(planRecord, { projectRoot });
|
|
191
|
+
if (!placement.ok) {
|
|
192
|
+
return {
|
|
193
|
+
exitCode: 1,
|
|
194
|
+
parentLineage: lineage,
|
|
195
|
+
message: buildReject(path, placement.message),
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (placement.warning === true) {
|
|
199
|
+
placementWarning = placement.message;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
171
202
|
// Keep the historical OK line when lineage is N/A (backward-compatible tests / agents).
|
|
172
|
-
|
|
203
|
+
let message = lineage.applicable
|
|
173
204
|
? `OK ${path} -- ready for implementation. parent lineage OK ` +
|
|
174
205
|
`(${lineage.parent_requirement_ids.length} req IDs` +
|
|
175
206
|
(lineage.negative_invariant_ids.length > 0
|
|
@@ -177,6 +208,9 @@ export function evaluate(vbriefPath, options = {}) {
|
|
|
177
208
|
: "") +
|
|
178
209
|
`).`
|
|
179
210
|
: `OK ${path} -- ready for implementation.`;
|
|
211
|
+
if (placementWarning !== undefined) {
|
|
212
|
+
message = `${message} ${placementWarning}`;
|
|
213
|
+
}
|
|
180
214
|
return {
|
|
181
215
|
exitCode: 0,
|
|
182
216
|
parentLineage: lineage,
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
export type { EvaluateOptions, EvaluateResult } from "./evaluate.js";
|
|
2
2
|
export { ACTIVATE_HINT, ACTIVE_FOLDER, ELIGIBLE_LIFECYCLE_DIRS, ELIGIBLE_STATUS, emitJson, evaluate, formatActivateHint, PREFLIGHT_USAGE_HINT, } from "./evaluate.js";
|
|
3
|
+
export type { IntendedPlacement, IntendedPlacementResult, ParsedIntendedPlacement, } from "./intended-placement.js";
|
|
4
|
+
export { emptyIntendedPlacement, evaluateIntendedPlacement, INTENDED_PLACEMENT_GRANDFATHER_HINT, INTENDED_PLACEMENT_MISSING_HINT, INTENDED_PLACEMENT_OVER_TRIGGER_HINT, INTENDED_PLACEMENT_SCHEMA, parseIntendedPlacement, readIntendedPlacement, stampIntendedPlacement, } from "./intended-placement.js";
|
|
5
|
+
export type { ProjectInvariantsGateOptions, ProjectInvariantsGateResult, } from "./project-invariants-gate.js";
|
|
6
|
+
export { evaluateProjectInvariantsGate, PROJECT_INVARIANT_REMEDIATION, resolveProjectRootForInvariants, } from "./project-invariants-gate.js";
|
|
3
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/preflight/index.js
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
export { ACTIVATE_HINT, ACTIVE_FOLDER, ELIGIBLE_LIFECYCLE_DIRS, ELIGIBLE_STATUS, emitJson, evaluate, formatActivateHint, PREFLIGHT_USAGE_HINT, } from "./evaluate.js";
|
|
2
|
+
export { emptyIntendedPlacement, evaluateIntendedPlacement, INTENDED_PLACEMENT_GRANDFATHER_HINT, INTENDED_PLACEMENT_MISSING_HINT, INTENDED_PLACEMENT_OVER_TRIGGER_HINT, INTENDED_PLACEMENT_SCHEMA, parseIntendedPlacement, readIntendedPlacement, stampIntendedPlacement, } from "./intended-placement.js";
|
|
3
|
+
export { evaluateProjectInvariantsGate, PROJECT_INVARIANT_REMEDIATION, resolveProjectRootForInvariants, } from "./project-invariants-gate.js";
|
|
2
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* xBRIEF intended-placement field + preflight check (#3424).
|
|
3
|
+
*
|
|
4
|
+
* Preflight keys on declared files vs FILE_SIZE_REVIEW_TRIGGER_LINES.
|
|
5
|
+
* Size alone is not a hard cap (#1488).
|
|
6
|
+
*
|
|
7
|
+
* ## Error policy
|
|
8
|
+
* Every anomaly on a declared file fails closed (exit 1 + remediation hint).
|
|
9
|
+
* Never throw. Never silent-skip. The only skip is first-touch `lstat` ENOENT
|
|
10
|
+
* (planned-new file — nothing to measure). If `lstat` succeeded and a later
|
|
11
|
+
* operation fails, that is an inconsistency → exit 1.
|
|
12
|
+
*
|
|
13
|
+
* ## Threat model
|
|
14
|
+
* Preflight is a quality gate the agent runs against its own declared plan
|
|
15
|
+
* in its own worktree. A concurrent local process that can swap symlinks
|
|
16
|
+
* mid-check can trivially edit the vBRIEF itself. Adversarial-local-attacker
|
|
17
|
+
* TOCTOU is a **non-goal** beyond the fd discipline below. Windows symlink
|
|
18
|
+
* creation requires elevation.
|
|
19
|
+
*
|
|
20
|
+
* ## fd discipline
|
|
21
|
+
* `lstat` rejects symlink entries outright. Resolve + containment-check once.
|
|
22
|
+
* `openSync(abs, O_RDONLY | O_NOFOLLOW)` (plain `O_RDONLY` where `O_NOFOLLOW`
|
|
23
|
+
* is undefined, i.e. Windows). `fstatSync(fd)` confirms a regular file; read
|
|
24
|
+
* from that same fd.
|
|
25
|
+
*/
|
|
26
|
+
export declare const INTENDED_PLACEMENT_SCHEMA: "deft.scope.intended_placement.v1";
|
|
27
|
+
export declare const INTENDED_PLACEMENT_MISSING_HINT = "Record plan.metadata.intended_placement with files[] and module_boundary before implementation.";
|
|
28
|
+
export declare const INTENDED_PLACEMENT_OVER_TRIGGER_HINT = "Record plan.metadata.intended_placement.split_plan or cohesion_exemption. Size alone is not a fail-closed cap (#1488 / #3424).";
|
|
29
|
+
export declare const INTENDED_PLACEMENT_GRANDFATHER_HINT = "Pre-#3424 brief: intended_placement is missing (warning). Ingest now stamps the field; record files[] before new work.";
|
|
30
|
+
export interface IntendedPlacement {
|
|
31
|
+
readonly schema?: string;
|
|
32
|
+
readonly files: readonly string[];
|
|
33
|
+
readonly module_boundary?: string;
|
|
34
|
+
readonly split_plan?: string;
|
|
35
|
+
readonly cohesion_exemption?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface IntendedPlacementResult {
|
|
38
|
+
readonly ok: boolean;
|
|
39
|
+
readonly message: string;
|
|
40
|
+
/** Grandfathered missing field — evaluate stays exit 0 and surfaces this. */
|
|
41
|
+
readonly warning?: boolean;
|
|
42
|
+
}
|
|
43
|
+
export type ParsedIntendedPlacement = {
|
|
44
|
+
kind: "missing";
|
|
45
|
+
} | {
|
|
46
|
+
kind: "malformed";
|
|
47
|
+
message: string;
|
|
48
|
+
} | {
|
|
49
|
+
kind: "ok";
|
|
50
|
+
placement: IntendedPlacement;
|
|
51
|
+
};
|
|
52
|
+
export declare function emptyIntendedPlacement(): IntendedPlacement;
|
|
53
|
+
/** Stamp a skeleton intended_placement onto plan.metadata when absent (#3424). */
|
|
54
|
+
export declare function stampIntendedPlacement(plan: Record<string, unknown>): void;
|
|
55
|
+
export declare function parseIntendedPlacement(plan: Record<string, unknown>): ParsedIntendedPlacement;
|
|
56
|
+
export declare function readIntendedPlacement(plan: Record<string, unknown>): IntendedPlacement | null;
|
|
57
|
+
export declare function countFileLines(text: string): number;
|
|
58
|
+
export declare function resolveProjectRootFromBrief(briefPath: string, explicitRoot?: string): string;
|
|
59
|
+
export declare function evaluateIntendedPlacement(plan: Record<string, unknown>, options: {
|
|
60
|
+
projectRoot: string;
|
|
61
|
+
}): IntendedPlacementResult;
|
|
62
|
+
//# sourceMappingURL=intended-placement.d.ts.map
|