@deftai/directive-core 0.83.0 → 0.85.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/cache/fetch.d.ts +17 -0
- package/dist/cache/fetch.js +50 -0
- package/dist/cache/main.js +36 -2
- package/dist/cache/task-cache/constants.d.ts +4 -0
- package/dist/cache/task-cache/constants.js +4 -0
- package/dist/cache/task-cache/executor.d.ts +9 -0
- package/dist/cache/task-cache/executor.js +51 -0
- package/dist/cache/task-cache/hash.d.ts +17 -0
- package/dist/cache/task-cache/hash.js +92 -0
- package/dist/cache/task-cache/index.d.ts +14 -0
- package/dist/cache/task-cache/index.js +15 -0
- package/dist/cache/task-cache/lint.d.ts +4 -0
- package/dist/cache/task-cache/lint.js +55 -0
- package/dist/cache/task-cache/registry.d.ts +7 -0
- package/dist/cache/task-cache/registry.js +67 -0
- package/dist/cache/task-cache/store.d.ts +10 -0
- package/dist/cache/task-cache/store.js +48 -0
- package/dist/cache/task-cache/types.d.ts +48 -0
- package/dist/cache/task-cache/types.js +3 -0
- package/dist/check/cached-orchestrator.d.ts +16 -0
- package/dist/check/cached-orchestrator.js +76 -0
- package/dist/check/context.d.ts +30 -0
- package/dist/check/context.js +28 -0
- package/dist/check/gate-lists.d.ts +18 -0
- package/dist/check/gate-lists.js +68 -0
- package/dist/check/index.d.ts +4 -1
- package/dist/check/index.js +3 -0
- package/dist/check/orchestrator.d.ts +3 -45
- package/dist/check/orchestrator.js +8 -46
- package/dist/check/runner-detect.d.ts +20 -0
- package/dist/check/runner-detect.js +131 -0
- package/dist/doctor/checks.js +16 -1
- package/dist/doctor/constants.d.ts +2 -0
- package/dist/doctor/constants.js +8 -4
- package/dist/doctor/index.d.ts +1 -0
- package/dist/doctor/index.js +1 -0
- package/dist/doctor/main.js +13 -4
- package/dist/doctor/npm-registry.d.ts +23 -0
- package/dist/doctor/npm-registry.js +128 -0
- package/dist/doctor/npm-view.d.ts +10 -0
- package/dist/doctor/npm-view.js +31 -0
- package/dist/doctor/payload-staleness.js +2 -9
- package/dist/doctor/signpost-checks.d.ts +2 -1
- package/dist/doctor/signpost-checks.js +2 -0
- package/dist/doctor/types.d.ts +9 -0
- package/dist/eval/readback.js +6 -1
- package/dist/eval-health-relocation/evaluate.js +15 -1
- package/dist/fs/projection-containment.js +1 -1
- package/dist/hooks/cursor-hooks.d.ts +6 -20
- package/dist/hooks/cursor-hooks.js +7 -92
- package/dist/hooks/dispatcher.d.ts +2 -0
- package/dist/hooks/dispatcher.js +48 -6
- package/dist/init-deposit/agent-hooks.d.ts +2 -2
- package/dist/init-deposit/agent-hooks.js +15 -37
- package/dist/init-deposit/gitignore.js +1 -0
- package/dist/init-deposit/hygiene.d.ts +22 -0
- package/dist/init-deposit/hygiene.js +136 -4
- package/dist/init-deposit/legacy-detect.d.ts +25 -1
- package/dist/init-deposit/legacy-detect.js +143 -11
- package/dist/init-deposit/refresh.d.ts +2 -0
- package/dist/init-deposit/refresh.js +18 -5
- package/dist/policy/index.d.ts +2 -0
- package/dist/policy/index.js +2 -0
- package/dist/policy/org-force-on-migration.d.ts +44 -0
- package/dist/policy/org-force-on-migration.js +240 -0
- package/dist/policy/product-signal.d.ts +3 -1
- package/dist/policy/product-signal.js +15 -4
- package/dist/policy/value-feedback.d.ts +18 -1
- package/dist/policy/value-feedback.js +78 -5
- package/dist/preflight-cache/evaluate.js +12 -1
- package/dist/product-signal/consent-prompt.d.ts +13 -0
- package/dist/product-signal/consent-prompt.js +30 -0
- package/dist/product-signal/submit.js +22 -1
- package/dist/render/index.d.ts +1 -0
- package/dist/render/index.js +1 -0
- package/dist/render/rule-map-template.d.ts +2 -0
- package/dist/render/rule-map-template.js +407 -0
- package/dist/render/rule-map.d.ts +2 -0
- package/dist/render/rule-map.js +703 -0
- package/dist/review-monitor/constants.d.ts +7 -1
- package/dist/review-monitor/constants.js +40 -14
- package/dist/review-monitor/github-lease.d.ts +45 -0
- package/dist/review-monitor/github-lease.js +106 -0
- package/dist/review-monitor/index.d.ts +2 -0
- package/dist/review-monitor/index.js +2 -0
- package/dist/review-monitor/lease-comment.d.ts +36 -0
- package/dist/review-monitor/lease-comment.js +152 -0
- package/dist/review-monitor/record.d.ts +61 -13
- package/dist/review-monitor/record.js +379 -132
- package/dist/review-monitor/verify.d.ts +2 -0
- package/dist/review-monitor/verify.js +32 -13
- package/dist/scm/gh-rest.d.ts +7 -1
- package/dist/scm/gh-rest.js +35 -0
- package/dist/scope/decompose.js +9 -3
- package/dist/session/git.d.ts +2 -0
- package/dist/session/git.js +14 -0
- package/dist/session/session-start.js +5 -0
- package/dist/session/verify-session-ritual.js +39 -5
- package/dist/swarm/routing-set-cli.js +16 -5
- package/dist/swarm/routing.d.ts +1 -1
- package/dist/swarm/routing.js +3 -1
- package/dist/task-surface/index.js +53 -13
- package/dist/value/readback.js +6 -1
- package/dist/xbrief-migrate/constants.d.ts +6 -0
- package/dist/xbrief-migrate/constants.js +6 -0
- package/dist/xbrief-migrate/index.d.ts +2 -2
- package/dist/xbrief-migrate/index.js +2 -2
- package/dist/xbrief-migrate/migrate-project.d.ts +7 -0
- package/dist/xbrief-migrate/migrate-project.js +18 -1
- package/package.json +7 -3
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { lintShippedRegistry, resolveTaskContract, runWithCache, } from "../cache/task-cache/index.js";
|
|
4
|
+
import { readCorePackageVersion } from "../engine-version.js";
|
|
5
|
+
import { resolveCheckTarget } from "./context.js";
|
|
6
|
+
import { checkGateId, checkGateSpawnArgs, gatesForCheckTarget } from "./gate-lists.js";
|
|
7
|
+
function captureSpawn(taskBin, args, opts) {
|
|
8
|
+
const result = spawnSync(taskBin, args, {
|
|
9
|
+
cwd: opts.cwd,
|
|
10
|
+
encoding: "utf8",
|
|
11
|
+
env: opts.env ?? process.env,
|
|
12
|
+
});
|
|
13
|
+
return {
|
|
14
|
+
exitCode: result.status ?? 1,
|
|
15
|
+
stdout: result.stdout ?? "",
|
|
16
|
+
stderr: result.stderr ?? "",
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Run check gates sequentially with content-hash caching (#1713).
|
|
21
|
+
* Falls back to fail-open execution for undeclared / non-cacheable gates.
|
|
22
|
+
*/
|
|
23
|
+
export function dispatchCachedTaskCheck(frameworkRoot, projectRoot, options = {}) {
|
|
24
|
+
const resolvedFramework = resolve(frameworkRoot);
|
|
25
|
+
const resolvedProject = resolve(projectRoot);
|
|
26
|
+
const taskfilePath = join(resolvedFramework, "Taskfile.yml");
|
|
27
|
+
const taskBin = options.taskBin ?? "task";
|
|
28
|
+
const target = resolveCheckTarget(resolvedFramework, resolvedProject);
|
|
29
|
+
const cwd = target === "check:framework-source" ? resolvedFramework : resolvedProject;
|
|
30
|
+
const gates = gatesForCheckTarget(target);
|
|
31
|
+
const codeVersion = readCorePackageVersion();
|
|
32
|
+
const registryLint = lintShippedRegistry();
|
|
33
|
+
if (!registryLint.ok) {
|
|
34
|
+
for (const finding of registryLint.findings.filter((f) => f.kind === "under-declared-input")) {
|
|
35
|
+
process.stderr.write(`check: task registry lint failed for ${finding.taskId}: ${finding.detail}\n`);
|
|
36
|
+
}
|
|
37
|
+
return 2;
|
|
38
|
+
}
|
|
39
|
+
if (gates.length === 0) {
|
|
40
|
+
process.stderr.write(`check: no gate list for target ${target}\n`);
|
|
41
|
+
return 2;
|
|
42
|
+
}
|
|
43
|
+
for (const gateSpec of gates) {
|
|
44
|
+
const gateId = checkGateId(gateSpec);
|
|
45
|
+
options.onGateStart?.(gateId);
|
|
46
|
+
const contract = resolveTaskContract(gateId);
|
|
47
|
+
const taskArgs = checkGateSpawnArgs(gateSpec, taskfilePath);
|
|
48
|
+
const result = runWithCache({
|
|
49
|
+
projectRoot: cwd,
|
|
50
|
+
contract,
|
|
51
|
+
codeVersion,
|
|
52
|
+
noCache: options.noCache,
|
|
53
|
+
runner: () => {
|
|
54
|
+
const spawned = options.gateSpawnFn
|
|
55
|
+
? options.gateSpawnFn(gateId, taskBin, taskArgs, {
|
|
56
|
+
cwd,
|
|
57
|
+
env: options.env,
|
|
58
|
+
})
|
|
59
|
+
: captureSpawn(taskBin, taskArgs, { cwd, env: options.env });
|
|
60
|
+
if (spawned.stdout.length > 0) {
|
|
61
|
+
process.stdout.write(spawned.stdout);
|
|
62
|
+
}
|
|
63
|
+
if (spawned.stderr.length > 0) {
|
|
64
|
+
process.stderr.write(spawned.stderr);
|
|
65
|
+
}
|
|
66
|
+
return spawned;
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
options.onGateComplete?.(gateId, result.exitCode, result.fromCache);
|
|
70
|
+
if (result.exitCode !== 0) {
|
|
71
|
+
return result.exitCode;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return 0;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=cached-orchestrator.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface CheckOrchestratorOptions {
|
|
2
|
+
readonly noCache?: boolean;
|
|
3
|
+
readonly useTaskCache?: boolean;
|
|
4
|
+
}
|
|
5
|
+
export interface CheckOrchestratorSeams extends CheckOrchestratorOptions {
|
|
6
|
+
/** Override the `task` binary path (default: "task"). */
|
|
7
|
+
readonly taskBin?: string;
|
|
8
|
+
/** Override the spawnSync implementation for unit testing. */
|
|
9
|
+
readonly spawnFn?: (cmd: string, args: string[], opts: {
|
|
10
|
+
cwd: string;
|
|
11
|
+
stdio: string;
|
|
12
|
+
env?: NodeJS.ProcessEnv;
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
}) => {
|
|
15
|
+
status: number | null;
|
|
16
|
+
signal?: NodeJS.Signals | null;
|
|
17
|
+
error?: Error;
|
|
18
|
+
};
|
|
19
|
+
/** Child-process environment (default: process.env). */
|
|
20
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
21
|
+
/** Wall-clock spawn timeout in milliseconds (default: none). */
|
|
22
|
+
readonly timeoutMs?: number;
|
|
23
|
+
}
|
|
24
|
+
/** True when `path` is the directive framework source checkout root. */
|
|
25
|
+
export declare function isFrameworkRepoRoot(path: string): boolean;
|
|
26
|
+
/** Return true when running in the framework's own source checkout (#1519). */
|
|
27
|
+
export declare function isFrameworkSourceContext(frameworkRoot: string, projectRoot: string): boolean;
|
|
28
|
+
/** Select the Taskfile target for the given context. */
|
|
29
|
+
export declare function resolveCheckTarget(frameworkRoot: string, projectRoot: string): string;
|
|
30
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join, resolve, sep } from "node:path";
|
|
3
|
+
/** True when `path` is the directive framework source checkout root. */
|
|
4
|
+
export function isFrameworkRepoRoot(path) {
|
|
5
|
+
const root = resolve(path);
|
|
6
|
+
return (existsSync(join(root, "packages", "cli", "package.json")) &&
|
|
7
|
+
existsSync(join(root, "biome.json")) &&
|
|
8
|
+
existsSync(join(root, "Taskfile.yml")));
|
|
9
|
+
}
|
|
10
|
+
/** Return true when running in the framework's own source checkout (#1519). */
|
|
11
|
+
export function isFrameworkSourceContext(frameworkRoot, projectRoot) {
|
|
12
|
+
const fw = resolve(frameworkRoot);
|
|
13
|
+
const pr = resolve(projectRoot);
|
|
14
|
+
if (fw === pr) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
if (!isFrameworkRepoRoot(fw)) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
return pr.startsWith(`${fw}${sep}`);
|
|
21
|
+
}
|
|
22
|
+
/** Select the Taskfile target for the given context. */
|
|
23
|
+
export function resolveCheckTarget(frameworkRoot, projectRoot) {
|
|
24
|
+
return isFrameworkSourceContext(frameworkRoot, projectRoot)
|
|
25
|
+
? "check:framework-source"
|
|
26
|
+
: "check:consumer";
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Gate execution order mirrors Taskfile.yml check targets (#1713 dogfood). */
|
|
2
|
+
/**
|
|
3
|
+
* A check gate is either a bare Taskfile task name, or a public task plus CLI
|
|
4
|
+
* args (after `--`). Framework-only shims that are `internal: true` in
|
|
5
|
+
* Taskfile.yml cannot be shelled by name under go-task 3.50 (#2791) — use the
|
|
6
|
+
* public surface with the shim's flags instead.
|
|
7
|
+
*/
|
|
8
|
+
export type CheckGateSpec = string | {
|
|
9
|
+
readonly task: string;
|
|
10
|
+
readonly args?: readonly string[];
|
|
11
|
+
};
|
|
12
|
+
export declare function checkGateId(spec: CheckGateSpec): string;
|
|
13
|
+
/** Args for `task … --taskfile <path>` (optional `--` + public CLI flags). */
|
|
14
|
+
export declare function checkGateSpawnArgs(spec: CheckGateSpec, taskfilePath: string): string[];
|
|
15
|
+
export declare const FRAMEWORK_CHECK_GATES: readonly CheckGateSpec[];
|
|
16
|
+
export declare const CONSUMER_CHECK_GATES: readonly CheckGateSpec[];
|
|
17
|
+
export declare function gatesForCheckTarget(target: string): readonly CheckGateSpec[];
|
|
18
|
+
//# sourceMappingURL=gate-lists.d.ts.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/** Gate execution order mirrors Taskfile.yml check targets (#1713 dogfood). */
|
|
2
|
+
export function checkGateId(spec) {
|
|
3
|
+
return typeof spec === "string" ? spec : spec.task;
|
|
4
|
+
}
|
|
5
|
+
/** Args for `task … --taskfile <path>` (optional `--` + public CLI flags). */
|
|
6
|
+
export function checkGateSpawnArgs(spec, taskfilePath) {
|
|
7
|
+
const task = checkGateId(spec);
|
|
8
|
+
const extra = typeof spec === "string" ? undefined : spec.args;
|
|
9
|
+
if (extra !== undefined && extra.length > 0) {
|
|
10
|
+
return [task, "--taskfile", taskfilePath, "--", ...extra];
|
|
11
|
+
}
|
|
12
|
+
return [task, "--taskfile", taskfilePath];
|
|
13
|
+
}
|
|
14
|
+
export const FRAMEWORK_CHECK_GATES = [
|
|
15
|
+
"ts:check-lane",
|
|
16
|
+
"toolchain:check",
|
|
17
|
+
"verify:stubs",
|
|
18
|
+
"verify:links",
|
|
19
|
+
"verify:rule-ownership",
|
|
20
|
+
"verify:biome-config",
|
|
21
|
+
"verify:content-manifest",
|
|
22
|
+
"verify:skill-external-fetch-gate",
|
|
23
|
+
"verify:contract-drift",
|
|
24
|
+
"verify:cursor-tier1",
|
|
25
|
+
"verify:go-freeze",
|
|
26
|
+
"verify:bridge-drift",
|
|
27
|
+
"verify:branch",
|
|
28
|
+
"verify:encoding",
|
|
29
|
+
"verify:forward-coverage",
|
|
30
|
+
"verify:vbrief-conformance",
|
|
31
|
+
"verify:destructive-gh-verbs",
|
|
32
|
+
"verify:scm-boundary",
|
|
33
|
+
"verify:xbrief-drift",
|
|
34
|
+
"verify:no-task-runtime",
|
|
35
|
+
"verify:cache-fresh",
|
|
36
|
+
"verify:pack-drift",
|
|
37
|
+
// Public surface for Taskfile verify-wip-cap-framework-self-check (#1124 / #2791)
|
|
38
|
+
{ task: "verify:wip-cap", args: ["--allow-over-cap"] },
|
|
39
|
+
"verify:orphan-active",
|
|
40
|
+
"verify:agents-md-budget",
|
|
41
|
+
// Public surfaces for internal eval-relocation framework shims (#2791)
|
|
42
|
+
{ task: "verify:eval-health-relocation", args: ["--base-ref", "origin/master"] },
|
|
43
|
+
{ task: "verify:eval-triggers-relocation", args: ["--base-ref", "origin/master"] },
|
|
44
|
+
"vbrief:validate",
|
|
45
|
+
"codebase:validate-structure",
|
|
46
|
+
"verify:codebase-map-fresh",
|
|
47
|
+
"verify-strategy-output",
|
|
48
|
+
];
|
|
49
|
+
export const CONSUMER_CHECK_GATES = [
|
|
50
|
+
"doctor",
|
|
51
|
+
"toolchain:check-consumer",
|
|
52
|
+
"verify:branch",
|
|
53
|
+
"verify:cache-fresh",
|
|
54
|
+
"verify:wip-cap",
|
|
55
|
+
"verify:orphan-active",
|
|
56
|
+
"vbrief:validate",
|
|
57
|
+
"verify-strategy-output",
|
|
58
|
+
];
|
|
59
|
+
export function gatesForCheckTarget(target) {
|
|
60
|
+
if (target === "check:framework-source") {
|
|
61
|
+
return FRAMEWORK_CHECK_GATES;
|
|
62
|
+
}
|
|
63
|
+
if (target === "check:consumer") {
|
|
64
|
+
return CONSUMER_CHECK_GATES;
|
|
65
|
+
}
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=gate-lists.js.map
|
package/dist/check/index.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { dispatchCachedTaskCheck } from "./cached-orchestrator.js";
|
|
2
|
+
export { type CheckGateSpec, CONSUMER_CHECK_GATES, checkGateId, checkGateSpawnArgs, FRAMEWORK_CHECK_GATES, gatesForCheckTarget, } from "./gate-lists.js";
|
|
3
|
+
export type { CheckOrchestratorOptions, CheckOrchestratorSeams } from "./orchestrator.js";
|
|
2
4
|
export { dispatchTaskCheck, isFrameworkRepoRoot, isFrameworkSourceContext, resolveCheckTarget, } from "./orchestrator.js";
|
|
5
|
+
export { detectTestRunner, type RunnerDetectResult, runnerDetectionTable, type TestRunnerKind, } from "./runner-detect.js";
|
|
3
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/check/index.js
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
+
export { dispatchCachedTaskCheck } from "./cached-orchestrator.js";
|
|
2
|
+
export { CONSUMER_CHECK_GATES, checkGateId, checkGateSpawnArgs, FRAMEWORK_CHECK_GATES, gatesForCheckTarget, } from "./gate-lists.js";
|
|
1
3
|
export { dispatchTaskCheck, isFrameworkRepoRoot, isFrameworkSourceContext, resolveCheckTarget, } from "./orchestrator.js";
|
|
4
|
+
export { detectTestRunner, runnerDetectionTable, } from "./runner-detect.js";
|
|
2
5
|
//# sourceMappingURL=index.js.map
|
|
@@ -11,51 +11,9 @@
|
|
|
11
11
|
* 1 -- one or more gates failed
|
|
12
12
|
* 2 -- config error (missing args, task spawn error, etc.)
|
|
13
13
|
*/
|
|
14
|
-
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
readonly taskBin?: string;
|
|
18
|
-
/** Override the spawnSync implementation for unit testing. */
|
|
19
|
-
readonly spawnFn?: (cmd: string, args: string[], opts: {
|
|
20
|
-
cwd: string;
|
|
21
|
-
stdio: string;
|
|
22
|
-
env?: NodeJS.ProcessEnv;
|
|
23
|
-
timeoutMs?: number;
|
|
24
|
-
}) => {
|
|
25
|
-
status: number | null;
|
|
26
|
-
signal?: NodeJS.Signals | null;
|
|
27
|
-
error?: Error;
|
|
28
|
-
};
|
|
29
|
-
/** Child-process environment (default: process.env). */
|
|
30
|
-
readonly env?: NodeJS.ProcessEnv;
|
|
31
|
-
/** Wall-clock spawn timeout in milliseconds (default: none). */
|
|
32
|
-
readonly timeoutMs?: number;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* True when `path` is the directive framework source checkout root (not a
|
|
36
|
-
* vendored `.deft/core` content deposit). Used to distinguish a maintainer
|
|
37
|
-
* running `task check` from a subdirectory (#2220) from a consumer install.
|
|
38
|
-
*/
|
|
39
|
-
export declare function isFrameworkRepoRoot(path: string): boolean;
|
|
40
|
-
/**
|
|
41
|
-
* Return true when running in the framework's own source checkout (#1519).
|
|
42
|
-
*
|
|
43
|
-
* Mirrors `is_framework_source_context` from _project_context.py with one
|
|
44
|
-
* extension (#2220): when the Taskfile lives at the framework repo root,
|
|
45
|
-
* `task check` may be invoked from a subdirectory (`USER_WORKING_DIR` !=
|
|
46
|
-
* `TASKFILE_DIR`). Those invocations must still route to
|
|
47
|
-
* `check:framework-source` so the biome lane runs. We do NOT resolve
|
|
48
|
-
* symlinks on the framework root -- a consumer project may symlink
|
|
49
|
-
* `.deft/core` to a local framework checkout and should still run the
|
|
50
|
-
* consumer-safe gate (the deposit path lacks `packages/cli`).
|
|
51
|
-
*/
|
|
52
|
-
export declare function isFrameworkSourceContext(frameworkRoot: string, projectRoot: string): boolean;
|
|
53
|
-
/**
|
|
54
|
-
* Select the Taskfile target for the given context.
|
|
55
|
-
*
|
|
56
|
-
* Mirrors _project_context.py::dispatch_task_check target selection.
|
|
57
|
-
*/
|
|
58
|
-
export declare function resolveCheckTarget(frameworkRoot: string, projectRoot: string): string;
|
|
14
|
+
import { type CheckOrchestratorSeams } from "./context.js";
|
|
15
|
+
export type { CheckOrchestratorOptions, CheckOrchestratorSeams } from "./context.js";
|
|
16
|
+
export { isFrameworkRepoRoot, isFrameworkSourceContext, resolveCheckTarget } from "./context.js";
|
|
59
17
|
/**
|
|
60
18
|
* Dispatch to the context-appropriate `task check` aggregate target.
|
|
61
19
|
*
|
|
@@ -12,52 +12,10 @@
|
|
|
12
12
|
* 2 -- config error (missing args, task spawn error, etc.)
|
|
13
13
|
*/
|
|
14
14
|
import { spawnSync } from "node:child_process";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
* vendored `.deft/core` content deposit). Used to distinguish a maintainer
|
|
20
|
-
* running `task check` from a subdirectory (#2220) from a consumer install.
|
|
21
|
-
*/
|
|
22
|
-
export function isFrameworkRepoRoot(path) {
|
|
23
|
-
const root = resolve(path);
|
|
24
|
-
return (existsSync(join(root, "packages", "cli", "package.json")) &&
|
|
25
|
-
existsSync(join(root, "biome.json")) &&
|
|
26
|
-
existsSync(join(root, "Taskfile.yml")));
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Return true when running in the framework's own source checkout (#1519).
|
|
30
|
-
*
|
|
31
|
-
* Mirrors `is_framework_source_context` from _project_context.py with one
|
|
32
|
-
* extension (#2220): when the Taskfile lives at the framework repo root,
|
|
33
|
-
* `task check` may be invoked from a subdirectory (`USER_WORKING_DIR` !=
|
|
34
|
-
* `TASKFILE_DIR`). Those invocations must still route to
|
|
35
|
-
* `check:framework-source` so the biome lane runs. We do NOT resolve
|
|
36
|
-
* symlinks on the framework root -- a consumer project may symlink
|
|
37
|
-
* `.deft/core` to a local framework checkout and should still run the
|
|
38
|
-
* consumer-safe gate (the deposit path lacks `packages/cli`).
|
|
39
|
-
*/
|
|
40
|
-
export function isFrameworkSourceContext(frameworkRoot, projectRoot) {
|
|
41
|
-
const fw = resolve(frameworkRoot);
|
|
42
|
-
const pr = resolve(projectRoot);
|
|
43
|
-
if (fw === pr) {
|
|
44
|
-
return true;
|
|
45
|
-
}
|
|
46
|
-
if (!isFrameworkRepoRoot(fw)) {
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
return pr.startsWith(`${fw}${sep}`);
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Select the Taskfile target for the given context.
|
|
53
|
-
*
|
|
54
|
-
* Mirrors _project_context.py::dispatch_task_check target selection.
|
|
55
|
-
*/
|
|
56
|
-
export function resolveCheckTarget(frameworkRoot, projectRoot) {
|
|
57
|
-
return isFrameworkSourceContext(frameworkRoot, projectRoot)
|
|
58
|
-
? "check:framework-source"
|
|
59
|
-
: "check:consumer";
|
|
60
|
-
}
|
|
15
|
+
import { join, resolve } from "node:path";
|
|
16
|
+
import { dispatchCachedTaskCheck } from "./cached-orchestrator.js";
|
|
17
|
+
import { resolveCheckTarget } from "./context.js";
|
|
18
|
+
export { isFrameworkRepoRoot, isFrameworkSourceContext, resolveCheckTarget } from "./context.js";
|
|
61
19
|
/**
|
|
62
20
|
* Dispatch to the context-appropriate `task check` aggregate target.
|
|
63
21
|
*
|
|
@@ -69,6 +27,10 @@ export function resolveCheckTarget(frameworkRoot, projectRoot) {
|
|
|
69
27
|
export function dispatchTaskCheck(frameworkRoot, projectRoot, seams = {}) {
|
|
70
28
|
const resolvedFramework = resolve(frameworkRoot);
|
|
71
29
|
const resolvedProject = resolve(projectRoot);
|
|
30
|
+
const useTaskCache = seams.useTaskCache !== false && !seams.noCache;
|
|
31
|
+
if (useTaskCache) {
|
|
32
|
+
return dispatchCachedTaskCheck(resolvedFramework, resolvedProject, seams);
|
|
33
|
+
}
|
|
72
34
|
const taskfilePath = join(resolvedFramework, "Taskfile.yml");
|
|
73
35
|
const taskBin = seams.taskBin ?? "task";
|
|
74
36
|
const target = resolveCheckTarget(resolvedFramework, resolvedProject);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type TestRunnerKind = "vitest" | "jest" | "go" | "pytest" | "none";
|
|
2
|
+
export interface RunnerDetectResult {
|
|
3
|
+
readonly kind: TestRunnerKind;
|
|
4
|
+
readonly affectedArgs: readonly string[];
|
|
5
|
+
readonly source: "config" | "heuristic" | "fallback";
|
|
6
|
+
readonly message?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface RunnerDetectOptions {
|
|
9
|
+
readonly projectRoot: string;
|
|
10
|
+
readonly override?: TestRunnerKind;
|
|
11
|
+
}
|
|
12
|
+
/** Auto-detect consumer test runner with explicit override (#1713). */
|
|
13
|
+
export declare function detectTestRunner(options: RunnerDetectOptions): RunnerDetectResult;
|
|
14
|
+
/** Human-readable detection table rows for docs. */
|
|
15
|
+
export declare function runnerDetectionTable(): ReadonlyArray<{
|
|
16
|
+
runner: TestRunnerKind;
|
|
17
|
+
detection: string;
|
|
18
|
+
affectedConvention: string;
|
|
19
|
+
}>;
|
|
20
|
+
//# sourceMappingURL=runner-detect.d.ts.map
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { projectDefinitionPath } from "../policy/index.js";
|
|
4
|
+
const RUNNER_AFFECTED = {
|
|
5
|
+
vitest: ["--changed"],
|
|
6
|
+
jest: ["--onlyChanged"],
|
|
7
|
+
go: [],
|
|
8
|
+
pytest: ["--testmon"],
|
|
9
|
+
};
|
|
10
|
+
function affectedArgsFor(kind) {
|
|
11
|
+
if (kind === "none") {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
return RUNNER_AFFECTED[kind];
|
|
15
|
+
}
|
|
16
|
+
function readJson(path) {
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function detectFromPolicy(projectRoot) {
|
|
25
|
+
try {
|
|
26
|
+
const planPath = projectDefinitionPath(projectRoot);
|
|
27
|
+
const plan = readJson(planPath);
|
|
28
|
+
const raw = plan?.plan?.policy?.testRunner;
|
|
29
|
+
if (raw === "vitest" || raw === "jest" || raw === "go" || raw === "pytest" || raw === "none") {
|
|
30
|
+
return raw;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
function detectFromHeuristics(projectRoot) {
|
|
39
|
+
const root = resolve(projectRoot);
|
|
40
|
+
if (existsSync(join(root, "go.mod"))) {
|
|
41
|
+
return "go";
|
|
42
|
+
}
|
|
43
|
+
const pkgPath = join(root, "package.json");
|
|
44
|
+
if (existsSync(pkgPath)) {
|
|
45
|
+
const pkg = readJson(pkgPath);
|
|
46
|
+
const deps = { ...(pkg?.dependencies ?? {}), ...(pkg?.devDependencies ?? {}) };
|
|
47
|
+
if ("vitest" in deps) {
|
|
48
|
+
return "vitest";
|
|
49
|
+
}
|
|
50
|
+
if ("jest" in deps || "@jest/core" in deps) {
|
|
51
|
+
return "jest";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (existsSync(join(root, "pytest.ini")) ||
|
|
55
|
+
existsSync(join(root, "pyproject.toml")) ||
|
|
56
|
+
existsSync(join(root, "requirements.txt"))) {
|
|
57
|
+
return "pytest";
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
/** Auto-detect consumer test runner with explicit override (#1713). */
|
|
62
|
+
export function detectTestRunner(options) {
|
|
63
|
+
if (options.override !== undefined) {
|
|
64
|
+
if (options.override === "none") {
|
|
65
|
+
return {
|
|
66
|
+
kind: "none",
|
|
67
|
+
affectedArgs: [],
|
|
68
|
+
source: "config",
|
|
69
|
+
message: "Runner override set to full-suite-only.",
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
kind: options.override,
|
|
74
|
+
affectedArgs: affectedArgsFor(options.override),
|
|
75
|
+
source: "config",
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const fromPolicy = detectFromPolicy(options.projectRoot);
|
|
79
|
+
if (fromPolicy !== null) {
|
|
80
|
+
return {
|
|
81
|
+
kind: fromPolicy,
|
|
82
|
+
affectedArgs: affectedArgsFor(fromPolicy),
|
|
83
|
+
source: "config",
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const fromHeuristics = detectFromHeuristics(options.projectRoot);
|
|
87
|
+
if (fromHeuristics !== null) {
|
|
88
|
+
return {
|
|
89
|
+
kind: fromHeuristics,
|
|
90
|
+
affectedArgs: affectedArgsFor(fromHeuristics),
|
|
91
|
+
source: "heuristic",
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
kind: "none",
|
|
96
|
+
affectedArgs: [],
|
|
97
|
+
source: "fallback",
|
|
98
|
+
message: "No supported test runner detected — merge gate uses the full suite.",
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/** Human-readable detection table rows for docs. */
|
|
102
|
+
export function runnerDetectionTable() {
|
|
103
|
+
return [
|
|
104
|
+
{
|
|
105
|
+
runner: "vitest",
|
|
106
|
+
detection: "package.json lists vitest, or plan.policy.testRunner = vitest",
|
|
107
|
+
affectedConvention: "vitest --changed",
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
runner: "jest",
|
|
111
|
+
detection: "package.json lists jest / @jest/core, or plan.policy.testRunner = jest",
|
|
112
|
+
affectedConvention: "jest --onlyChanged",
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
runner: "go",
|
|
116
|
+
detection: "go.mod present, or plan.policy.testRunner = go",
|
|
117
|
+
affectedConvention: "go test (native package cache)",
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
runner: "pytest",
|
|
121
|
+
detection: "pytest.ini / pyproject.toml / requirements.txt, or plan.policy.testRunner = pytest",
|
|
122
|
+
affectedConvention: "pytest --testmon",
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
runner: "none",
|
|
126
|
+
detection: "No match after config + heuristics",
|
|
127
|
+
affectedConvention: "Full suite at merge gate",
|
|
128
|
+
},
|
|
129
|
+
];
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=runner-detect.js.map
|
package/dist/doctor/checks.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { CANONICAL_GITIGNORE_BASELINE } from "../init-deposit/gitignore.js";
|
|
3
|
-
import { detectLegacyLayout, legacyLayoutSignpostLine, } from "../init-deposit/legacy-detect.js";
|
|
3
|
+
import { detectDualLayout, detectLegacyLayout, dualLayoutSignpostLine, legacyLayoutSignpostLine, } from "../init-deposit/legacy-detect.js";
|
|
4
4
|
import { detectCanonicalVendoredManifest, isNpmManaged, NPM_MANAGED_SENTINEL_KEY, NPM_MANAGED_SENTINEL_VALUE, } from "../init-deposit/migrate.js";
|
|
5
5
|
import { resolveLifecycleRoot } from "../layout/resolve.js";
|
|
6
6
|
import { findSkillPathsInText } from "../text/redos-safe.js";
|
|
@@ -300,6 +300,21 @@ export function checkLegacyLayout(projectRoot, seams = {}) {
|
|
|
300
300
|
...(seams.isFile ? { isFile: seams.isFile } : {}),
|
|
301
301
|
...(seams.isDir ? { isDir: seams.isDir } : {}),
|
|
302
302
|
};
|
|
303
|
+
const dualLayout = detectDualLayout(projectRoot, legacySeams);
|
|
304
|
+
if (dualLayout !== null) {
|
|
305
|
+
return {
|
|
306
|
+
name: "legacy-layout",
|
|
307
|
+
status: "fail",
|
|
308
|
+
detail: dualLayoutSignpostLine(dualLayout),
|
|
309
|
+
data: {
|
|
310
|
+
legacy_layout: true,
|
|
311
|
+
legacy_layout_kind: dualLayout.kind,
|
|
312
|
+
evidence: [...dualLayout.evidence],
|
|
313
|
+
upgrading_doc_url: UPGRADING_DOC_URL,
|
|
314
|
+
go_bridge_releases_url: GO_BRIDGE_RELEASES_URL,
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
}
|
|
303
318
|
const detection = detectLegacyLayout(projectRoot, legacySeams);
|
|
304
319
|
if (!detection.legacy) {
|
|
305
320
|
return {
|
|
@@ -10,6 +10,8 @@ export declare const TASKFILE_INCLUDE_SNIPPET = "version: '3'\n\nincludes:\n de
|
|
|
10
10
|
export declare const DOCTOR_ALLOWED_FLAGS: readonly ["--session", "--fix", "--repair", "--repair-taskfile", "--json", "--quiet", "--full", "--network", "--project-root", "-h", "--help"];
|
|
11
11
|
/** npm consumer deposit after #2022 Phase 3 -- Python scripts/ tree is intentionally absent. */
|
|
12
12
|
export declare const NPM_PACKAGE_NAME = "@deftai/directive";
|
|
13
|
+
export declare const PUBLIC_NPM_REGISTRY = "https://registry.npmjs.org/";
|
|
14
|
+
export declare const NPM_REGISTRY_MIRROR_DOC_URL = "https://github.com/deftai/directive/blob/master/content/UPGRADING.md#corporate-or-mirrored-npm-registry";
|
|
13
15
|
export declare const NETWORK_DISCLOSURE_LINE: string;
|
|
14
16
|
export declare const PAYLOAD_STALENESS_OFFLINE_SKIP_MESSAGE: string;
|
|
15
17
|
export declare const EXPECTED_FRAMEWORK_DIRS: readonly ["tasks", "scripts", "vbrief"];
|
package/dist/doctor/constants.js
CHANGED
|
@@ -28,12 +28,16 @@ export const DOCTOR_ALLOWED_FLAGS = [
|
|
|
28
28
|
];
|
|
29
29
|
/** npm consumer deposit after #2022 Phase 3 -- Python scripts/ tree is intentionally absent. */
|
|
30
30
|
export const NPM_PACKAGE_NAME = "@deftai/directive";
|
|
31
|
+
export const PUBLIC_NPM_REGISTRY = "https://registry.npmjs.org/";
|
|
32
|
+
export const NPM_REGISTRY_MIRROR_DOC_URL = `${UPGRADING_DOC_URL}#corporate-or-mirrored-npm-registry`;
|
|
31
33
|
// #2182: payload-staleness is the only doctor check that can reach a network
|
|
32
34
|
// endpoint (git ls-remote verifies the pinned ref and `npm view` compares a
|
|
33
|
-
// release-tag install with the latest stable package).
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
35
|
+
// release-tag install with the latest stable package). The #2808 baseline
|
|
36
|
+
// registry-routing check uses only offline `npm config get` reads.
|
|
37
|
+
// Payload-staleness is OFF by default (offline tier) and requires the explicit
|
|
38
|
+
// `--network` flag; this line discloses exactly which tool + registry class it
|
|
39
|
+
// may contact BEFORE the check runs, and the skip line tells an offline run how
|
|
40
|
+
// to opt in.
|
|
37
41
|
export const NETWORK_DISCLOSURE_LINE = "[deft doctor] --network: this run may contact your git remote (framework " +
|
|
38
42
|
"repo host) and the npm registry (registry.npmjs.org) to " +
|
|
39
43
|
`look up the latest ${NPM_PACKAGE_NAME} version.`;
|
package/dist/doctor/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export * from "./flags.js";
|
|
|
6
6
|
export * from "./json.js";
|
|
7
7
|
export * from "./main.js";
|
|
8
8
|
export * from "./manifest.js";
|
|
9
|
+
export * from "./npm-registry.js";
|
|
9
10
|
export * from "./paths.js";
|
|
10
11
|
export * from "./payload-staleness.js";
|
|
11
12
|
export * from "./release-availability.js";
|
package/dist/doctor/index.js
CHANGED
|
@@ -6,6 +6,7 @@ export * from "./flags.js";
|
|
|
6
6
|
export * from "./json.js";
|
|
7
7
|
export * from "./main.js";
|
|
8
8
|
export * from "./manifest.js";
|
|
9
|
+
export * from "./npm-registry.js";
|
|
9
10
|
export * from "./paths.js";
|
|
10
11
|
export * from "./payload-staleness.js";
|
|
11
12
|
export * from "./release-availability.js";
|
package/dist/doctor/main.js
CHANGED
|
@@ -14,6 +14,7 @@ import { decideThrottle, formatIsoZ, readState, renderDoctorStatusLine, writeSta
|
|
|
14
14
|
import { formatAllowedFlagsHint, formatUnknownFlagsError, parseDoctorFlags } from "./flags.js";
|
|
15
15
|
import { pythonJsonDump } from "./json.js";
|
|
16
16
|
import { parseInstallRootFromAgentsMd } from "./manifest.js";
|
|
17
|
+
import { runNpmRegistryMirrorCheck } from "./npm-registry.js";
|
|
17
18
|
import { createPlainSink } from "./output.js";
|
|
18
19
|
import { readTextSafe, resolveDefaultFrameworkRoot, resolvePath, resolveVersion, runningInsideDeftRepo, } from "./paths.js";
|
|
19
20
|
import { runPayloadStalenessCheck } from "./payload-staleness.js";
|
|
@@ -90,7 +91,7 @@ export function cmdDoctor(args, seams = {}) {
|
|
|
90
91
|
}
|
|
91
92
|
const signpostWarnings = throttleFindings.filter((f) => f.severity === "warning").length;
|
|
92
93
|
if (signpostWarnings > 0 && !jsonMode) {
|
|
93
|
-
throttleSink.finalWarn(`Signpost advisory: ${signpostWarnings} local
|
|
94
|
+
throttleSink.finalWarn(`Signpost advisory: ${signpostWarnings} local configuration / layout note(s) above (throttle-skipped full probe).`);
|
|
94
95
|
}
|
|
95
96
|
return decision.dirty ? 1 : 0;
|
|
96
97
|
}
|
|
@@ -165,12 +166,20 @@ export function cmdDoctor(args, seams = {}) {
|
|
|
165
166
|
}
|
|
166
167
|
sink.info("Checking agent-host hook registration...");
|
|
167
168
|
runAgentHooksHealthCheck(projectRoot, consumerContext, sink, addFinding, seams);
|
|
169
|
+
if (consumerContext) {
|
|
170
|
+
if (!jsonMode) {
|
|
171
|
+
sink.blank();
|
|
172
|
+
}
|
|
173
|
+
sink.info("Checking npm registry routing...");
|
|
174
|
+
runNpmRegistryMirrorCheck(projectRoot, sink, addFinding, seams);
|
|
175
|
+
}
|
|
168
176
|
if (!jsonMode) {
|
|
169
177
|
sink.blank();
|
|
170
178
|
}
|
|
171
|
-
// #2182: payload-staleness is the only doctor check that can reach a
|
|
172
|
-
//
|
|
173
|
-
//
|
|
179
|
+
// #2182: payload-staleness is the only doctor check that can reach a network
|
|
180
|
+
// endpoint (git verifies the pin; npm compares stable release availability).
|
|
181
|
+
// The baseline #2808 registry-routing diagnostic above is an offline
|
|
182
|
+
// `npm config get` read. Payload-staleness stays in the OFFLINE
|
|
174
183
|
// tier (skipped) unless the operator explicitly opts into the NETWORK tier
|
|
175
184
|
// via `--network`, and the tool + registry class is disclosed BEFORE the
|
|
176
185
|
// check runs -- never silently, never as a side effect of a read-only
|