@deftai/directive-core 0.88.0 → 0.90.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authz/actions.d.ts +55 -0
- package/dist/authz/actions.js +125 -0
- package/dist/authz/classify.d.ts +23 -0
- package/dist/authz/classify.js +217 -0
- package/dist/authz/closed-verb.d.ts +42 -0
- package/dist/authz/closed-verb.js +279 -0
- package/dist/authz/evaluate.d.ts +41 -0
- package/dist/authz/evaluate.js +298 -0
- package/dist/authz/index.d.ts +15 -0
- package/dist/authz/index.js +15 -0
- package/dist/authz/origin.d.ts +28 -0
- package/dist/authz/origin.js +64 -0
- package/dist/authz/paths.d.ts +6 -0
- package/dist/authz/paths.js +19 -0
- package/dist/authz/store.d.ts +40 -0
- package/dist/authz/store.js +317 -0
- package/dist/authz/templates.d.ts +139 -0
- package/dist/authz/templates.js +241 -0
- package/dist/authz/types.d.ts +111 -0
- package/dist/authz/types.js +41 -0
- package/dist/authz/verb-classification.d.ts +44 -0
- package/dist/authz/verb-classification.js +237 -0
- package/dist/branch/evaluate.js +6 -1
- package/dist/cache/fetch.js +10 -5
- package/dist/cache/io.d.ts +9 -2
- package/dist/cache/io.js +30 -10
- package/dist/cache/task-cache/store.js +11 -7
- package/dist/capacity/backfill.js +10 -4
- package/dist/category-b-namespace/index.js +10 -4
- package/dist/codebase/default-extractor.js +3 -0
- package/dist/codebase/map.js +11 -4
- package/dist/doctor/constants.d.ts +1 -1
- package/dist/doctor/constants.js +2 -0
- package/dist/doctor/doctor-state.js +28 -4
- package/dist/doctor/flags.js +21 -1
- package/dist/doctor/index.d.ts +1 -0
- package/dist/doctor/index.js +1 -0
- package/dist/doctor/main.d.ts +10 -0
- package/dist/doctor/main.js +182 -0
- package/dist/doctor/openclaw-skills.d.ts +109 -0
- package/dist/doctor/openclaw-skills.js +463 -0
- package/dist/doctor/types.d.ts +22 -0
- package/dist/escalation/actions.d.ts +63 -0
- package/dist/escalation/actions.js +137 -0
- package/dist/escalation/index.d.ts +8 -0
- package/dist/escalation/index.js +8 -0
- package/dist/escalation/paths.d.ts +3 -0
- package/dist/escalation/paths.js +10 -0
- package/dist/escalation/store.d.ts +17 -0
- package/dist/escalation/store.js +172 -0
- package/dist/escalation/types.d.ts +73 -0
- package/dist/escalation/types.js +43 -0
- package/dist/eval/crud-telemetry.js +30 -10
- package/dist/eval/health.js +22 -7
- package/dist/eval/readback.js +11 -10
- package/dist/eval/run.js +32 -16
- package/dist/events/attribution-enrichment.js +10 -4
- package/dist/finish-loop/directive-finish-loop.d.ts +37 -0
- package/dist/finish-loop/directive-finish-loop.js +239 -0
- package/dist/finish-loop/grant-gate.d.ts +31 -0
- package/dist/finish-loop/grant-gate.js +169 -0
- package/dist/finish-loop/index.d.ts +11 -0
- package/dist/finish-loop/index.js +11 -0
- package/dist/finish-loop/main.d.ts +35 -0
- package/dist/finish-loop/main.js +365 -0
- package/dist/finish-loop/pr-finish-loop.d.ts +34 -0
- package/dist/finish-loop/pr-finish-loop.js +217 -0
- package/dist/finish-loop/progress.d.ts +17 -0
- package/dist/finish-loop/progress.js +45 -0
- package/dist/finish-loop/queue.d.ts +16 -0
- package/dist/finish-loop/queue.js +65 -0
- package/dist/finish-loop/types.d.ts +52 -0
- package/dist/finish-loop/types.js +10 -0
- package/dist/fs/contained-write.d.ts +101 -0
- package/dist/fs/contained-write.js +281 -0
- package/dist/hooks/classify/classify.d.ts +10 -0
- package/dist/hooks/classify/classify.js +37 -0
- package/dist/hooks/classify/index.d.ts +14 -0
- package/dist/hooks/classify/index.js +13 -0
- package/dist/hooks/classify/paths.d.ts +22 -0
- package/dist/hooks/classify/paths.js +72 -0
- package/dist/hooks/classify/payload.d.ts +16 -0
- package/dist/hooks/classify/payload.js +45 -0
- package/dist/hooks/classify/stdin.d.ts +12 -0
- package/dist/hooks/classify/stdin.js +63 -0
- package/dist/hooks/classify/tool-name.d.ts +18 -0
- package/dist/hooks/classify/tool-name.js +85 -0
- package/dist/hooks/classify/types.d.ts +41 -0
- package/dist/hooks/classify/types.js +7 -0
- package/dist/hooks/dispatcher.d.ts +21 -18
- package/dist/hooks/dispatcher.js +232 -168
- package/dist/hooks/fixtures/cases.d.ts +44 -0
- package/dist/hooks/fixtures/cases.js +595 -0
- package/dist/hooks/fixtures/index.d.ts +2 -0
- package/dist/hooks/fixtures/index.js +2 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.js +2 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +6 -0
- package/dist/init-deposit/agent-hooks.js +27 -8
- package/dist/init-deposit/gitignore.js +11 -3
- package/dist/init-deposit/headless-manifest.js +12 -4
- package/dist/init-deposit/migrate.d.ts +1 -1
- package/dist/init-deposit/migrate.js +13 -3
- package/dist/init-deposit/prettierignore.js +10 -3
- package/dist/init-deposit/scaffold.js +35 -26
- package/dist/init-deposit/xbrief-projections.js +11 -4
- package/dist/intake/candidates-log.js +46 -35
- package/dist/intake/github-body-cli.d.ts +6 -0
- package/dist/intake/github-body-cli.js +17 -0
- package/dist/intake/github-body.d.ts +46 -3
- package/dist/intake/github-body.js +191 -20
- package/dist/intake/issue-emit.d.ts +1 -0
- package/dist/intake/issue-emit.js +41 -23
- package/dist/lifecycle/event-detect.js +12 -4
- package/dist/lifecycle/events.js +31 -20
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.js +1 -0
- package/dist/lifecycle/lifecycle-hygiene.js +9 -3
- package/dist/lifecycle/stats.d.ts +53 -0
- package/dist/lifecycle/stats.js +286 -0
- package/dist/packs/pack-render.js +19 -6
- package/dist/plan-sequence/store.js +11 -4
- package/dist/policy/hotfix-criteria.d.ts +79 -0
- package/dist/policy/hotfix-criteria.js +197 -0
- package/dist/policy/index.d.ts +4 -0
- package/dist/policy/index.js +31 -1
- package/dist/policy/intent-ceiling.d.ts +79 -0
- package/dist/policy/intent-ceiling.js +181 -0
- package/dist/policy/no-deft-directive.js +10 -3
- package/dist/policy/org-force-on-migration.js +9 -5
- package/dist/policy/require-human-merge.d.ts +75 -0
- package/dist/policy/require-human-merge.js +324 -0
- package/dist/policy/resolve.js +17 -6
- package/dist/policy/runtime-authority.d.ts +15 -2
- package/dist/policy/runtime-authority.js +23 -3
- package/dist/policy/write-fence.d.ts +78 -0
- package/dist/policy/write-fence.js +164 -0
- package/dist/pr-wait-mergeable/cascade.d.ts +10 -0
- package/dist/pr-wait-mergeable/cascade.js +28 -0
- package/dist/preflight/evaluate.js +10 -0
- package/dist/product-signal/consent.js +21 -5
- package/dist/product-signal/submit.js +22 -12
- package/dist/release/build-dist-runner.js +5 -2
- package/dist/release/build-dist.d.ts +19 -1
- package/dist/release/build-dist.js +50 -2
- package/dist/release/native-steps.js +7 -2
- package/dist/release/spawn.js +13 -0
- package/dist/release-e2e/git-ops.d.ts +7 -0
- package/dist/release-e2e/git-ops.js +35 -2
- package/dist/release-publish/pipeline.d.ts +13 -0
- package/dist/release-publish/pipeline.js +46 -1
- package/dist/scope/audit-log.js +19 -24
- package/dist/scope/decompose.js +10 -5
- package/dist/scope/decomposed-refs.js +18 -3
- package/dist/scope/demote.js +9 -2
- package/dist/scope/undo.js +9 -2
- package/dist/session/index.d.ts +2 -0
- package/dist/session/index.js +2 -0
- package/dist/session/process-cost-constants.d.ts +9 -0
- package/dist/session/process-cost-constants.js +11 -0
- package/dist/session/process-cost.d.ts +53 -0
- package/dist/session/process-cost.js +82 -0
- package/dist/session/release-availability.js +26 -6
- package/dist/session/ritual-sentinel.d.ts +5 -0
- package/dist/session/ritual-sentinel.js +31 -13
- package/dist/session/session-ready.d.ts +67 -0
- package/dist/session/session-ready.js +264 -0
- package/dist/session/session-start.d.ts +56 -1
- package/dist/session/session-start.js +384 -23
- package/dist/session/verify-session-ritual.d.ts +8 -0
- package/dist/session/verify-session-ritual.js +95 -35
- package/dist/staleness-tickler/state.js +26 -6
- package/dist/swarm/launch.js +13 -3
- package/dist/swarm/routing.js +9 -3
- package/dist/task-surface/index.js +24 -9
- package/dist/tool-events/classify.d.ts +20 -0
- package/dist/tool-events/classify.js +634 -0
- package/dist/tool-events/index.d.ts +10 -0
- package/dist/tool-events/index.js +10 -0
- package/dist/tool-events/summarize.d.ts +34 -0
- package/dist/tool-events/summarize.js +93 -0
- package/dist/tool-events/types.d.ts +52 -0
- package/dist/tool-events/types.js +13 -0
- package/dist/triage/bootstrap/gitignore.js +53 -10
- package/dist/triage/cache-path.js +10 -3
- package/dist/triage/welcome/summary.js +11 -4
- package/dist/triage/welcome/writers.js +45 -16
- package/dist/validate-content/validate-links.js +5 -0
- package/dist/value/readback.js +11 -6
- package/dist/vbrief-activate/activate.js +12 -4
- package/dist/vbrief-build/project-definition-io.js +14 -6
- package/dist/verify-source/contained-writes.d.ts +59 -0
- package/dist/verify-source/contained-writes.js +272 -0
- package/dist/verify-source/index.d.ts +1 -0
- package/dist/verify-source/index.js +1 -0
- package/dist/verify-source/openclaw-tier1.js +14 -1
- package/dist/verify-source/verify-stubs.js +3 -0
- package/dist/xbrief-migrate/migrate-project.js +26 -12
- package/dist/xbrief-migrate/transforms.d.ts +4 -2
- package/dist/xbrief-migrate/transforms.js +37 -14
- package/package.json +19 -3
package/dist/branch/evaluate.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { recordBypassSignal, recordGateCatch } from "../events/attribution-ledger.js";
|
|
2
2
|
import { disclosureLine } from "../policy/disclosure.js";
|
|
3
3
|
import { policyColonInvocation } from "../policy/policy-invocation.js";
|
|
4
|
+
import { humanMergeBranchNote, resolveHumanMergePolicy } from "../policy/require-human-merge.js";
|
|
4
5
|
import { ENV_BYPASS, resolvePolicy } from "../policy/resolve.js";
|
|
5
6
|
import { currentBranch, GitNotFoundError } from "./git.js";
|
|
6
7
|
export const DEFAULT_BRANCHES = new Set(["master", "main"]);
|
|
@@ -93,9 +94,13 @@ export function evaluate(projectRoot, options = {}) {
|
|
|
93
94
|
};
|
|
94
95
|
}
|
|
95
96
|
if (!isDefaultBranch(branch, defaultBranches)) {
|
|
97
|
+
// Surface (2) human-merge gate: advisory note on feature branches (#1193).
|
|
98
|
+
const hm = resolveHumanMergePolicy(projectRoot);
|
|
99
|
+
const hmNote = humanMergeBranchNote(hm);
|
|
100
|
+
const base = `✓ deft branch-protection: feature branch '${branch}' -- proceeding.`;
|
|
96
101
|
return {
|
|
97
102
|
exitCode: 0,
|
|
98
|
-
message:
|
|
103
|
+
message: hmNote !== null ? `${base}\n${hmNote}` : base,
|
|
99
104
|
};
|
|
100
105
|
}
|
|
101
106
|
const result = resolvePolicy(projectRoot);
|
package/dist/cache/fetch.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { existsSync, readdirSync, readFileSync
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { ContainedWriteError, containedWrite } from "../fs/contained-write.js";
|
|
4
4
|
import { GhRestError, InvalidRepoError, restIssueView, runGhApi, } from "../scm/gh-rest.js";
|
|
5
5
|
import { DEFAULT_BATCH_SIZE, DEFAULT_DELAY_MS } from "./constants.js";
|
|
6
6
|
import { CacheError, CacheFetchError } from "./errors.js";
|
|
@@ -622,8 +622,13 @@ function readSelfHealState(cacheRoot) {
|
|
|
622
622
|
}
|
|
623
623
|
function writeSelfHealState(projectRoot, cacheRoot, when) {
|
|
624
624
|
const path = join(resolve(cacheRoot), SELF_HEAL_STATE_FILENAME);
|
|
625
|
-
|
|
626
|
-
|
|
625
|
+
// #2980 wave C: product write sink routes through containedWrite.
|
|
626
|
+
containedWrite({
|
|
627
|
+
root: resolve(projectRoot),
|
|
628
|
+
target: path,
|
|
629
|
+
data: `${JSON.stringify({ last_reconcile_at: when.toISOString() })}\n`,
|
|
630
|
+
mode: "replace",
|
|
631
|
+
});
|
|
627
632
|
}
|
|
628
633
|
/** TTL-bounded closed-reconcile for session ritual / triage:welcome self-healing (#1886). */
|
|
629
634
|
export function maybeSelfHealCache(projectRoot, options = {}) {
|
|
@@ -679,7 +684,7 @@ export function maybeSelfHealCache(projectRoot, options = {}) {
|
|
|
679
684
|
writeSelfHealState(projectRoot, cacheRoot, now);
|
|
680
685
|
}
|
|
681
686
|
catch (err) {
|
|
682
|
-
if (err instanceof
|
|
687
|
+
if (err instanceof ContainedWriteError) {
|
|
683
688
|
return { skipped: true, skipReason: "containment-refused", drift, refresh: null };
|
|
684
689
|
}
|
|
685
690
|
throw err;
|
package/dist/cache/io.d.ts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { tmpdir } from "node:os";
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Write text via tempfile + rename (mirrors Python `_atomic_write_text`).
|
|
4
|
+
* #2951 Phase 2: temp payload write uses containedWrite under the parent dir.
|
|
5
|
+
*/
|
|
3
6
|
export declare function atomicWriteText(path: string, text: string): void;
|
|
4
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Append one JSON audit record (mirrors `_append_audit`).
|
|
9
|
+
* #2951 Phase 2: product write sink routes through containedWrite.
|
|
10
|
+
* Create cacheRoot first — containedWrite requires the containment root to exist.
|
|
11
|
+
*/
|
|
5
12
|
export declare function appendAudit(record: Record<string, unknown>, cacheRoot: string): void;
|
|
6
13
|
/** Touch mtime for LRU signal; failures swallowed. */
|
|
7
14
|
export declare function touchMtime(path: string): void;
|
package/dist/cache/io.js
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { mkdirSync, renameSync, rmSync, statSync, utimesSync } from "node:fs";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
|
-
import { dirname, join } from "node:path";
|
|
4
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
5
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
5
6
|
import { pythonJsonLine } from "./json.js";
|
|
6
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Write text via tempfile + rename (mirrors Python `_atomic_write_text`).
|
|
9
|
+
* #2951 Phase 2: temp payload write uses containedWrite under the parent dir.
|
|
10
|
+
*/
|
|
7
11
|
export function atomicWriteText(path, text) {
|
|
8
|
-
|
|
9
|
-
|
|
12
|
+
const dir = dirname(path);
|
|
13
|
+
mkdirSync(dir, { recursive: true });
|
|
14
|
+
const tmpName = `${basename(path)}.${randomBytes(4).toString("hex")}.tmp`;
|
|
15
|
+
const tmp = join(dir, tmpName);
|
|
10
16
|
try {
|
|
11
|
-
|
|
17
|
+
containedWrite({
|
|
18
|
+
root: resolve(dir),
|
|
19
|
+
target: tmpName,
|
|
20
|
+
data: text,
|
|
21
|
+
mode: "create",
|
|
22
|
+
});
|
|
12
23
|
renameSync(tmp, path);
|
|
13
24
|
}
|
|
14
25
|
catch (err) {
|
|
@@ -21,11 +32,20 @@ export function atomicWriteText(path, text) {
|
|
|
21
32
|
throw err;
|
|
22
33
|
}
|
|
23
34
|
}
|
|
24
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* Append one JSON audit record (mirrors `_append_audit`).
|
|
37
|
+
* #2951 Phase 2: product write sink routes through containedWrite.
|
|
38
|
+
* Create cacheRoot first — containedWrite requires the containment root to exist.
|
|
39
|
+
*/
|
|
25
40
|
export function appendAudit(record, cacheRoot) {
|
|
26
|
-
const
|
|
27
|
-
mkdirSync(
|
|
28
|
-
|
|
41
|
+
const root = resolve(cacheRoot);
|
|
42
|
+
mkdirSync(root, { recursive: true });
|
|
43
|
+
containedWrite({
|
|
44
|
+
root,
|
|
45
|
+
target: "quarantine-audit.jsonl",
|
|
46
|
+
data: `${pythonJsonLine(record)}\n`,
|
|
47
|
+
mode: "append",
|
|
48
|
+
});
|
|
29
49
|
}
|
|
30
50
|
/** Touch mtime for LRU signal; failures swallowed. */
|
|
31
51
|
export function touchMtime(path) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { existsSync,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync, rmSync } from "node:fs";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { containedWrite } from "../../fs/contained-write.js";
|
|
4
4
|
import { DEFAULT_TASK_CACHE_ROOT, TASK_CACHE_MANIFEST } from "./constants.js";
|
|
5
5
|
function entryDir(projectRoot, cacheKey, cacheRoot = DEFAULT_TASK_CACHE_ROOT) {
|
|
6
6
|
return join(resolve(projectRoot), cacheRoot, cacheKey.slice(0, 2), cacheKey);
|
|
@@ -22,12 +22,16 @@ export function writeCachedTaskRecord(projectRoot, cacheKey, record, cacheRoot =
|
|
|
22
22
|
if (record.exitCode !== 0) {
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
|
+
const root = resolve(projectRoot);
|
|
25
26
|
const dir = entryDir(projectRoot, cacheKey, cacheRoot);
|
|
26
27
|
const manifest = join(dir, TASK_CACHE_MANIFEST);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
// #2951 Phase 2: product write sink routes through containedWrite (mkdir + replace).
|
|
29
|
+
containedWrite({
|
|
30
|
+
root,
|
|
31
|
+
target: manifest,
|
|
32
|
+
data: `${JSON.stringify(record, null, 2)}\n`,
|
|
33
|
+
mode: "replace",
|
|
34
|
+
});
|
|
31
35
|
}
|
|
32
36
|
export function clearTaskCache(projectRoot, cacheRoot = DEFAULT_TASK_CACHE_ROOT) {
|
|
33
37
|
const root = join(resolve(projectRoot), cacheRoot);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
|
-
import { existsSync, readdirSync, readFileSync
|
|
2
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
4
|
import { referenceTypeMatches } from "@deftai/directive-types";
|
|
5
5
|
import { sortedStringifyCompact } from "../codebase/json.js";
|
|
6
|
-
import {
|
|
6
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
7
7
|
import { hasArtifactSuffix, resolveLifecycleFolder } from "../layout/resolve.js";
|
|
8
8
|
import { classifyBucket, loadBucketMatchers, resolveCapacityAllocation, SOURCE_MATCH, } from "../policy/capacity.js";
|
|
9
9
|
export const COMPLETED_FOLDER = "completed";
|
|
@@ -139,7 +139,7 @@ function inWindow(completedAt, windowDays, now) {
|
|
|
139
139
|
return ageDays >= 0 && ageDays <= windowDays;
|
|
140
140
|
}
|
|
141
141
|
function writeMetadata(projectRoot, path, data, plan, metadata, options) {
|
|
142
|
-
|
|
142
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
143
143
|
if (typeof plan.metadata !== "object" || plan.metadata === null || Array.isArray(plan.metadata)) {
|
|
144
144
|
plan.metadata = metadata;
|
|
145
145
|
}
|
|
@@ -152,7 +152,13 @@ function writeMetadata(projectRoot, path, data, plan, metadata, options) {
|
|
|
152
152
|
metadata.capacityBucketSource = options.source;
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
|
-
|
|
155
|
+
const root = resolve(projectRoot);
|
|
156
|
+
containedWrite({
|
|
157
|
+
root,
|
|
158
|
+
target: path,
|
|
159
|
+
data: `${JSON.stringify(data, null, 2)}\n`,
|
|
160
|
+
mode: "replace",
|
|
161
|
+
});
|
|
156
162
|
}
|
|
157
163
|
/** Backfill capacityBucket / completedAt on completed vBRIEFs. */
|
|
158
164
|
export async function backfill(projectRoot, options = {}) {
|
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
* order-preserving (the namespaced key takes the legacy key's slot, keeping
|
|
10
10
|
* artifact diffs minimal).
|
|
11
11
|
*/
|
|
12
|
-
import { existsSync, lstatSync, readdirSync, readFileSync
|
|
12
|
+
import { existsSync, lstatSync, readdirSync, readFileSync } from "node:fs";
|
|
13
13
|
import { join, relative, resolve } from "node:path";
|
|
14
|
-
import {
|
|
14
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
15
|
+
import { assertDirectoryNotSymlink } from "../fs/projection-containment.js";
|
|
15
16
|
import { hasArtifactSuffix, resolveLifecycleRoot } from "../layout/resolve.js";
|
|
16
17
|
import { LEGACY_PLAN_COMPLETED_NOTE_KEY, LEGACY_PLAN_POLICY_KEY, PLAN_COMPLETED_NOTE_KEY, PLAN_POLICY_KEY, } from "../policy/plan-extensions.js";
|
|
17
18
|
/** The locked Category B renames (#1650): directive's own config, not xbrief data. */
|
|
@@ -141,7 +142,13 @@ export function migrateCategoryBCorpus(projectRoot) {
|
|
|
141
142
|
}
|
|
142
143
|
if (result.changed) {
|
|
143
144
|
try {
|
|
144
|
-
|
|
145
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
146
|
+
containedWrite({
|
|
147
|
+
root,
|
|
148
|
+
target: file,
|
|
149
|
+
data: `${JSON.stringify(result.doc, null, 2)}\n`,
|
|
150
|
+
mode: "replace",
|
|
151
|
+
});
|
|
145
152
|
}
|
|
146
153
|
catch (err) {
|
|
147
154
|
conflicts.push({
|
|
@@ -150,7 +157,6 @@ export function migrateCategoryBCorpus(projectRoot) {
|
|
|
150
157
|
});
|
|
151
158
|
continue;
|
|
152
159
|
}
|
|
153
|
-
writeFileSync(file, `${JSON.stringify(result.doc, null, 2)}\n`, "utf8");
|
|
154
160
|
changed.push(relPath);
|
|
155
161
|
}
|
|
156
162
|
}
|
|
@@ -20,6 +20,9 @@ export const SKIP_DIRS = new Set([
|
|
|
20
20
|
"build",
|
|
21
21
|
"dist",
|
|
22
22
|
"node_modules",
|
|
23
|
+
// Swarm / agent worktrees are not source modules (#2953, #1656).
|
|
24
|
+
".deft-scratch",
|
|
25
|
+
// Legacy swarm worktree root name (pre-.deft-scratch layout).
|
|
23
26
|
"swarm-worktrees",
|
|
24
27
|
]);
|
|
25
28
|
export const LANGUAGE_BY_SUFFIX = {
|
package/dist/codebase/map.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { existsSync,
|
|
2
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
3
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
3
4
|
import { assertProjectionContained } from "../fs/projection-containment.js";
|
|
4
5
|
import { resolveProjectDefinitionPath } from "../layout/resolve.js";
|
|
5
6
|
import { extractCodeStructure, loadJsonFile } from "../verify-source/code-structure-validate.js";
|
|
@@ -249,8 +250,14 @@ export function writeCodebaseMap(projectRoot, options) {
|
|
|
249
250
|
artifactPath: options.artifactPath,
|
|
250
251
|
});
|
|
251
252
|
const document = renderCodebaseMap(selection.artifact);
|
|
252
|
-
|
|
253
|
-
|
|
253
|
+
// #2980 wave D: product write sink routes through containedWrite.
|
|
254
|
+
const root = resolve(projectRoot);
|
|
255
|
+
containedWrite({
|
|
256
|
+
root,
|
|
257
|
+
target: resolvedOutput,
|
|
258
|
+
data: document,
|
|
259
|
+
mode: "replace",
|
|
260
|
+
});
|
|
254
261
|
return resolvedOutput;
|
|
255
262
|
}
|
|
256
263
|
export function runCodebaseMapCli(argv) {
|
|
@@ -7,7 +7,7 @@ export declare const DEPRECATED_REDIRECT_SENTINEL = "<!-- deft:deprecated-redire
|
|
|
7
7
|
export declare const DEPRECATED_SKILL_REDIRECT_SENTINEL = "<!-- deft:deprecated-skill-redirect -->";
|
|
8
8
|
export declare const REDIRECT_STUB_HEADER_LINES = 8;
|
|
9
9
|
export declare const TASKFILE_INCLUDE_SNIPPET = "version: '3'\n\nincludes:\n deft:\n taskfile: ./.deft/core/Taskfile.yml\n optional: true\n";
|
|
10
|
-
export declare const DOCTOR_ALLOWED_FLAGS: readonly ["--session", "--fix", "--repair", "--repair-taskfile", "--json", "--quiet", "--full", "--network", "--project-root", "-h", "--help"];
|
|
10
|
+
export declare const DOCTOR_ALLOWED_FLAGS: readonly ["--session", "--fix", "--repair", "--repair-taskfile", "--json", "--quiet", "--full", "--network", "--project-root", "--force", "--openclaw-all-agents", "-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
13
|
export declare const PUBLIC_NPM_REGISTRY = "https://registry.npmjs.org/";
|
package/dist/doctor/constants.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { mkdirSync, readFileSync
|
|
1
|
+
import { mkdirSync, readFileSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
|
-
import { dirname, join } from "node:path";
|
|
3
|
+
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
4
|
+
import { containedWrite } from "../fs/contained-write.js";
|
|
4
5
|
import { resolveTriageCachePath } from "../triage/cache-path.js";
|
|
5
6
|
import { CLEAN_WINDOW_HOURS, DIRTY_WINDOW_HOURS, ENV_STATE_PATH } from "./constants.js";
|
|
6
7
|
const STATE_FILENAME = "doctor-state.json";
|
|
@@ -57,8 +58,31 @@ export function writeState(projectRoot, payload) {
|
|
|
57
58
|
};
|
|
58
59
|
const path = statePath(projectRoot);
|
|
59
60
|
try {
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
// #2980 wave C: product write sink routes through containedWrite.
|
|
62
|
+
// Default path is under the project triage cache; ENV_STATE_PATH may point outside.
|
|
63
|
+
const projectAbs = resolve(projectRoot);
|
|
64
|
+
const pathAbs = resolve(path);
|
|
65
|
+
const rel = relative(projectAbs, pathAbs);
|
|
66
|
+
const nested = rel.length > 0 && !rel.startsWith("..") && !isAbsolute(rel);
|
|
67
|
+
const payload = `${JSON.stringify(body, null, 2)}\n`;
|
|
68
|
+
if (nested) {
|
|
69
|
+
containedWrite({
|
|
70
|
+
root: projectAbs,
|
|
71
|
+
target: pathAbs,
|
|
72
|
+
data: payload,
|
|
73
|
+
mode: "replace",
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
const parent = dirname(pathAbs);
|
|
78
|
+
mkdirSync(parent, { recursive: true });
|
|
79
|
+
containedWrite({
|
|
80
|
+
root: resolve(parent),
|
|
81
|
+
target: basename(pathAbs),
|
|
82
|
+
data: payload,
|
|
83
|
+
mode: "replace",
|
|
84
|
+
});
|
|
85
|
+
}
|
|
62
86
|
return path;
|
|
63
87
|
}
|
|
64
88
|
catch {
|
package/dist/doctor/flags.js
CHANGED
|
@@ -8,6 +8,8 @@ export function parseDoctorFlags(args) {
|
|
|
8
8
|
let network = false;
|
|
9
9
|
let help = false;
|
|
10
10
|
let projectRoot = null;
|
|
11
|
+
let force = false;
|
|
12
|
+
let openclawAllAgents = false;
|
|
11
13
|
const unknown = [];
|
|
12
14
|
let i = 0;
|
|
13
15
|
while (i < args.length) {
|
|
@@ -30,6 +32,12 @@ export function parseDoctorFlags(args) {
|
|
|
30
32
|
else if (token === "--network") {
|
|
31
33
|
network = true;
|
|
32
34
|
}
|
|
35
|
+
else if (token === "--force") {
|
|
36
|
+
force = true;
|
|
37
|
+
}
|
|
38
|
+
else if (token === "--openclaw-all-agents") {
|
|
39
|
+
openclawAllAgents = true;
|
|
40
|
+
}
|
|
33
41
|
else if (token === "-h" || token === "--help") {
|
|
34
42
|
help = true;
|
|
35
43
|
}
|
|
@@ -56,7 +64,19 @@ export function parseDoctorFlags(args) {
|
|
|
56
64
|
}
|
|
57
65
|
i += 1;
|
|
58
66
|
}
|
|
59
|
-
return {
|
|
67
|
+
return {
|
|
68
|
+
session,
|
|
69
|
+
fix,
|
|
70
|
+
json,
|
|
71
|
+
quiet,
|
|
72
|
+
full,
|
|
73
|
+
network,
|
|
74
|
+
help,
|
|
75
|
+
projectRoot,
|
|
76
|
+
force,
|
|
77
|
+
openclawAllAgents,
|
|
78
|
+
unknown,
|
|
79
|
+
};
|
|
60
80
|
}
|
|
61
81
|
export function formatUnknownFlagsError(unknown) {
|
|
62
82
|
return `Unknown flag(s): ${unknown.join(", ")}`;
|
package/dist/doctor/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export * from "./json.js";
|
|
|
7
7
|
export * from "./main.js";
|
|
8
8
|
export * from "./manifest.js";
|
|
9
9
|
export * from "./npm-registry.js";
|
|
10
|
+
export * from "./openclaw-skills.js";
|
|
10
11
|
export * from "./paths.js";
|
|
11
12
|
export * from "./payload-staleness.js";
|
|
12
13
|
export * from "./release-availability.js";
|
package/dist/doctor/index.js
CHANGED
|
@@ -7,6 +7,7 @@ export * from "./json.js";
|
|
|
7
7
|
export * from "./main.js";
|
|
8
8
|
export * from "./manifest.js";
|
|
9
9
|
export * from "./npm-registry.js";
|
|
10
|
+
export * from "./openclaw-skills.js";
|
|
10
11
|
export * from "./paths.js";
|
|
11
12
|
export * from "./payload-staleness.js";
|
|
12
13
|
export * from "./release-availability.js";
|
package/dist/doctor/main.d.ts
CHANGED
|
@@ -4,6 +4,16 @@ import type { DoctorSeams, Finding, ResolutionSummary } from "./types.js";
|
|
|
4
4
|
export declare function cmdDoctor(args: readonly string[], seams?: DoctorSeams): number;
|
|
5
5
|
export declare function runAgentHooksHealthCheck(projectRoot: string, consumerContext: boolean, sink: ReturnType<typeof createPlainSink>, addFinding: (finding: Finding) => void, seams: DoctorSeams): boolean;
|
|
6
6
|
export declare function runAgentHooksLiveProbeCheck(projectRoot: string, sink: ReturnType<typeof createPlainSink>, addFinding: (finding: Finding) => void, seams: DoctorSeams): void;
|
|
7
|
+
/**
|
|
8
|
+
* Fail closed when PROJECT-DEFINITION under an xbrief/ layout still declares
|
|
9
|
+
* envelope 0.6 while the framework schema is 0.8 (#2971). Greenfield (no
|
|
10
|
+
* project definition yet) and current 0.8 envelopes pass. Unreadable paths
|
|
11
|
+
* (test seams / permission) skip rather than false-positive fail. Behind-major
|
|
12
|
+
* records `deft migrate:xbrief` as the next action — layout rename alone is not
|
|
13
|
+
* enough. Distinct from deposited-schema (`stale-xbrief-schema-deposit`) which
|
|
14
|
+
* must NOT route to migrate:xbrief when only framework schema files are stale.
|
|
15
|
+
*/
|
|
16
|
+
export declare function runXbriefEnvelopeVersionCheck(projectRoot: string, sink: ReturnType<typeof createPlainSink>, addFinding: (f: Finding) => void, seams: DoctorSeams): void;
|
|
7
17
|
/**
|
|
8
18
|
* Never emit a bare `task ...` remediation in a project without Taskfile wiring
|
|
9
19
|
* (#2267 / #2893). The `directive`/`deft` surface always works; `task deft:X` is
|
package/dist/doctor/main.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { existsSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
|
+
import { VBRIEF_VERSION } from "@deftai/directive-types";
|
|
3
4
|
import { evaluate as evaluateAgentsMdAdvisory } from "../agents-md-advisory/evaluate.js";
|
|
4
5
|
import { contentRoot } from "../content-root.js";
|
|
6
|
+
import { resolveProjectDefinitionPath } from "../layout/resolve.js";
|
|
5
7
|
import { detectNoDeftDirective, NO_DEFT_DIRECTIVE_DISABLED_MESSAGE, NO_DEFT_DIRECTIVE_FLAG_NAME, NO_DEFT_DIRECTIVE_INCONSISTENT_MESSAGE, NO_DEFT_DIRECTIVE_INCONSISTENT_POLICY, } from "../policy/no-deft-directive.js";
|
|
6
8
|
import { describeShadowedPlanExtension, detectShadowedPlanExtensions, } from "../policy/plan-extensions.js";
|
|
7
9
|
import { loadProjectDefinition } from "../policy/resolve.js";
|
|
8
10
|
import { checkLocalEngineIntegrity, classify, detectPackageManager, evaluateSkew, reconcileVersions, plan as resolvePlan, } from "../resolution/index.js";
|
|
11
|
+
import { classifyXbriefSchemaDistance } from "../staleness-tickler/probe-xbrief.js";
|
|
9
12
|
import { resolveUserMdPath } from "../user-config/resolve-user-md.js";
|
|
10
13
|
import { evaluateAgentHooks } from "../verify-env/agent-hooks.js";
|
|
11
14
|
import { probeAgentHooksLive } from "../verify-env/agent-hooks-live-probe.js";
|
|
15
|
+
import { readDeclaredArtifactVersion } from "../xbrief-migrate/transforms.js";
|
|
12
16
|
import { agentsRefreshPlan, hasV3ManagedMarker } from "./agents-md.js";
|
|
13
17
|
import { runChecks } from "./checks.js";
|
|
14
18
|
import { CONSUMER_FRAMEWORK_DIRS, EXPECTED_CONTENT_DIRS, EXPECTED_FRAMEWORK_DIRS, NETWORK_DISCLOSURE_LINE, PAYLOAD_STALENESS_OFFLINE_SKIP_MESSAGE, TASKFILE_INCLUDE_SNIPPET, UV_INSTALL_URL, } from "./constants.js";
|
|
@@ -17,6 +21,7 @@ import { formatAllowedFlagsHint, formatUnknownFlagsError, parseDoctorFlags } fro
|
|
|
17
21
|
import { pythonJsonDump } from "./json.js";
|
|
18
22
|
import { parseInstallRootFromAgentsMd } from "./manifest.js";
|
|
19
23
|
import { runNpmRegistryMirrorCheck } from "./npm-registry.js";
|
|
24
|
+
import { runOpenClawSkillPinsCheck } from "./openclaw-skills.js";
|
|
20
25
|
import { createPlainSink } from "./output.js";
|
|
21
26
|
import { readTextSafe, resolveFrameworkRootForProject, resolvePath, resolveVersion, runningInsideDeftRepo, } from "./paths.js";
|
|
22
27
|
import { runPayloadStalenessCheck } from "./payload-staleness.js";
|
|
@@ -24,6 +29,8 @@ import { runLocalSignpostChecks } from "./signpost-checks.js";
|
|
|
24
29
|
import { classifyTaskfileInclude, formatGatesSurfaceDualRemediation, formatMissingIncludeSnippet, GATES_SURFACE_DEFT_REMEDIATION, includesBlockHasDeftTaskfile, resolveConsumerTaskfile, } from "./taskfile.js";
|
|
25
30
|
import { defaultWhich } from "./which.js";
|
|
26
31
|
const DEFAULT_RESOLUTION_PLATFORMS = ["linux", "darwin", "win32"];
|
|
32
|
+
/** Next-action command for project-envelope behind-major (#2971). */
|
|
33
|
+
const XBRIEF_ENVELOPE_MIGRATE_COMMAND = "deft migrate:xbrief";
|
|
27
34
|
/**
|
|
28
35
|
* Read the `packageManager` field (Corepack) from a project package.json, or
|
|
29
36
|
* null when absent/unreadable. Lets the doctor detect a pnpm project that has
|
|
@@ -341,6 +348,32 @@ export function cmdDoctor(args, seams = {}) {
|
|
|
341
348
|
}
|
|
342
349
|
sink.info("Checking gates-surface readiness (Taskfile include for deep-think agent gates)...");
|
|
343
350
|
runTaskfileIncludeCheck(projectRoot, fixMode, jsonMode, sink, addFinding, seams);
|
|
351
|
+
if (!jsonMode) {
|
|
352
|
+
sink.blank();
|
|
353
|
+
}
|
|
354
|
+
sink.info("Checking OpenClaw always-pin skills...");
|
|
355
|
+
runOpenClawSkillPinsCheck(sink, addFinding, {
|
|
356
|
+
frameworkRoot,
|
|
357
|
+
fixMode,
|
|
358
|
+
jsonMode,
|
|
359
|
+
force: flags.force,
|
|
360
|
+
allAgents: flags.openclawAllAgents,
|
|
361
|
+
seams: {
|
|
362
|
+
...seams,
|
|
363
|
+
env: seams.openclawEnv,
|
|
364
|
+
homeDir: seams.openclawHomeDir,
|
|
365
|
+
contentRootFor: seams.openclawContentRootFor,
|
|
366
|
+
isDir: seams.isDir,
|
|
367
|
+
isFile: seams.isFile,
|
|
368
|
+
isTty: seams.isTty,
|
|
369
|
+
readYn: seams.readYn,
|
|
370
|
+
},
|
|
371
|
+
});
|
|
372
|
+
if (!jsonMode) {
|
|
373
|
+
sink.blank();
|
|
374
|
+
}
|
|
375
|
+
sink.info("Checking xBRIEF project envelope version...");
|
|
376
|
+
runXbriefEnvelopeVersionCheck(projectRoot, sink, addFinding, seams);
|
|
344
377
|
let resolution = null;
|
|
345
378
|
if (!runningInsideDeftRepo(projectRoot, seams)) {
|
|
346
379
|
if (!jsonMode) {
|
|
@@ -770,6 +803,155 @@ function runTaskfileIncludeCheck(projectRoot, fixMode, jsonMode, sink, addFindin
|
|
|
770
803
|
suggestion: GATES_SURFACE_DEFT_REMEDIATION,
|
|
771
804
|
});
|
|
772
805
|
}
|
|
806
|
+
/**
|
|
807
|
+
* Fail closed when PROJECT-DEFINITION under an xbrief/ layout still declares
|
|
808
|
+
* envelope 0.6 while the framework schema is 0.8 (#2971). Greenfield (no
|
|
809
|
+
* project definition yet) and current 0.8 envelopes pass. Unreadable paths
|
|
810
|
+
* (test seams / permission) skip rather than false-positive fail. Behind-major
|
|
811
|
+
* records `deft migrate:xbrief` as the next action — layout rename alone is not
|
|
812
|
+
* enough. Distinct from deposited-schema (`stale-xbrief-schema-deposit`) which
|
|
813
|
+
* must NOT route to migrate:xbrief when only framework schema files are stale.
|
|
814
|
+
*/
|
|
815
|
+
export function runXbriefEnvelopeVersionCheck(projectRoot, sink, addFinding, seams) {
|
|
816
|
+
const checkName = "xbrief-envelope-version";
|
|
817
|
+
const isFile = seams.isFile ?? ((p) => existsSync(p));
|
|
818
|
+
const readText = seams.readText ?? readTextSafe;
|
|
819
|
+
const targetVersion = VBRIEF_VERSION;
|
|
820
|
+
if (seams.probeXbriefEnvelope) {
|
|
821
|
+
const probe = seams.probeXbriefEnvelope(projectRoot);
|
|
822
|
+
emitXbriefEnvelopeFinding(checkName, probe, sink, addFinding);
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
let definitionPath;
|
|
826
|
+
try {
|
|
827
|
+
definitionPath = resolveProjectDefinitionPath(projectRoot);
|
|
828
|
+
}
|
|
829
|
+
catch {
|
|
830
|
+
// Pure vbrief/-only trees are already covered by layout migrate signposts.
|
|
831
|
+
const skipMessage = `${checkName}: skip -- legacy-only layout (use layout migrate first)`;
|
|
832
|
+
sink.info(skipMessage);
|
|
833
|
+
addFinding({
|
|
834
|
+
severity: "skip",
|
|
835
|
+
message: skipMessage,
|
|
836
|
+
check: checkName,
|
|
837
|
+
status: "skip",
|
|
838
|
+
reason: "legacy-only-layout",
|
|
839
|
+
});
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
if (!isFile(definitionPath)) {
|
|
843
|
+
const skipMessage = `${checkName}: skip -- no PROJECT-DEFINITION yet (greenfield)`;
|
|
844
|
+
sink.info(skipMessage);
|
|
845
|
+
addFinding({
|
|
846
|
+
severity: "skip",
|
|
847
|
+
message: skipMessage,
|
|
848
|
+
check: checkName,
|
|
849
|
+
status: "skip",
|
|
850
|
+
reason: "no-project-definition",
|
|
851
|
+
});
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
const text = readText(definitionPath);
|
|
855
|
+
if (text === null) {
|
|
856
|
+
// Unreadable path (permissions or injectable seams) is not proof of 0.6.
|
|
857
|
+
const skipMessage = `${checkName}: skip -- PROJECT-DEFINITION unreadable`;
|
|
858
|
+
sink.info(skipMessage);
|
|
859
|
+
addFinding({
|
|
860
|
+
severity: "skip",
|
|
861
|
+
message: skipMessage,
|
|
862
|
+
check: checkName,
|
|
863
|
+
status: "skip",
|
|
864
|
+
reason: "unreadable",
|
|
865
|
+
});
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
let declaredVersion = null;
|
|
869
|
+
try {
|
|
870
|
+
const parsed = JSON.parse(text);
|
|
871
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
872
|
+
declaredVersion = readDeclaredArtifactVersion(parsed);
|
|
873
|
+
}
|
|
874
|
+
else {
|
|
875
|
+
const skipMessage = `${checkName}: skip -- PROJECT-DEFINITION is not a JSON object`;
|
|
876
|
+
sink.info(skipMessage);
|
|
877
|
+
addFinding({
|
|
878
|
+
severity: "skip",
|
|
879
|
+
message: skipMessage,
|
|
880
|
+
check: checkName,
|
|
881
|
+
status: "skip",
|
|
882
|
+
reason: "invalid-json-shape",
|
|
883
|
+
});
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
catch {
|
|
888
|
+
const skipMessage = `${checkName}: skip -- PROJECT-DEFINITION JSON parse failed`;
|
|
889
|
+
sink.info(skipMessage);
|
|
890
|
+
addFinding({
|
|
891
|
+
severity: "skip",
|
|
892
|
+
message: skipMessage,
|
|
893
|
+
check: checkName,
|
|
894
|
+
status: "skip",
|
|
895
|
+
reason: "parse-error",
|
|
896
|
+
});
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
const distance = classifyXbriefSchemaDistance(declaredVersion, targetVersion);
|
|
900
|
+
emitXbriefEnvelopeFinding(checkName, {
|
|
901
|
+
declaredVersion,
|
|
902
|
+
targetVersion,
|
|
903
|
+
distance,
|
|
904
|
+
stale: distance !== "current",
|
|
905
|
+
}, sink, addFinding);
|
|
906
|
+
}
|
|
907
|
+
function emitXbriefEnvelopeFinding(checkName, probe, sink, addFinding) {
|
|
908
|
+
if (probe.distance === "current") {
|
|
909
|
+
const okMessage = `${checkName}: current -- xBRIEFInfo@${probe.declaredVersion ?? probe.targetVersion} ` +
|
|
910
|
+
`(framework ${probe.targetVersion})`;
|
|
911
|
+
sink.success(okMessage);
|
|
912
|
+
addFinding({
|
|
913
|
+
severity: "skip",
|
|
914
|
+
message: okMessage,
|
|
915
|
+
check: checkName,
|
|
916
|
+
status: "current",
|
|
917
|
+
declared_version: probe.declaredVersion,
|
|
918
|
+
target_version: probe.targetVersion,
|
|
919
|
+
});
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
if (probe.distance === "behind-minor") {
|
|
923
|
+
const warnMessage = `${checkName}: behind-minor -- declared ${probe.declaredVersion ?? "unknown"}, ` +
|
|
924
|
+
`framework ${probe.targetVersion}. Prefer \`deft migrate:xbrief\` when convenient.`;
|
|
925
|
+
sink.warn(warnMessage);
|
|
926
|
+
addFinding({
|
|
927
|
+
severity: "warning",
|
|
928
|
+
message: warnMessage,
|
|
929
|
+
check: checkName,
|
|
930
|
+
status: "behind-minor",
|
|
931
|
+
suggestion: XBRIEF_ENVELOPE_MIGRATE_COMMAND,
|
|
932
|
+
declared_version: probe.declaredVersion,
|
|
933
|
+
target_version: probe.targetVersion,
|
|
934
|
+
next_command: XBRIEF_ENVELOPE_MIGRATE_COMMAND,
|
|
935
|
+
});
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
// behind-major (declared 0.6 vs framework 0.8, dual half-state, missing version)
|
|
939
|
+
const nextCommand = XBRIEF_ENVELOPE_MIGRATE_COMMAND;
|
|
940
|
+
const message = `${checkName}: behind-major -- declared ${probe.declaredVersion ?? "unknown"}, ` +
|
|
941
|
+
`framework ${probe.targetVersion}. Next action: run \`${nextCommand}\` to bump project ` +
|
|
942
|
+
`JSON envelopes to xBRIEFInfo@${probe.targetVersion} (layout rename alone is not enough).`;
|
|
943
|
+
sink.error(message);
|
|
944
|
+
addFinding({
|
|
945
|
+
severity: "error",
|
|
946
|
+
message,
|
|
947
|
+
check: checkName,
|
|
948
|
+
status: "behind-major",
|
|
949
|
+
suggestion: nextCommand,
|
|
950
|
+
declared_version: probe.declaredVersion,
|
|
951
|
+
target_version: probe.targetVersion,
|
|
952
|
+
next_command: nextCommand,
|
|
953
|
+
});
|
|
954
|
+
}
|
|
773
955
|
/**
|
|
774
956
|
* Surface the resolved USER.md path + which search rung matched (#2271) so the
|
|
775
957
|
* resolution boundary is visible in doctor output. Uses the shared first-hit-
|