@deftai/directive-core 0.73.1 → 0.75.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/agents-md-budget/evaluate.d.ts +61 -0
- package/dist/agents-md-budget/evaluate.js +321 -19
- package/dist/agents-md-budget/index.d.ts +1 -0
- package/dist/agents-md-budget/index.js +1 -0
- package/dist/agents-md-budget/skill-frontmatter.d.ts +33 -0
- package/dist/agents-md-budget/skill-frontmatter.js +115 -0
- package/dist/check/orchestrator.d.ts +3 -0
- package/dist/check/orchestrator.js +2 -1
- package/dist/codebase/map.js +2 -0
- package/dist/content-contracts/skills/helpers.d.ts +0 -1
- package/dist/content-contracts/skills/helpers.js +1 -11
- package/dist/content-contracts/skills/skill-frontmatter.js +8 -1
- package/dist/content-contracts/standards/_helpers.js +4 -2
- package/dist/content-contracts/standards/_taskfile-helpers.d.ts +2 -0
- package/dist/content-contracts/standards/_taskfile-helpers.js +11 -5
- package/dist/doctor/checks.d.ts +9 -0
- package/dist/doctor/checks.js +67 -0
- package/dist/doctor/doctor-state.js +2 -1
- package/dist/doctor/main.js +2 -1
- package/dist/doctor/paths.js +2 -1
- package/dist/eval-health-relocation/evaluate.d.ts +71 -0
- package/dist/eval-health-relocation/evaluate.js +252 -0
- package/dist/eval-health-relocation/index.d.ts +2 -0
- package/dist/eval-health-relocation/index.js +2 -0
- package/dist/fs/projection-containment.d.ts +35 -0
- package/dist/fs/projection-containment.js +118 -0
- package/dist/init-deposit/scaffold.d.ts +21 -0
- package/dist/init-deposit/scaffold.js +86 -9
- package/dist/intake/issue-emit.js +2 -2
- package/dist/policy/agents-md-budget.d.ts +23 -0
- package/dist/policy/agents-md-budget.js +75 -4
- package/dist/pr-merge-readiness/constants.d.ts +4 -0
- package/dist/pr-merge-readiness/constants.js +4 -0
- package/dist/pr-merge-readiness/evaluate.js +3 -0
- package/dist/pr-merge-readiness/mergeability.d.ts +8 -6
- package/dist/pr-merge-readiness/mergeability.js +15 -10
- package/dist/pr-merge-readiness/output.js +12 -6
- package/dist/pr-merge-readiness/parse.d.ts +1 -0
- package/dist/pr-merge-readiness/parse.js +9 -1
- package/dist/pr-merge-readiness/types.d.ts +2 -0
- package/dist/preflight-cache/evaluate.d.ts +2 -0
- package/dist/preflight-cache/evaluate.js +14 -3
- package/dist/preflight-cache/index.d.ts +1 -1
- package/dist/preflight-cache/index.js +1 -1
- package/dist/release/constants.d.ts +2 -0
- package/dist/release/constants.js +2 -0
- package/dist/release/preflight.d.ts +2 -0
- package/dist/release/preflight.js +14 -1
- package/dist/release/spawn.js +5 -3
- package/dist/scope/decompose.js +4 -3
- package/dist/scope/index.d.ts +1 -0
- package/dist/scope/index.js +1 -0
- package/dist/scope/main.js +24 -1
- package/dist/scope/open-umbrella-warning.d.ts +12 -0
- package/dist/scope/open-umbrella-warning.js +403 -0
- package/dist/scope/vbrief-ref.js +3 -3
- package/dist/swarm/complete-cohort.js +6 -6
- package/dist/swarm/launch.js +2 -2
- package/dist/triage/bootstrap/gitignore.d.ts +1 -1
- package/dist/triage/bootstrap/gitignore.js +69 -58
- package/dist/triage/queue/cache.d.ts +14 -0
- package/dist/triage/queue/cache.js +61 -1
- package/dist/validate-content/validate-links.js +2 -2
- package/dist/value/readback.d.ts +1 -0
- package/dist/value/readback.js +5 -1
- package/dist/vbrief-reconcile/umbrellas.js +12 -11
- package/dist/verify-env/toolchain-check.js +20 -5
- package/dist/verify-env/verify-hooks-installed.d.ts +2 -0
- package/dist/verify-env/verify-hooks-installed.js +17 -15
- package/dist/xbrief-migrate/migrate-project.js +9 -0
- package/package.json +7 -3
|
@@ -1,9 +1,51 @@
|
|
|
1
|
+
import { type AgentsMdBudget } from "../policy/agents-md-budget.js";
|
|
2
|
+
import { type SkillFrontmatterMeasure } from "./skill-frontmatter.js";
|
|
1
3
|
export type OutputStream = "stdout" | "stderr" | "none";
|
|
4
|
+
/**
|
|
5
|
+
* Layered absolute north-star for the always-on managed surface (#2372 / #2450 / #2452).
|
|
6
|
+
*
|
|
7
|
+
* `ABSOLUTE_MANAGED_MAX_BYTES` is the relocation north-star (<=8192 B / ~2k tok).
|
|
8
|
+
* When `plan.policy.agentsMdBudget.absoluteMaxBytes` is set, growth past that seeded
|
|
9
|
+
* ratchet fails closed; distance-to-north-star is always reported. Optional release-gate
|
|
10
|
+
* north-star enforcement: DEFT_AGENTS_MD_BUDGET_ENFORCE_NORTH_STAR=1 (waiver:
|
|
11
|
+
* DEFT_ALLOW_ABSOLUTE_BUDGET_WAIVER=1).
|
|
12
|
+
*
|
|
13
|
+
* DD-3 (harness-injected skill frontmatter) is measured and itemized (#2463).
|
|
14
|
+
* Managed `absoluteMaxBytes` remains the fail-closed ratchet for the rendered
|
|
15
|
+
* managed section; skill-frontmatter caps are advisory unless
|
|
16
|
+
* `skillFrontmatterMaxBytes` is set (or enforced via env).
|
|
17
|
+
*/
|
|
18
|
+
export declare const ABSOLUTE_MANAGED_MAX_BYTES = 8192;
|
|
19
|
+
export declare const ABSOLUTE_MANAGED_MAX_TOKENS = 2000;
|
|
20
|
+
/** Bootstrap host hooks are 0 B until #2438 ships. */
|
|
21
|
+
export declare const BOOTSTRAP_HOOK_BYTES = 0;
|
|
22
|
+
/** Rough UTF-8 bytes-per-token estimate for advisory reporting (~8192 B ≈ ~2048 tok). */
|
|
23
|
+
export declare const ABSOLUTE_BYTES_PER_TOKEN_ESTIMATE = 4;
|
|
24
|
+
/** Byte + estimated-token measure of the managed section body. */
|
|
25
|
+
export interface ManagedSectionMeasure {
|
|
26
|
+
readonly bytes: number;
|
|
27
|
+
readonly estimatedTokens: number;
|
|
28
|
+
}
|
|
29
|
+
/** Itemized always-on bootstrap surface (managed + DD-3 + hooks). */
|
|
30
|
+
export interface BootstrapMeasure {
|
|
31
|
+
readonly managed: ManagedSectionMeasure;
|
|
32
|
+
readonly skillFrontmatter: SkillFrontmatterMeasure;
|
|
33
|
+
readonly bootstrapHookBytes: number;
|
|
34
|
+
readonly totalBytes: number;
|
|
35
|
+
readonly totalEstimatedTokens: number;
|
|
36
|
+
}
|
|
2
37
|
/** Result of verify:agents-md-budget evaluation; three-state exit contract. */
|
|
3
38
|
export interface EvaluateResult {
|
|
4
39
|
readonly code: 0 | 1 | 2;
|
|
5
40
|
readonly message: string;
|
|
6
41
|
readonly stream: OutputStream;
|
|
42
|
+
/** North-star distance note (#2452); may accompany success or failure paths. */
|
|
43
|
+
readonly northStarMessage?: string;
|
|
44
|
+
readonly northStarStream?: OutputStream;
|
|
45
|
+
/** @deprecated Use northStarMessage — retained for one release of CLI compat. */
|
|
46
|
+
readonly advisoryMessage?: string;
|
|
47
|
+
/** @deprecated Use northStarStream — retained for one release of CLI compat. */
|
|
48
|
+
readonly advisoryStream?: OutputStream;
|
|
7
49
|
}
|
|
8
50
|
export interface EvaluateOptions {
|
|
9
51
|
readonly quiet?: boolean;
|
|
@@ -26,6 +68,25 @@ export declare function countRegions(text: string): {
|
|
|
26
68
|
} | {
|
|
27
69
|
error: string;
|
|
28
70
|
};
|
|
71
|
+
/**
|
|
72
|
+
* Extract the managed-section span (open marker through close marker, inclusive).
|
|
73
|
+
*
|
|
74
|
+
* Returns an empty section when no markers are present — consistent with
|
|
75
|
+
* `countRegions` treating markerless files as entirely unmanaged.
|
|
76
|
+
*/
|
|
77
|
+
export declare function extractManagedSection(text: string): {
|
|
78
|
+
section: string;
|
|
79
|
+
} | {
|
|
80
|
+
error: string;
|
|
81
|
+
};
|
|
82
|
+
/** Measure UTF-8 byte length and a rough token estimate for the managed section. */
|
|
83
|
+
export declare function measureManagedSection(text: string): ManagedSectionMeasure | {
|
|
84
|
+
error: string;
|
|
85
|
+
};
|
|
86
|
+
/** Measure managed + DD-3 skill frontmatter + bootstrap hooks. */
|
|
87
|
+
export declare function measureBootstrapSurface(projectRoot: string, managedText: string, budget: AgentsMdBudget | null): BootstrapMeasure | {
|
|
88
|
+
error: string;
|
|
89
|
+
};
|
|
29
90
|
/**
|
|
30
91
|
* Pure evaluator for the AGENTS.md line-budget ratchet gate (#645).
|
|
31
92
|
*
|
|
@@ -1,7 +1,28 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
import { AGENTS_MANAGED_CLOSE } from "../platform/constants.js";
|
|
4
|
-
import { resolveAgentsMdBudget } from "../policy/agents-md-budget.js";
|
|
4
|
+
import { resolveAgentsMdBudget, } from "../policy/agents-md-budget.js";
|
|
5
|
+
import { measureSkillFrontmatter } from "./skill-frontmatter.js";
|
|
6
|
+
/**
|
|
7
|
+
* Layered absolute north-star for the always-on managed surface (#2372 / #2450 / #2452).
|
|
8
|
+
*
|
|
9
|
+
* `ABSOLUTE_MANAGED_MAX_BYTES` is the relocation north-star (<=8192 B / ~2k tok).
|
|
10
|
+
* When `plan.policy.agentsMdBudget.absoluteMaxBytes` is set, growth past that seeded
|
|
11
|
+
* ratchet fails closed; distance-to-north-star is always reported. Optional release-gate
|
|
12
|
+
* north-star enforcement: DEFT_AGENTS_MD_BUDGET_ENFORCE_NORTH_STAR=1 (waiver:
|
|
13
|
+
* DEFT_ALLOW_ABSOLUTE_BUDGET_WAIVER=1).
|
|
14
|
+
*
|
|
15
|
+
* DD-3 (harness-injected skill frontmatter) is measured and itemized (#2463).
|
|
16
|
+
* Managed `absoluteMaxBytes` remains the fail-closed ratchet for the rendered
|
|
17
|
+
* managed section; skill-frontmatter caps are advisory unless
|
|
18
|
+
* `skillFrontmatterMaxBytes` is set (or enforced via env).
|
|
19
|
+
*/
|
|
20
|
+
export const ABSOLUTE_MANAGED_MAX_BYTES = 8192;
|
|
21
|
+
export const ABSOLUTE_MANAGED_MAX_TOKENS = 2000;
|
|
22
|
+
/** Bootstrap host hooks are 0 B until #2438 ships. */
|
|
23
|
+
export const BOOTSTRAP_HOOK_BYTES = 0;
|
|
24
|
+
/** Rough UTF-8 bytes-per-token estimate for advisory reporting (~8192 B ≈ ~2048 tok). */
|
|
25
|
+
export const ABSOLUTE_BYTES_PER_TOKEN_ESTIMATE = 4;
|
|
5
26
|
const OPEN_MARKER_PREFIX = "<!-- deft:managed-section";
|
|
6
27
|
/**
|
|
7
28
|
* Split AGENTS.md into managed / unmanaged line counts.
|
|
@@ -42,6 +63,238 @@ export function countRegions(text) {
|
|
|
42
63
|
const managed = closeLine - openLine + 1;
|
|
43
64
|
return { counts: { total, managed, unmanaged: total - managed } };
|
|
44
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Extract the managed-section span (open marker through close marker, inclusive).
|
|
68
|
+
*
|
|
69
|
+
* Returns an empty section when no markers are present — consistent with
|
|
70
|
+
* `countRegions` treating markerless files as entirely unmanaged.
|
|
71
|
+
*/
|
|
72
|
+
export function extractManagedSection(text) {
|
|
73
|
+
const normalized = text.replace(/\r\n/g, "\n");
|
|
74
|
+
const lines = normalized.split("\n");
|
|
75
|
+
if (lines.length > 0 && lines[lines.length - 1] === "") {
|
|
76
|
+
lines.pop();
|
|
77
|
+
}
|
|
78
|
+
const openLine = lines.findIndex((l) => l.startsWith(OPEN_MARKER_PREFIX));
|
|
79
|
+
const closeLine = lines.findIndex((l) => l.trim().startsWith(AGENTS_MANAGED_CLOSE));
|
|
80
|
+
const openCount = lines.filter((l) => l.startsWith(OPEN_MARKER_PREFIX)).length;
|
|
81
|
+
const closeCount = lines.filter((l) => l.trim().startsWith(AGENTS_MANAGED_CLOSE)).length;
|
|
82
|
+
if (openLine === -1 && closeLine === -1) {
|
|
83
|
+
return { section: "" };
|
|
84
|
+
}
|
|
85
|
+
if (openLine === -1 ||
|
|
86
|
+
closeLine === -1 ||
|
|
87
|
+
closeLine < openLine ||
|
|
88
|
+
openCount > 1 ||
|
|
89
|
+
closeCount > 1) {
|
|
90
|
+
return {
|
|
91
|
+
error: "AGENTS.md managed-section markers are malformed " +
|
|
92
|
+
`(open@${openLine === -1 ? "none" : openLine + 1}×${openCount}, ` +
|
|
93
|
+
`close@${closeLine === -1 ? "none" : closeLine + 1}×${closeCount}); ` +
|
|
94
|
+
"expected a single <!-- deft:managed-section ... --> ... " +
|
|
95
|
+
"<!-- /deft:managed-section --> pair.",
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return { section: lines.slice(openLine, closeLine + 1).join("\n") };
|
|
99
|
+
}
|
|
100
|
+
/** Measure UTF-8 byte length and a rough token estimate for the managed section. */
|
|
101
|
+
export function measureManagedSection(text) {
|
|
102
|
+
const extracted = extractManagedSection(text);
|
|
103
|
+
if ("error" in extracted) {
|
|
104
|
+
return extracted;
|
|
105
|
+
}
|
|
106
|
+
const bytes = Buffer.byteLength(extracted.section, "utf8");
|
|
107
|
+
return {
|
|
108
|
+
bytes,
|
|
109
|
+
estimatedTokens: Math.ceil(bytes / ABSOLUTE_BYTES_PER_TOKEN_ESTIMATE),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function resolveHarnessProfile(budget, projectRoot) {
|
|
113
|
+
const env = process.env.DEFT_AGENTS_MD_BUDGET_HARNESS_PROFILE?.trim();
|
|
114
|
+
if (env === "cursor" || env === "none") {
|
|
115
|
+
return env;
|
|
116
|
+
}
|
|
117
|
+
if (budget?.harnessProfile !== undefined) {
|
|
118
|
+
return budget.harnessProfile;
|
|
119
|
+
}
|
|
120
|
+
const skillsRoot = join(projectRoot, "content", "skills");
|
|
121
|
+
if (existsSync(skillsRoot)) {
|
|
122
|
+
return "cursor";
|
|
123
|
+
}
|
|
124
|
+
return "none";
|
|
125
|
+
}
|
|
126
|
+
function resolveSkillFrontmatterTier(budget) {
|
|
127
|
+
const env = process.env.DEFT_AGENTS_MD_BUDGET_SKILL_TIER?.trim();
|
|
128
|
+
if (env === "daily-core" || env === "all" || env === "none") {
|
|
129
|
+
return env;
|
|
130
|
+
}
|
|
131
|
+
return budget?.skillFrontmatterTier ?? "all";
|
|
132
|
+
}
|
|
133
|
+
/** Measure managed + DD-3 skill frontmatter + bootstrap hooks. */
|
|
134
|
+
export function measureBootstrapSurface(projectRoot, managedText, budget) {
|
|
135
|
+
const managedResult = measureManagedSection(managedText);
|
|
136
|
+
if ("error" in managedResult) {
|
|
137
|
+
return managedResult;
|
|
138
|
+
}
|
|
139
|
+
const harnessProfile = resolveHarnessProfile(budget, projectRoot);
|
|
140
|
+
const tier = resolveSkillFrontmatterTier(budget);
|
|
141
|
+
const skillFrontmatter = measureSkillFrontmatter(projectRoot, {
|
|
142
|
+
harnessProfile,
|
|
143
|
+
tier,
|
|
144
|
+
bytesPerToken: ABSOLUTE_BYTES_PER_TOKEN_ESTIMATE,
|
|
145
|
+
});
|
|
146
|
+
const totalBytes = managedResult.bytes + skillFrontmatter.bytes + BOOTSTRAP_HOOK_BYTES;
|
|
147
|
+
return {
|
|
148
|
+
managed: managedResult,
|
|
149
|
+
skillFrontmatter,
|
|
150
|
+
bootstrapHookBytes: BOOTSTRAP_HOOK_BYTES,
|
|
151
|
+
totalBytes,
|
|
152
|
+
totalEstimatedTokens: Math.ceil(totalBytes / ABSOLUTE_BYTES_PER_TOKEN_ESTIMATE),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function formatNorthStarOverageBytes(overBytes, overTokens) {
|
|
156
|
+
const parts = [];
|
|
157
|
+
if (overBytes > 0) {
|
|
158
|
+
parts.push(`${overBytes} bytes over`);
|
|
159
|
+
}
|
|
160
|
+
if (overTokens > 0) {
|
|
161
|
+
parts.push(`~${overTokens} tok over`);
|
|
162
|
+
}
|
|
163
|
+
return parts.join(", ");
|
|
164
|
+
}
|
|
165
|
+
function formatNorthStarOverage(measure) {
|
|
166
|
+
return formatNorthStarOverageBytes(measure.bytes - ABSOLUTE_MANAGED_MAX_BYTES, measure.estimatedTokens - ABSOLUTE_MANAGED_MAX_TOKENS);
|
|
167
|
+
}
|
|
168
|
+
function formatCombinedNorthStarOverage(bootstrap) {
|
|
169
|
+
return formatNorthStarOverageBytes(bootstrap.totalBytes - ABSOLUTE_MANAGED_MAX_BYTES, bootstrap.totalEstimatedTokens - ABSOLUTE_MANAGED_MAX_TOKENS);
|
|
170
|
+
}
|
|
171
|
+
function formatNorthStarDistance(measure) {
|
|
172
|
+
const overBytes = measure.bytes - ABSOLUTE_MANAGED_MAX_BYTES;
|
|
173
|
+
const overTokens = measure.estimatedTokens - ABSOLUTE_MANAGED_MAX_TOKENS;
|
|
174
|
+
if (overBytes <= 0 && overTokens <= 0) {
|
|
175
|
+
return (`north-star: managed ${measure.bytes} bytes (~${measure.estimatedTokens} tok) within ` +
|
|
176
|
+
`≤${ABSOLUTE_MANAGED_MAX_BYTES} B / ~${ABSOLUTE_MANAGED_MAX_TOKENS} tok target.`);
|
|
177
|
+
}
|
|
178
|
+
return (`north-star: managed ≤${ABSOLUTE_MANAGED_MAX_BYTES} B / ~${ABSOLUTE_MANAGED_MAX_TOKENS} tok ` +
|
|
179
|
+
`(current ${measure.bytes} bytes / ~${measure.estimatedTokens} tok — ` +
|
|
180
|
+
`${formatNorthStarOverage(measure)}).`);
|
|
181
|
+
}
|
|
182
|
+
function formatCombinedNorthStarDistance(bootstrap) {
|
|
183
|
+
const overBytes = bootstrap.totalBytes - ABSOLUTE_MANAGED_MAX_BYTES;
|
|
184
|
+
const overTokens = bootstrap.totalEstimatedTokens - ABSOLUTE_MANAGED_MAX_TOKENS;
|
|
185
|
+
if (overBytes <= 0 && overTokens <= 0) {
|
|
186
|
+
return (`north-star: combined always-on ${bootstrap.totalBytes} bytes ` +
|
|
187
|
+
`(~${bootstrap.totalEstimatedTokens} tok) within ` +
|
|
188
|
+
`≤${ABSOLUTE_MANAGED_MAX_BYTES} B / ~${ABSOLUTE_MANAGED_MAX_TOKENS} tok target.`);
|
|
189
|
+
}
|
|
190
|
+
return (`north-star: combined always-on ≤${ABSOLUTE_MANAGED_MAX_BYTES} B / ~${ABSOLUTE_MANAGED_MAX_TOKENS} tok ` +
|
|
191
|
+
`(current ${bootstrap.totalBytes} bytes / ~${bootstrap.totalEstimatedTokens} tok — ` +
|
|
192
|
+
`${formatCombinedNorthStarOverage(bootstrap)}).`);
|
|
193
|
+
}
|
|
194
|
+
function formatBootstrapItemization(bootstrap) {
|
|
195
|
+
const { managed, skillFrontmatter, bootstrapHookBytes } = bootstrap;
|
|
196
|
+
const tierLabel = skillFrontmatter.harnessProfile === "none"
|
|
197
|
+
? "none"
|
|
198
|
+
: `${skillFrontmatter.harnessProfile}/${skillFrontmatter.tier}`;
|
|
199
|
+
const skillPart = skillFrontmatter.bytes > 0
|
|
200
|
+
? `skill-frontmatter ${skillFrontmatter.bytes} B (${tierLabel}, ${skillFrontmatter.skillCount} skills)`
|
|
201
|
+
: `skill-frontmatter 0 B (${tierLabel})`;
|
|
202
|
+
return (`bootstrap: managed ${managed.bytes} B, ${skillPart}, hooks ${bootstrapHookBytes} B; ` +
|
|
203
|
+
`combined ${bootstrap.totalBytes} B (~${bootstrap.totalEstimatedTokens} tok)`);
|
|
204
|
+
}
|
|
205
|
+
function formatAbsoluteAdvisory(bootstrap) {
|
|
206
|
+
const measure = bootstrap.managed;
|
|
207
|
+
return (`⚠ verify:agents-md-budget: always-on bootstrap advisory — ` +
|
|
208
|
+
`${formatBootstrapItemization(bootstrap)}.\n` +
|
|
209
|
+
` Managed section alone: ${measure.bytes} bytes (~${measure.estimatedTokens} tok) exceeds the north-star ` +
|
|
210
|
+
`of ${ABSOLUTE_MANAGED_MAX_BYTES} bytes / ~${ABSOLUTE_MANAGED_MAX_TOKENS} tok ` +
|
|
211
|
+
`(OVER: ${formatNorthStarOverage(measure)}).\n` +
|
|
212
|
+
` ${formatCombinedNorthStarDistance(bootstrap)}\n` +
|
|
213
|
+
" Advisory only — set plan.policy.agentsMdBudget.absoluteMaxBytes to enable " +
|
|
214
|
+
"fail-closed managed growth ratchet (#2452).\n" +
|
|
215
|
+
" Optional DD-3 ratchet: plan.policy.agentsMdBudget.skillFrontmatterMaxBytes (#2463).\n" +
|
|
216
|
+
" Tier daily-core skills via OpenPackage or plan.policy.agentsMdBudget.skillFrontmatterTier.\n" +
|
|
217
|
+
" Remediation: UPGRADING.md § Always-on bootstrap budget (DD-3).\n" +
|
|
218
|
+
" The relative line ratchet (#645) remains fail-closed.");
|
|
219
|
+
}
|
|
220
|
+
function formatAbsoluteRefusal(bootstrap, absoluteMaxBytes, projectRoot) {
|
|
221
|
+
const measure = bootstrap.managed;
|
|
222
|
+
const overBytes = measure.bytes - absoluteMaxBytes;
|
|
223
|
+
return (`❌ verify:agents-md-budget: managed section grew past its absolute byte ratchet ` +
|
|
224
|
+
`(project_root=${projectRoot}).\n` +
|
|
225
|
+
` managed section: ${measure.bytes}/${absoluteMaxBytes} bytes (OVER by ${overBytes})\n` +
|
|
226
|
+
` ${formatBootstrapItemization(bootstrap)}\n` +
|
|
227
|
+
` ${formatNorthStarDistance(measure)}\n` +
|
|
228
|
+
` ${formatCombinedNorthStarDistance(bootstrap)}\n` +
|
|
229
|
+
" AGENTS.md is a map, not a manual (#1882): push detail into a\n" +
|
|
230
|
+
" reference doc (main.md / a pack / docs/) and leave a pointer,\n" +
|
|
231
|
+
" rather than expanding AGENTS.md. See REFERENCES.md.\n" +
|
|
232
|
+
" If the growth is deliberate, raise absoluteMaxBytes in\n" +
|
|
233
|
+
" plan.policy.agentsMdBudget in PROJECT-DEFINITION (a reviewed diff). (#2452)");
|
|
234
|
+
}
|
|
235
|
+
function formatSkillFrontmatterRefusal(bootstrap, skillFrontmatterMaxBytes, projectRoot) {
|
|
236
|
+
const { skillFrontmatter } = bootstrap;
|
|
237
|
+
const overBytes = skillFrontmatter.bytes - skillFrontmatterMaxBytes;
|
|
238
|
+
return (`❌ verify:agents-md-budget: skill frontmatter grew past its DD-3 byte ratchet ` +
|
|
239
|
+
`(project_root=${projectRoot}).\n` +
|
|
240
|
+
` skill-frontmatter: ${skillFrontmatter.bytes}/${skillFrontmatterMaxBytes} bytes ` +
|
|
241
|
+
`(OVER by ${overBytes}; tier ${skillFrontmatter.tier}, ${skillFrontmatter.skillCount} skills)\n` +
|
|
242
|
+
` ${formatBootstrapItemization(bootstrap)}\n` +
|
|
243
|
+
` ${formatCombinedNorthStarDistance(bootstrap)}\n` +
|
|
244
|
+
" Tier deferred skills via OpenPackage (daily-core vs advanced) or shorten\n" +
|
|
245
|
+
" SKILL.md descriptions. See UPGRADING.md § Always-on bootstrap budget (DD-3).\n" +
|
|
246
|
+
" If the growth is deliberate, raise skillFrontmatterMaxBytes in\n" +
|
|
247
|
+
" plan.policy.agentsMdBudget in PROJECT-DEFINITION (a reviewed diff). (#2463)");
|
|
248
|
+
}
|
|
249
|
+
function formatNorthStarRefusal(bootstrap, projectRoot) {
|
|
250
|
+
const measure = bootstrap.managed;
|
|
251
|
+
const overBytes = bootstrap.totalBytes - ABSOLUTE_MANAGED_MAX_BYTES;
|
|
252
|
+
return (`❌ verify:agents-md-budget: combined always-on surface exceeds the north-star ceiling ` +
|
|
253
|
+
`(project_root=${projectRoot}, release-gate mode).\n` +
|
|
254
|
+
` ${formatBootstrapItemization(bootstrap)}\n` +
|
|
255
|
+
` managed section: ${measure.bytes}/${ABSOLUTE_MANAGED_MAX_BYTES} bytes\n` +
|
|
256
|
+
` combined OVER by ${overBytes} bytes vs north-star\n` +
|
|
257
|
+
" Thin the managed section and/or tier DD-3 skills toward the <=8192 B target,\n" +
|
|
258
|
+
" or set DEFT_ALLOW_ABSOLUTE_BUDGET_WAIVER=1 for a time-boxed operator waiver (#2452).");
|
|
259
|
+
}
|
|
260
|
+
function enforceNorthStarEnabled() {
|
|
261
|
+
return process.env.DEFT_AGENTS_MD_BUDGET_ENFORCE_NORTH_STAR === "1";
|
|
262
|
+
}
|
|
263
|
+
function northStarWaiverActive() {
|
|
264
|
+
return process.env.DEFT_ALLOW_ABSOLUTE_BUDGET_WAIVER === "1";
|
|
265
|
+
}
|
|
266
|
+
function attachNorthStarNote(result, bootstrap, options) {
|
|
267
|
+
const measure = bootstrap.managed;
|
|
268
|
+
const overManagedBytes = measure.bytes > ABSOLUTE_MANAGED_MAX_BYTES;
|
|
269
|
+
const overManagedTokens = measure.estimatedTokens > ABSOLUTE_MANAGED_MAX_TOKENS;
|
|
270
|
+
const overCombinedBytes = bootstrap.totalBytes > ABSOLUTE_MANAGED_MAX_BYTES;
|
|
271
|
+
const overCombinedTokens = bootstrap.totalEstimatedTokens > ABSOLUTE_MANAGED_MAX_TOKENS;
|
|
272
|
+
if (options.advisoryOnly) {
|
|
273
|
+
if (!overManagedBytes && !overManagedTokens && !overCombinedBytes && !overCombinedTokens) {
|
|
274
|
+
return result;
|
|
275
|
+
}
|
|
276
|
+
return {
|
|
277
|
+
...result,
|
|
278
|
+
northStarMessage: formatAbsoluteAdvisory(bootstrap),
|
|
279
|
+
northStarStream: "stderr",
|
|
280
|
+
advisoryMessage: formatAbsoluteAdvisory(bootstrap),
|
|
281
|
+
advisoryStream: "stderr",
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
const distance = `${formatNorthStarDistance(measure)}\n ${formatCombinedNorthStarDistance(bootstrap)}`;
|
|
285
|
+
return {
|
|
286
|
+
...result,
|
|
287
|
+
northStarMessage: distance,
|
|
288
|
+
northStarStream: "stderr",
|
|
289
|
+
advisoryMessage: distance,
|
|
290
|
+
advisoryStream: "stderr",
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
function formatAbsoluteSummary(bootstrap, absoluteMaxBytes) {
|
|
294
|
+
const measure = bootstrap.managed;
|
|
295
|
+
return (`absolute managed ${measure.bytes}/${absoluteMaxBytes} bytes (~${measure.estimatedTokens} tok); ` +
|
|
296
|
+
`${formatBootstrapItemization(bootstrap)}`);
|
|
297
|
+
}
|
|
45
298
|
function formatRefusal(counts, managedMax, unmanagedMax, projectRoot) {
|
|
46
299
|
const over = [];
|
|
47
300
|
if (counts.managed > managedMax) {
|
|
@@ -106,19 +359,35 @@ export function evaluate(projectRoot, options = {}) {
|
|
|
106
359
|
};
|
|
107
360
|
}
|
|
108
361
|
const counts = regionResult.counts;
|
|
362
|
+
const bootstrapResult = measureBootstrapSurface(root, text, budgetResult.budget);
|
|
363
|
+
if ("error" in bootstrapResult) {
|
|
364
|
+
return {
|
|
365
|
+
code: 2,
|
|
366
|
+
message: `❌ verify:agents-md-budget: ${bootstrapResult.error}`,
|
|
367
|
+
stream: "stderr",
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
const bootstrap = bootstrapResult;
|
|
371
|
+
const measure = bootstrap.managed;
|
|
372
|
+
const absoluteMaxBytes = budgetResult.budget?.absoluteMaxBytes;
|
|
373
|
+
const advisoryOnly = absoluteMaxBytes === undefined;
|
|
374
|
+
const skillFrontmatterMaxBytes = budgetResult.budget?.skillFrontmatterMaxBytes;
|
|
109
375
|
if (budgetResult.source === "unset") {
|
|
110
376
|
if (quiet) {
|
|
111
|
-
return { code: 0, message: "", stream: "none" }
|
|
377
|
+
return attachNorthStarNote({ code: 0, message: "", stream: "none" }, bootstrap, {
|
|
378
|
+
advisoryOnly,
|
|
379
|
+
});
|
|
112
380
|
}
|
|
113
|
-
return {
|
|
381
|
+
return attachNorthStarNote({
|
|
114
382
|
code: 0,
|
|
115
383
|
message: "⚠ verify:agents-md-budget: no plan.policy.agentsMdBudget configured " +
|
|
116
384
|
`(managed=${counts.managed}, unmanaged=${counts.unmanaged} lines).\n` +
|
|
385
|
+
` ${formatBootstrapItemization(bootstrap)}.\n` +
|
|
117
386
|
" Seed a ratchet at current size to freeze growth (#645): set\n" +
|
|
118
387
|
" plan.policy.agentsMdBudget.{managedMaxLines,unmanagedMaxLines} in " +
|
|
119
388
|
"PROJECT-DEFINITION.",
|
|
120
389
|
stream: "stderr",
|
|
121
|
-
};
|
|
390
|
+
}, bootstrap, { advisoryOnly });
|
|
122
391
|
}
|
|
123
392
|
/* v8 ignore start -- defensive: source "typed" always carries a non-null budget. */
|
|
124
393
|
if (budgetResult.budget === null) {
|
|
@@ -132,21 +401,54 @@ export function evaluate(projectRoot, options = {}) {
|
|
|
132
401
|
const budget = budgetResult.budget;
|
|
133
402
|
const overManaged = counts.managed > budget.managedMaxLines;
|
|
134
403
|
const overUnmanaged = counts.unmanaged > budget.unmanagedMaxLines;
|
|
135
|
-
if (
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
message: `✓ verify:agents-md-budget: managed ${counts.managed}/${budget.managedMaxLines}, ` +
|
|
142
|
-
`unmanaged ${counts.unmanaged}/${budget.unmanagedMaxLines} lines (within ratchet).`,
|
|
143
|
-
stream: "stdout",
|
|
144
|
-
};
|
|
404
|
+
if (overManaged || overUnmanaged) {
|
|
405
|
+
return attachNorthStarNote({
|
|
406
|
+
code: 1,
|
|
407
|
+
message: formatRefusal(counts, budget.managedMaxLines, budget.unmanagedMaxLines, root),
|
|
408
|
+
stream: "stderr",
|
|
409
|
+
}, bootstrap, { advisoryOnly });
|
|
145
410
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
411
|
+
if (absoluteMaxBytes !== undefined && measure.bytes > absoluteMaxBytes) {
|
|
412
|
+
return attachNorthStarNote({
|
|
413
|
+
code: 1,
|
|
414
|
+
message: formatAbsoluteRefusal(bootstrap, absoluteMaxBytes, root),
|
|
415
|
+
stream: "stderr",
|
|
416
|
+
}, bootstrap, { advisoryOnly: false });
|
|
417
|
+
}
|
|
418
|
+
if (skillFrontmatterMaxBytes !== undefined &&
|
|
419
|
+
bootstrap.skillFrontmatter.bytes > skillFrontmatterMaxBytes) {
|
|
420
|
+
return attachNorthStarNote({
|
|
421
|
+
code: 1,
|
|
422
|
+
message: formatSkillFrontmatterRefusal(bootstrap, skillFrontmatterMaxBytes, root),
|
|
423
|
+
stream: "stderr",
|
|
424
|
+
}, bootstrap, { advisoryOnly: false });
|
|
425
|
+
}
|
|
426
|
+
const overNorthStarManaged = measure.bytes > ABSOLUTE_MANAGED_MAX_BYTES ||
|
|
427
|
+
measure.estimatedTokens > ABSOLUTE_MANAGED_MAX_TOKENS;
|
|
428
|
+
const overNorthStarCombined = bootstrap.totalBytes > ABSOLUTE_MANAGED_MAX_BYTES ||
|
|
429
|
+
bootstrap.totalEstimatedTokens > ABSOLUTE_MANAGED_MAX_TOKENS;
|
|
430
|
+
if (enforceNorthStarEnabled() &&
|
|
431
|
+
(overNorthStarManaged || overNorthStarCombined) &&
|
|
432
|
+
!northStarWaiverActive()) {
|
|
433
|
+
return attachNorthStarNote({
|
|
434
|
+
code: 1,
|
|
435
|
+
message: formatNorthStarRefusal(bootstrap, root),
|
|
436
|
+
stream: "stderr",
|
|
437
|
+
}, bootstrap, { advisoryOnly: false });
|
|
438
|
+
}
|
|
439
|
+
const absoluteSummary = absoluteMaxBytes !== undefined ? `; ${formatAbsoluteSummary(bootstrap, absoluteMaxBytes)}` : "";
|
|
440
|
+
const bootstrapSummary = absoluteMaxBytes === undefined ? `; ${formatBootstrapItemization(bootstrap)}` : "";
|
|
441
|
+
if (quiet) {
|
|
442
|
+
return attachNorthStarNote({ code: 0, message: "", stream: "none" }, bootstrap, {
|
|
443
|
+
advisoryOnly,
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
return attachNorthStarNote({
|
|
447
|
+
code: 0,
|
|
448
|
+
message: `✓ verify:agents-md-budget: managed ${counts.managed}/${budget.managedMaxLines}, ` +
|
|
449
|
+
`unmanaged ${counts.unmanaged}/${budget.unmanagedMaxLines} lines (within ratchet)` +
|
|
450
|
+
`${absoluteSummary}${bootstrapSummary}.`,
|
|
451
|
+
stream: "stdout",
|
|
452
|
+
}, bootstrap, { advisoryOnly });
|
|
151
453
|
}
|
|
152
454
|
//# sourceMappingURL=evaluate.js.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** Daily-core tier from spike #2370 / OpenPackage manifest (#2462). */
|
|
2
|
+
export declare const DAILY_CORE_SKILL_NAMES: readonly ["deft-directive-setup", "deft-directive-sync", "deft-directive-build", "deft-directive-pre-pr", "deft-directive-review-cycle", "deft-directive-triage"];
|
|
3
|
+
export type SkillFrontmatterTier = "daily-core" | "all" | "none";
|
|
4
|
+
export type HarnessProfile = "cursor" | "none";
|
|
5
|
+
/** Extract the YAML `description` field from a SKILL.md frontmatter block. */
|
|
6
|
+
export declare function extractSkillDescription(text: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Cursor `<agent_skill>` injection shape (DD-3 minimum).
|
|
9
|
+
* Uses repo-relative POSIX paths for stable cross-platform byte counts.
|
|
10
|
+
*/
|
|
11
|
+
export declare function formatCursorAgentSkill(relPath: string, description: string): string;
|
|
12
|
+
export interface SkillFrontmatterEntry {
|
|
13
|
+
readonly skillName: string;
|
|
14
|
+
readonly relPath: string;
|
|
15
|
+
readonly bytes: number;
|
|
16
|
+
}
|
|
17
|
+
export interface SkillFrontmatterMeasure {
|
|
18
|
+
readonly bytes: number;
|
|
19
|
+
readonly estimatedTokens: number;
|
|
20
|
+
readonly skillCount: number;
|
|
21
|
+
readonly tier: SkillFrontmatterTier;
|
|
22
|
+
readonly harnessProfile: HarnessProfile;
|
|
23
|
+
readonly entries: readonly SkillFrontmatterEntry[];
|
|
24
|
+
}
|
|
25
|
+
export interface MeasureSkillFrontmatterOptions {
|
|
26
|
+
readonly skillsRoot?: string;
|
|
27
|
+
readonly tier?: SkillFrontmatterTier;
|
|
28
|
+
readonly harnessProfile?: HarnessProfile;
|
|
29
|
+
readonly bytesPerToken?: number;
|
|
30
|
+
}
|
|
31
|
+
/** Measure harness-injected skill frontmatter bytes for the configured profile/tier. */
|
|
32
|
+
export declare function measureSkillFrontmatter(projectRoot: string, options?: MeasureSkillFrontmatterOptions): SkillFrontmatterMeasure;
|
|
33
|
+
//# sourceMappingURL=skill-frontmatter.d.ts.map
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join, posix } from "node:path";
|
|
3
|
+
/** Daily-core tier from spike #2370 / OpenPackage manifest (#2462). */
|
|
4
|
+
export const DAILY_CORE_SKILL_NAMES = [
|
|
5
|
+
"deft-directive-setup",
|
|
6
|
+
"deft-directive-sync",
|
|
7
|
+
"deft-directive-build",
|
|
8
|
+
"deft-directive-pre-pr",
|
|
9
|
+
"deft-directive-review-cycle",
|
|
10
|
+
"deft-directive-triage",
|
|
11
|
+
];
|
|
12
|
+
const DAILY_CORE_SET = new Set(DAILY_CORE_SKILL_NAMES);
|
|
13
|
+
/** Extract the YAML `description` field from a SKILL.md frontmatter block. */
|
|
14
|
+
export function extractSkillDescription(text) {
|
|
15
|
+
if (!text.startsWith("---")) {
|
|
16
|
+
return "";
|
|
17
|
+
}
|
|
18
|
+
const closing = text.indexOf("\n---", 3);
|
|
19
|
+
if (closing === -1) {
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
const frontmatter = text.slice(3, closing).replace(/^\r?\n/, "");
|
|
23
|
+
const lines = frontmatter.split(/\r?\n/);
|
|
24
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
25
|
+
const line = lines[i] ?? "";
|
|
26
|
+
if (/^description:\s*>(-)?\s*$/.test(line)) {
|
|
27
|
+
const descLines = [];
|
|
28
|
+
for (let j = i + 1; j < lines.length; j += 1) {
|
|
29
|
+
const next = lines[j] ?? "";
|
|
30
|
+
if (!/^[ \t]/.test(next)) {
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
descLines.push(next.replace(/^[ \t]+/, ""));
|
|
34
|
+
}
|
|
35
|
+
return descLines.join("\n").trim();
|
|
36
|
+
}
|
|
37
|
+
const single = line.match(/^description:\s*(.+)$/);
|
|
38
|
+
if (single !== null && single[1] !== undefined) {
|
|
39
|
+
return single[1].trim();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return "";
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Cursor `<agent_skill>` injection shape (DD-3 minimum).
|
|
46
|
+
* Uses repo-relative POSIX paths for stable cross-platform byte counts.
|
|
47
|
+
*/
|
|
48
|
+
export function formatCursorAgentSkill(relPath, description) {
|
|
49
|
+
const normalized = relPath.replace(/\\/g, "/");
|
|
50
|
+
return `<agent_skill fullPath="${normalized}">${description}</agent_skill>`;
|
|
51
|
+
}
|
|
52
|
+
function defaultSkillsRoot(projectRoot) {
|
|
53
|
+
return join(projectRoot, "content", "skills");
|
|
54
|
+
}
|
|
55
|
+
function listSkillDirs(skillsRoot) {
|
|
56
|
+
if (!existsSync(skillsRoot)) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
return readdirSync(skillsRoot, { withFileTypes: true })
|
|
60
|
+
.filter((entry) => entry.isDirectory())
|
|
61
|
+
.map((entry) => entry.name)
|
|
62
|
+
.sort();
|
|
63
|
+
}
|
|
64
|
+
function skillMatchesTier(skillName, tier) {
|
|
65
|
+
if (tier === "none") {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
if (tier === "all") {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
return DAILY_CORE_SET.has(skillName);
|
|
72
|
+
}
|
|
73
|
+
/** Measure harness-injected skill frontmatter bytes for the configured profile/tier. */
|
|
74
|
+
export function measureSkillFrontmatter(projectRoot, options = {}) {
|
|
75
|
+
const harnessProfile = options.harnessProfile ?? "cursor";
|
|
76
|
+
const tier = options.tier ?? "all";
|
|
77
|
+
const bytesPerToken = options.bytesPerToken ?? 4;
|
|
78
|
+
const skillsRoot = options.skillsRoot ?? defaultSkillsRoot(projectRoot);
|
|
79
|
+
if (harnessProfile === "none" || tier === "none") {
|
|
80
|
+
return {
|
|
81
|
+
bytes: 0,
|
|
82
|
+
estimatedTokens: 0,
|
|
83
|
+
skillCount: 0,
|
|
84
|
+
tier,
|
|
85
|
+
harnessProfile,
|
|
86
|
+
entries: [],
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
const entries = [];
|
|
90
|
+
for (const skillName of listSkillDirs(skillsRoot)) {
|
|
91
|
+
if (!skillMatchesTier(skillName, tier)) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const skillPath = join(skillsRoot, skillName, "SKILL.md");
|
|
95
|
+
if (!existsSync(skillPath)) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const text = readFileSync(skillPath, "utf8");
|
|
99
|
+
const description = extractSkillDescription(text);
|
|
100
|
+
const relPath = posix.join("content", "skills", skillName, "SKILL.md");
|
|
101
|
+
const block = formatCursorAgentSkill(relPath, description);
|
|
102
|
+
const bytes = Buffer.byteLength(block, "utf8");
|
|
103
|
+
entries.push({ skillName, relPath, bytes });
|
|
104
|
+
}
|
|
105
|
+
const bytes = entries.reduce((sum, entry) => sum + entry.bytes, 0);
|
|
106
|
+
return {
|
|
107
|
+
bytes,
|
|
108
|
+
estimatedTokens: Math.ceil(bytes / bytesPerToken),
|
|
109
|
+
skillCount: entries.length,
|
|
110
|
+
tier,
|
|
111
|
+
harnessProfile,
|
|
112
|
+
entries,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=skill-frontmatter.js.map
|
|
@@ -19,10 +19,13 @@ export interface CheckOrchestratorSeams {
|
|
|
19
19
|
readonly spawnFn?: (cmd: string, args: string[], opts: {
|
|
20
20
|
cwd: string;
|
|
21
21
|
stdio: string;
|
|
22
|
+
env?: NodeJS.ProcessEnv;
|
|
22
23
|
}) => {
|
|
23
24
|
status: number | null;
|
|
24
25
|
error?: Error;
|
|
25
26
|
};
|
|
27
|
+
/** Child-process environment (default: process.env). */
|
|
28
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
26
29
|
}
|
|
27
30
|
/**
|
|
28
31
|
* True when `path` is the directive framework source checkout root (not a
|
|
@@ -77,6 +77,7 @@ export function dispatchTaskCheck(frameworkRoot, projectRoot, seams = {}) {
|
|
|
77
77
|
const result = spawn(taskBin, [target, "--taskfile", taskfilePath], {
|
|
78
78
|
cwd,
|
|
79
79
|
stdio: "inherit",
|
|
80
|
+
env: seams.env,
|
|
80
81
|
});
|
|
81
82
|
if (result.error !== undefined) {
|
|
82
83
|
process.stderr.write(`check: failed to invoke task: ${result.error.message}\n`);
|
|
@@ -88,7 +89,7 @@ function defaultSpawn(cmd, args, opts) {
|
|
|
88
89
|
const result = spawnSync(cmd, args, {
|
|
89
90
|
cwd: opts.cwd,
|
|
90
91
|
stdio: opts.stdio,
|
|
91
|
-
env:
|
|
92
|
+
env: opts.env ?? process.env,
|
|
92
93
|
});
|
|
93
94
|
return { status: result.status, error: result.error };
|
|
94
95
|
}
|
package/dist/codebase/map.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
3
|
+
import { assertProjectionContained } from "../fs/projection-containment.js";
|
|
3
4
|
import { resolveProjectDefinitionPath } from "../layout/resolve.js";
|
|
4
5
|
import { extractCodeStructure, loadJsonFile } from "../verify-source/code-structure-validate.js";
|
|
5
6
|
import { CodeStructureConfigError, configErrorToDict, defaultCodeStructurePath, } from "./default-extractor.js";
|
|
@@ -239,6 +240,7 @@ export function writeCodebaseMap(projectRoot, options) {
|
|
|
239
240
|
const resolvedOutput = isAbsolute(options.outputPath)
|
|
240
241
|
? options.outputPath
|
|
241
242
|
: join(projectRoot, options.outputPath);
|
|
243
|
+
assertProjectionContained(projectRoot, resolvedOutput);
|
|
242
244
|
if (!options.force && !isDeftGenerated(resolvedOutput)) {
|
|
243
245
|
throw new Error(`refusing to overwrite non-generated MAP at ${resolvedOutput}; ` +
|
|
244
246
|
`missing '${GENERATED_SENTINEL}' banner`);
|
|
@@ -19,6 +19,5 @@ export declare function listSkillMdFiles(): string[];
|
|
|
19
19
|
export declare const RFC2119_LEGEND = "!=MUST, ~=SHOULD";
|
|
20
20
|
export declare const PLATFORM_DETECTION_HEADING = "## Platform Detection";
|
|
21
21
|
export declare const USER_MD_GATE_HEADING = "## USER.md Gate";
|
|
22
|
-
export declare const DEPRECATED_SKILL_REDIRECT_STUBS: Set<string>;
|
|
23
22
|
export declare const REQUIRED_OSES: Set<string>;
|
|
24
23
|
//# sourceMappingURL=helpers.d.ts.map
|