@deftai/directive-core 0.79.1 → 0.79.2
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/cache/fetch.js +14 -4
- package/dist/capacity/backfill.js +4 -2
- package/dist/category-b-namespace/index.js +31 -6
- package/dist/content-contracts/skills/skill-frontmatter.js +6 -2
- package/dist/eval/health.js +8 -1
- package/dist/eval/run.js +2 -0
- package/dist/fs/projection-containment.d.ts +11 -0
- package/dist/fs/projection-containment.js +62 -1
- package/dist/hooks/dispatcher.d.ts +1 -1
- package/dist/hooks/dispatcher.js +66 -7
- package/dist/init-deposit/hygiene.js +3 -0
- package/dist/intake/reconcile-issues.d.ts +1 -1
- package/dist/intake/reconcile-issues.js +25 -2
- package/dist/issue-sync/sync-from-xbrief-cli.d.ts +1 -0
- package/dist/issue-sync/sync-from-xbrief-cli.js +3 -0
- package/dist/issue-sync/sync-from-xbrief.d.ts +4 -0
- package/dist/issue-sync/sync-from-xbrief.js +12 -0
- package/dist/lifecycle/event.d.ts +15 -0
- package/dist/lifecycle/event.js +163 -0
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.js +1 -0
- package/dist/orchestration/verify-judgment-gates.js +18 -2
- package/dist/pr-merge-readiness/compute.d.ts +2 -1
- package/dist/pr-merge-readiness/compute.js +23 -6
- package/dist/pr-merge-readiness/evaluate.d.ts +2 -1
- package/dist/pr-merge-readiness/evaluate.js +46 -31
- package/dist/pr-merge-readiness/greptile-inline.d.ts +27 -0
- package/dist/pr-merge-readiness/greptile-inline.js +239 -0
- package/dist/pr-merge-readiness/index.d.ts +1 -0
- package/dist/pr-merge-readiness/index.js +1 -0
- package/dist/pr-merge-readiness/mergeability.d.ts +2 -1
- package/dist/pr-merge-readiness/mergeability.js +7 -1
- package/dist/scope/demote.js +20 -0
- package/dist/swarm/worktrees.d.ts +3 -0
- package/dist/swarm/worktrees.js +18 -2
- package/dist/task-surface/index.js +3 -2
- package/dist/vitest-runner/win32-coverage-tmp-setup.d.ts +16 -8
- package/dist/vitest-runner/win32-coverage-tmp-setup.js +41 -14
- package/dist/xbrief-migrate/migration-containment.js +9 -25
- package/package.json +3 -3
|
@@ -3,6 +3,7 @@ export { computeGateResult } from "./compute.js";
|
|
|
3
3
|
export * from "./constants.js";
|
|
4
4
|
export { evaluateGates, isMergeReady } from "./evaluate.js";
|
|
5
5
|
export { defaultRunGh } from "./gh.js";
|
|
6
|
+
export { evaluateInlineReviewThreads, fetchUnresolvedGreptileInlineFindings, headShaMatches, inlineFindingsToDict, } from "./greptile-inline.js";
|
|
6
7
|
export { cmdPrMergeReadiness, parseArgs, run } from "./main.js";
|
|
7
8
|
export { fetchMergeability, isGithubMergeableClean, MERGE_STATE_CLEAN, mergeabilityToDict, verdictBlockIsSoftOnly, verdictShaIsStale, } from "./mergeability.js";
|
|
8
9
|
export { emitJson, exitCodeFor, gateResultToDict, printHuman } from "./output.js";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { InlineGreptileFindings } from "./greptile-inline.js";
|
|
1
2
|
import type { GreptileVerdict, RunGhFn } from "./types.js";
|
|
2
3
|
/**
|
|
3
4
|
* GitHub's authoritative mergeability signal, read over REST (#2260).
|
|
@@ -41,5 +42,5 @@ export declare function verdictShaIsStale(verdict: GreptileVerdict, headSha: str
|
|
|
41
42
|
* regardless of GitHub mergeability (guardrail: do not merge a PR with a real
|
|
42
43
|
* P0/P1 review finding).
|
|
43
44
|
*/
|
|
44
|
-
export declare function verdictBlockIsSoftOnly(verdict: GreptileVerdict, headSha: string | null): boolean;
|
|
45
|
+
export declare function verdictBlockIsSoftOnly(verdict: GreptileVerdict, headSha: string | null, inline?: InlineGreptileFindings | null): boolean;
|
|
45
46
|
//# sourceMappingURL=mergeability.d.ts.map
|
|
@@ -75,7 +75,13 @@ export function verdictShaIsStale(verdict, headSha) {
|
|
|
75
75
|
* regardless of GitHub mergeability (guardrail: do not merge a PR with a real
|
|
76
76
|
* P0/P1 review finding).
|
|
77
77
|
*/
|
|
78
|
-
export function verdictBlockIsSoftOnly(verdict, headSha) {
|
|
78
|
+
export function verdictBlockIsSoftOnly(verdict, headSha, inline = null) {
|
|
79
|
+
if (inline !== null && inline.error !== null) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
if (inline !== null && inline.error === null && (inline.p0Count > 0 || inline.p1Count > 0)) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
79
85
|
// Absent: no Greptile rolling-summary comment at all.
|
|
80
86
|
if (!verdict.found) {
|
|
81
87
|
return true;
|
package/dist/scope/demote.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, statSync, writeFileSync, } from "node:fs";
|
|
2
2
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
3
|
+
import { assertWriteTargetSafe, ProjectionContainmentError } from "../fs/projection-containment.js";
|
|
3
4
|
import { hasArtifactSuffix, resolveLifecycleFolder } from "../layout/resolve.js";
|
|
4
5
|
import { stripTrailingPathSeparators } from "../text/redos-safe.js";
|
|
5
6
|
import { append, canonicalLogPath, latestForPath, newDecisionId } from "./audit-log.js";
|
|
@@ -51,6 +52,15 @@ export function demoteOne(filePath, projectRoot, reason, options = {}) {
|
|
|
51
52
|
auditEntry: null,
|
|
52
53
|
};
|
|
53
54
|
}
|
|
55
|
+
try {
|
|
56
|
+
assertWriteTargetSafe(projectRoot, resolved);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
if (err instanceof ProjectionContainmentError) {
|
|
60
|
+
return { ok: false, message: err.message, auditEntry: null };
|
|
61
|
+
}
|
|
62
|
+
throw err;
|
|
63
|
+
}
|
|
54
64
|
let data;
|
|
55
65
|
try {
|
|
56
66
|
data = JSON.parse(readFileSync(resolved, "utf8"));
|
|
@@ -129,6 +139,16 @@ export function batchDemote(projectRoot, olderThanDays, options = {}) {
|
|
|
129
139
|
.sort();
|
|
130
140
|
for (const name of files) {
|
|
131
141
|
const candidate = join(pendingDir, name);
|
|
142
|
+
try {
|
|
143
|
+
assertWriteTargetSafe(projectRoot, candidate);
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
if (err instanceof ProjectionContainmentError) {
|
|
147
|
+
skipped.push(`${name}: ${err.message}`);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
throw err;
|
|
151
|
+
}
|
|
132
152
|
let data;
|
|
133
153
|
try {
|
|
134
154
|
data = JSON.parse(readFileSync(candidate, "utf8"));
|
|
@@ -18,6 +18,9 @@ export declare class DuplicateStoryError extends WorktreeMapError {
|
|
|
18
18
|
export declare class WorktreeMapConfigError extends Error {
|
|
19
19
|
name: string;
|
|
20
20
|
}
|
|
21
|
+
export declare class WorktreePathEscapeError extends WorktreeMapError {
|
|
22
|
+
name: string;
|
|
23
|
+
}
|
|
21
24
|
export type GitRunner = (args: readonly string[], cwd: string) => TextCaptureResult;
|
|
22
25
|
export declare const defaultGitRunner: GitRunner;
|
|
23
26
|
/** Case-normalized comparison key for worktree-path equality. */
|
package/dist/swarm/worktrees.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { mkdirSync, readFileSync } from "node:fs";
|
|
2
|
-
import { resolve as pathResolve } from "node:path";
|
|
2
|
+
import { isAbsolute, resolve as pathResolve } from "node:path";
|
|
3
|
+
import { assertProjectionContained, ProjectionContainmentError, } from "../fs/projection-containment.js";
|
|
3
4
|
import { C3_FIELDS } from "./constants.js";
|
|
4
5
|
import { runText } from "./subprocess.js";
|
|
5
6
|
export class WorktreeMapError extends Error {
|
|
@@ -20,11 +21,25 @@ export class DuplicateStoryError extends WorktreeMapError {
|
|
|
20
21
|
export class WorktreeMapConfigError extends Error {
|
|
21
22
|
name = "WorktreeMapConfigError";
|
|
22
23
|
}
|
|
24
|
+
export class WorktreePathEscapeError extends WorktreeMapError {
|
|
25
|
+
name = "WorktreePathEscapeError";
|
|
26
|
+
}
|
|
23
27
|
export const defaultGitRunner = (args, cwd) => runText(["git", ...args], { cwd });
|
|
24
28
|
function resolvePath(raw, repoRoot) {
|
|
25
|
-
const candidate = raw
|
|
29
|
+
const candidate = isAbsolute(raw) ? raw : pathResolve(repoRoot, raw);
|
|
26
30
|
return pathResolve(candidate);
|
|
27
31
|
}
|
|
32
|
+
function assertWorktreePathContained(repoRoot, worktreePath) {
|
|
33
|
+
try {
|
|
34
|
+
assertProjectionContained(repoRoot, worktreePath);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
if (err instanceof ProjectionContainmentError) {
|
|
38
|
+
throw new WorktreePathEscapeError(`worktree_path must stay under the repository root: ${err.message}`);
|
|
39
|
+
}
|
|
40
|
+
throw err;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
28
43
|
/** Case-normalized comparison key for worktree-path equality. */
|
|
29
44
|
export function compareKey(pathStr) {
|
|
30
45
|
return pathStr.replace(/\\/g, "/").toLowerCase();
|
|
@@ -119,6 +134,7 @@ export function resolveWorktreeMap(mapping, baseBranch, createMissing = true, op
|
|
|
119
134
|
}
|
|
120
135
|
}
|
|
121
136
|
const worktreePath = resolvePath(rawPath.trim(), root);
|
|
137
|
+
assertWorktreePathContained(root, worktreePath);
|
|
122
138
|
const key = compareKey(worktreePath);
|
|
123
139
|
const posixPath = worktreePath.replace(/\\/g, "/");
|
|
124
140
|
if (seenPaths.has(key)) {
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
|
+
import { LEGACY_VBRIEF_VERSION } from "@deftai/directive-types";
|
|
4
5
|
const UNRELEASED_RE = /## \[Unreleased\][ \t]*\n([\s\S]*?)(?=\n## \[|$)/;
|
|
5
6
|
const CHANGE_NAME_RE = /^[\w][\w-]*$/;
|
|
6
7
|
const COMMIT_TYPES = "feat|fix|docs|chore|refactor|test|style|perf|ci|build|revert";
|
|
7
8
|
const COMMIT_SUBJECT_RE = new RegExp(`^(${COMMIT_TYPES})(\\(.+\\))?!?: .+`);
|
|
8
9
|
function proposalTemplate(name) {
|
|
9
10
|
return {
|
|
10
|
-
vBRIEFInfo: { version:
|
|
11
|
+
vBRIEFInfo: { version: LEGACY_VBRIEF_VERSION },
|
|
11
12
|
plan: {
|
|
12
13
|
title: name,
|
|
13
14
|
status: "draft",
|
|
@@ -26,7 +27,7 @@ function proposalTemplate(name) {
|
|
|
26
27
|
}
|
|
27
28
|
function tasksTemplate(name) {
|
|
28
29
|
return {
|
|
29
|
-
vBRIEFInfo: { version:
|
|
30
|
+
vBRIEFInfo: { version: LEGACY_VBRIEF_VERSION },
|
|
30
31
|
plan: { title: name, status: "draft", items: [], edges: [] },
|
|
31
32
|
};
|
|
32
33
|
}
|
|
@@ -1,12 +1,20 @@
|
|
|
1
|
+
/** Matches Vitest v8 chunk paths such as coverage/.tmp/coverage-0.json (#2580 / #2634). */
|
|
2
|
+
export declare const COVERAGE_TMP_CHUNK_RE: RegExp;
|
|
3
|
+
export declare function isCoverageTmpChunkPath(filePath: string): boolean;
|
|
4
|
+
export declare function ensureCoverageTmpDir(coverageTmpDir?: string): void;
|
|
1
5
|
/**
|
|
2
|
-
*
|
|
6
|
+
* Vitest 3.2.x writes coverage chunks without mkdir'ing the parent directory
|
|
7
|
+
* (fixed upstream in vitest 4.x — vitest-dev/vitest#10117). On Windows the
|
|
8
|
+
* directory can disappear between clean() and writeFile under release-scale
|
|
9
|
+
* load; mkdir immediately before chunk writes closes that race without
|
|
10
|
+
* soft-failing real threshold failures (#2634).
|
|
11
|
+
*/
|
|
12
|
+
export declare function installCoverageTmpWriteGuard(): () => void;
|
|
13
|
+
/**
|
|
14
|
+
* Win32 globalSetup for coverage runs (#2580, hardened #2634).
|
|
3
15
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* disappear mid-suite, surfacing as ENOENT after an otherwise green run.
|
|
7
|
-
* Keep the directory present for the coordinator process; late ENOENT flakes
|
|
8
|
-
* are tolerated via vitest dangerouslyIgnoreUnhandledErrors (#2546) without
|
|
9
|
-
* soft-failing real coverage threshold failures.
|
|
16
|
+
* Keepalive mkdir plus a writeFile guard mirror vitest 4's defensive mkdir until
|
|
17
|
+
* directive upgrades past vitest@3 (see vitest.config.ts #2634 upgrade note).
|
|
10
18
|
*/
|
|
11
|
-
export default function setup(): void;
|
|
19
|
+
export default function setup(): () => void;
|
|
12
20
|
//# sourceMappingURL=win32-coverage-tmp-setup.d.ts.map
|
|
@@ -1,24 +1,51 @@
|
|
|
1
|
-
import { mkdirSync } from "node:fs";
|
|
2
|
-
import { resolve } from "node:path";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { promises as fsPromises, mkdirSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
/** Matches Vitest v8 chunk paths such as coverage/.tmp/coverage-0.json (#2580 / #2634). */
|
|
4
|
+
export const COVERAGE_TMP_CHUNK_RE = /[/\\]coverage[/\\]\.tmp[/\\]coverage-\d+\.json$/;
|
|
5
|
+
const defaultCoverageTmp = resolve(process.cwd(), "coverage", ".tmp");
|
|
6
|
+
export function isCoverageTmpChunkPath(filePath) {
|
|
7
|
+
return COVERAGE_TMP_CHUNK_RE.test(filePath.replace(/\\/g, "/"));
|
|
8
|
+
}
|
|
9
|
+
export function ensureCoverageTmpDir(coverageTmpDir = defaultCoverageTmp) {
|
|
10
|
+
mkdirSync(coverageTmpDir, { recursive: true });
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Vitest 3.2.x writes coverage chunks without mkdir'ing the parent directory
|
|
14
|
+
* (fixed upstream in vitest 4.x — vitest-dev/vitest#10117). On Windows the
|
|
15
|
+
* directory can disappear between clean() and writeFile under release-scale
|
|
16
|
+
* load; mkdir immediately before chunk writes closes that race without
|
|
17
|
+
* soft-failing real threshold failures (#2634).
|
|
18
|
+
*/
|
|
19
|
+
export function installCoverageTmpWriteGuard() {
|
|
20
|
+
const originalWriteFile = fsPromises.writeFile.bind(fsPromises);
|
|
21
|
+
const patchedWriteFile = async (path, ...args) => {
|
|
22
|
+
const target = typeof path === "string" ? path : String(path);
|
|
23
|
+
if (isCoverageTmpChunkPath(target)) {
|
|
24
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
return originalWriteFile(path, ...args);
|
|
27
|
+
};
|
|
28
|
+
fsPromises.writeFile = patchedWriteFile;
|
|
29
|
+
return () => {
|
|
30
|
+
fsPromises.writeFile = originalWriteFile;
|
|
31
|
+
};
|
|
6
32
|
}
|
|
7
33
|
/**
|
|
8
|
-
* Win32 globalSetup for coverage runs (#2580).
|
|
34
|
+
* Win32 globalSetup for coverage runs (#2580, hardened #2634).
|
|
9
35
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* disappear mid-suite, surfacing as ENOENT after an otherwise green run.
|
|
13
|
-
* Keep the directory present for the coordinator process; late ENOENT flakes
|
|
14
|
-
* are tolerated via vitest dangerouslyIgnoreUnhandledErrors (#2546) without
|
|
15
|
-
* soft-failing real coverage threshold failures.
|
|
36
|
+
* Keepalive mkdir plus a writeFile guard mirror vitest 4's defensive mkdir until
|
|
37
|
+
* directive upgrades past vitest@3 (see vitest.config.ts #2634 upgrade note).
|
|
16
38
|
*/
|
|
17
39
|
export default function setup() {
|
|
18
40
|
if (process.platform !== "win32")
|
|
19
|
-
return;
|
|
41
|
+
return () => { };
|
|
20
42
|
ensureCoverageTmpDir();
|
|
21
|
-
const
|
|
43
|
+
const uninstallWriteGuard = installCoverageTmpWriteGuard();
|
|
44
|
+
const keepalive = setInterval(() => ensureCoverageTmpDir(), 50);
|
|
22
45
|
keepalive.unref?.();
|
|
46
|
+
return () => {
|
|
47
|
+
clearInterval(keepalive);
|
|
48
|
+
uninstallWriteGuard();
|
|
49
|
+
};
|
|
23
50
|
}
|
|
24
51
|
//# sourceMappingURL=win32-coverage-tmp-setup.js.map
|
|
@@ -1,37 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { assertProjectionContained } from "../fs/projection-containment.js";
|
|
1
|
+
import { assertProjectionContained, ProjectionContainmentError, walkDirectoryRejectSymlinks, } from "../fs/projection-containment.js";
|
|
4
2
|
/**
|
|
5
3
|
* Refuse migrate:xbrief when legacy `vbrief/` (or any traversed entry) escapes
|
|
6
4
|
* the project tree via symlinks (#2601).
|
|
7
5
|
*/
|
|
8
6
|
export function assertMigrationSourceSafe(projectRoot, legacyDir) {
|
|
9
7
|
assertProjectionContained(projectRoot, legacyDir);
|
|
10
|
-
walkMigrationTreeRejectSymlinks(legacyDir);
|
|
11
|
-
}
|
|
12
|
-
function walkMigrationTreeRejectSymlinks(root) {
|
|
13
|
-
let entries;
|
|
14
8
|
try {
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
catch {
|
|
18
|
-
return;
|
|
9
|
+
walkDirectoryRejectSymlinks(legacyDir);
|
|
19
10
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
catch {
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
if (info.isSymbolicLink()) {
|
|
30
|
-
throw new Error(`refusing to migrate: symlink on migration path: ${full}`);
|
|
31
|
-
}
|
|
32
|
-
if (info.isDirectory()) {
|
|
33
|
-
walkMigrationTreeRejectSymlinks(full);
|
|
11
|
+
catch (err) {
|
|
12
|
+
if (err instanceof ProjectionContainmentError) {
|
|
13
|
+
const nested = err.message.match(/symlink on traversal path: (.+)$/);
|
|
14
|
+
if (nested) {
|
|
15
|
+
throw new Error(`refusing to migrate: symlink on migration path: ${nested[1]}`);
|
|
16
|
+
}
|
|
34
17
|
}
|
|
18
|
+
throw err;
|
|
35
19
|
}
|
|
36
20
|
}
|
|
37
21
|
//# sourceMappingURL=migration-containment.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deftai/directive-core",
|
|
3
|
-
"version": "0.79.
|
|
3
|
+
"version": "0.79.2",
|
|
4
4
|
"description": "TypeScript engine core for the Directive framework.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -305,8 +305,8 @@
|
|
|
305
305
|
"provenance": true
|
|
306
306
|
},
|
|
307
307
|
"dependencies": {
|
|
308
|
-
"@deftai/directive-content": "^0.79.
|
|
309
|
-
"@deftai/directive-types": "^0.79.
|
|
308
|
+
"@deftai/directive-content": "^0.79.2",
|
|
309
|
+
"@deftai/directive-types": "^0.79.2",
|
|
310
310
|
"archiver": "^8.0.0"
|
|
311
311
|
},
|
|
312
312
|
"scripts": {
|