@deftai/directive-core 0.91.0 → 0.93.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.js +3 -2
- package/dist/cache/io.d.ts +13 -2
- package/dist/cache/io.js +36 -7
- package/dist/cache/operations.js +5 -3
- package/dist/doctor/index.d.ts +1 -0
- package/dist/doctor/index.js +1 -0
- package/dist/doctor/main.js +49 -0
- package/dist/doctor/openclaw-l2-adapter.d.ts +26 -0
- package/dist/doctor/openclaw-l2-adapter.js +199 -0
- package/dist/hooks/dispatcher.d.ts +6 -1
- package/dist/hooks/dispatcher.js +30 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/init-deposit/gitignore.js +3 -0
- package/dist/init-deposit/hygiene.d.ts +43 -1
- package/dist/init-deposit/hygiene.js +134 -10
- package/dist/init-deposit/index.d.ts +3 -0
- package/dist/init-deposit/index.js +3 -0
- package/dist/init-deposit/init-deposit.js +10 -0
- package/dist/init-deposit/refresh.js +11 -0
- package/dist/init-deposit/scaffold.js +6 -134
- package/dist/init-deposit/skill-discovery-deposit.d.ts +65 -0
- package/dist/init-deposit/skill-discovery-deposit.js +287 -0
- package/dist/init-deposit/skill-discovery-hosts.d.ts +94 -0
- package/dist/init-deposit/skill-discovery-hosts.js +217 -0
- package/dist/init-deposit/slash-deposit.d.ts +46 -0
- package/dist/init-deposit/slash-deposit.js +174 -0
- package/dist/orchestration/probe-session.d.ts +5 -1
- package/dist/orchestration/probe-session.js +24 -13
- package/dist/platform/agents-md.js +1 -1
- package/dist/policy/deft-directive-disable.d.ts +86 -0
- package/dist/policy/deft-directive-disable.js +167 -0
- package/dist/policy/delivery-branch.d.ts +33 -0
- package/dist/policy/delivery-branch.js +124 -0
- package/dist/policy/host-slash-commands.d.ts +28 -0
- package/dist/policy/host-slash-commands.js +103 -0
- package/dist/policy/index.d.ts +3 -0
- package/dist/policy/index.js +61 -5
- package/dist/scope/brief-io.d.ts +3 -1
- package/dist/scope/brief-io.js +5 -3
- package/dist/scope/delivery-evidence.d.ts +112 -0
- package/dist/scope/delivery-evidence.js +419 -0
- package/dist/scope/index.d.ts +1 -0
- package/dist/scope/index.js +1 -0
- package/dist/scope/main.d.ts +5 -0
- package/dist/scope/main.js +98 -3
- package/dist/scope/registry-artifact-sync.js +4 -1
- package/dist/scope/transition.d.ts +11 -1
- package/dist/scope/transition.js +30 -4
- package/dist/session/ritual-sentinel.js +21 -12
- package/dist/session/session-start-hook.d.ts +3 -0
- package/dist/session/session-start-hook.js +21 -0
- package/dist/session/session-start.js +31 -0
- package/dist/slash/emitters.d.ts +102 -0
- package/dist/slash/emitters.js +148 -0
- package/dist/slash/generator.d.ts +98 -0
- package/dist/slash/generator.js +145 -0
- package/dist/slash/index.d.ts +16 -0
- package/dist/slash/index.js +16 -0
- package/dist/slash/openclaw-adapter.d.ts +64 -0
- package/dist/slash/openclaw-adapter.js +198 -0
- package/dist/slash/openclaw-deposit.d.ts +73 -0
- package/dist/slash/openclaw-deposit.js +279 -0
- package/dist/slash/openclaw-slugs.d.ts +52 -0
- package/dist/slash/openclaw-slugs.js +126 -0
- package/dist/slash/product-set.d.ts +50 -0
- package/dist/slash/product-set.js +142 -0
- package/dist/swarm/complete-cohort.d.ts +20 -1
- package/dist/swarm/complete-cohort.js +56 -9
- package/dist/swarm/finalize-cohort-cli.js +9 -0
- package/dist/swarm/finalize-cohort.d.ts +8 -0
- package/dist/swarm/finalize-cohort.js +217 -21
- package/dist/user-config/experimental-rules.d.ts +43 -0
- package/dist/user-config/experimental-rules.js +162 -0
- package/dist/user-config/index.d.ts +1 -0
- package/dist/user-config/index.js +1 -0
- package/dist/vbrief-validate/plan-hooks.d.ts +4 -0
- package/dist/vbrief-validate/plan-hooks.js +50 -0
- package/dist/verify-source/contained-writes.js +1 -1
- package/dist/xbrief/create.d.ts +36 -0
- package/dist/xbrief/create.js +285 -0
- package/dist/xbrief/index.d.ts +14 -0
- package/dist/xbrief/index.js +42 -0
- package/dist/xbrief/paths.d.ts +37 -0
- package/dist/xbrief/paths.js +123 -0
- package/dist/xbrief/styles.d.ts +36 -0
- package/dist/xbrief/styles.js +235 -0
- package/dist/xbrief/types.d.ts +50 -0
- package/dist/xbrief/types.js +17 -0
- package/dist/xbrief/verify.d.ts +30 -0
- package/dist/xbrief/verify.js +251 -0
- package/package.json +11 -3
package/dist/cache/fetch.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
|
-
import { join, resolve } from "node:path";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
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";
|
|
@@ -45,7 +45,8 @@ export function writeOpenInventoryStamp(options) {
|
|
|
45
45
|
fetched_at: utcIso(clock, fetchedAt),
|
|
46
46
|
open_count: 0,
|
|
47
47
|
};
|
|
48
|
-
|
|
48
|
+
// #3042: contain stamp write against project root (parent of cacheRoot).
|
|
49
|
+
atomicWriteText(openInventoryStampPath(options.cacheRoot, options.source, options.repo), `${JSON.stringify(payload)}\n`, { projectRoot: dirname(resolve(options.cacheRoot)) });
|
|
49
50
|
}
|
|
50
51
|
export const REST_MAX_PER_PAGE = 100;
|
|
51
52
|
export const REST_PAGINATION_MAX_PAGES = 100;
|
package/dist/cache/io.d.ts
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import { tmpdir } from "node:os";
|
|
2
|
+
export interface AtomicWriteTextOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Project / checkout root used as the containment boundary (#3042).
|
|
5
|
+
* When set, refuses symlink parents and out-of-root targets before temp+rename.
|
|
6
|
+
* Prefer always passing this for product sinks (brief stay-path, agents refresh, cache).
|
|
7
|
+
* When omitted, falls back to parent-dir containment (legacy test / low-risk helpers).
|
|
8
|
+
*/
|
|
9
|
+
readonly projectRoot?: string;
|
|
10
|
+
}
|
|
2
11
|
/**
|
|
3
12
|
* Write text via tempfile + rename (mirrors Python `_atomic_write_text`).
|
|
4
|
-
* #2951 Phase 2: temp payload write uses containedWrite
|
|
13
|
+
* #2951 Phase 2: temp payload write uses containedWrite.
|
|
14
|
+
* #3042: when `projectRoot` is set, containment root is projectRoot (not dirname(path))
|
|
15
|
+
* so force-added lifecycle / cache directory symlinks fail closed.
|
|
5
16
|
*/
|
|
6
|
-
export declare function atomicWriteText(path: string, text: string): void;
|
|
17
|
+
export declare function atomicWriteText(path: string, text: string, options?: AtomicWriteTextOptions): void;
|
|
7
18
|
/**
|
|
8
19
|
* Append one JSON audit record (mirrors `_append_audit`).
|
|
9
20
|
* #2951 Phase 2: product write sink routes through containedWrite.
|
package/dist/cache/io.js
CHANGED
|
@@ -3,24 +3,53 @@ import { mkdirSync, renameSync, rmSync, statSync, utimesSync } from "node:fs";
|
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { basename, dirname, join, resolve } from "node:path";
|
|
5
5
|
import { containedWrite } from "../fs/contained-write.js";
|
|
6
|
+
import { assertWriteTargetSafe } from "../fs/projection-containment.js";
|
|
6
7
|
import { pythonJsonLine } from "./json.js";
|
|
7
8
|
/**
|
|
8
9
|
* Write text via tempfile + rename (mirrors Python `_atomic_write_text`).
|
|
9
|
-
* #2951 Phase 2: temp payload write uses containedWrite
|
|
10
|
+
* #2951 Phase 2: temp payload write uses containedWrite.
|
|
11
|
+
* #3042: when `projectRoot` is set, containment root is projectRoot (not dirname(path))
|
|
12
|
+
* so force-added lifecycle / cache directory symlinks fail closed.
|
|
10
13
|
*/
|
|
11
|
-
export function atomicWriteText(path, text) {
|
|
12
|
-
const
|
|
14
|
+
export function atomicWriteText(path, text, options = {}) {
|
|
15
|
+
const targetAbs = resolve(path);
|
|
16
|
+
const dir = dirname(targetAbs);
|
|
17
|
+
const tmpBase = `${basename(targetAbs)}.${randomBytes(4).toString("hex")}.tmp`;
|
|
18
|
+
const tmp = join(dir, tmpBase);
|
|
19
|
+
if (options.projectRoot !== undefined) {
|
|
20
|
+
// Contain against projectRoot (parent-as-root fix #3042 / authz writeJsonContained pattern).
|
|
21
|
+
const root = resolve(options.projectRoot);
|
|
22
|
+
assertWriteTargetSafe(root, targetAbs);
|
|
23
|
+
try {
|
|
24
|
+
containedWrite({
|
|
25
|
+
root,
|
|
26
|
+
target: tmp,
|
|
27
|
+
data: text,
|
|
28
|
+
mode: "create",
|
|
29
|
+
});
|
|
30
|
+
renameSync(tmp, targetAbs);
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
try {
|
|
34
|
+
rmSync(tmp, { force: true });
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
/* v8 ignore next -- best-effort cleanup */
|
|
38
|
+
}
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Legacy: parent-dir containment when no projectRoot (unit helpers / transitional call sites).
|
|
13
44
|
mkdirSync(dir, { recursive: true });
|
|
14
|
-
const tmpName = `${basename(path)}.${randomBytes(4).toString("hex")}.tmp`;
|
|
15
|
-
const tmp = join(dir, tmpName);
|
|
16
45
|
try {
|
|
17
46
|
containedWrite({
|
|
18
47
|
root: resolve(dir),
|
|
19
|
-
target:
|
|
48
|
+
target: tmpBase,
|
|
20
49
|
data: text,
|
|
21
50
|
mode: "create",
|
|
22
51
|
});
|
|
23
|
-
renameSync(tmp,
|
|
52
|
+
renameSync(tmp, targetAbs);
|
|
24
53
|
}
|
|
25
54
|
catch (err) {
|
|
26
55
|
try {
|
package/dist/cache/operations.js
CHANGED
|
@@ -129,14 +129,16 @@ export function cachePut(source, key, raw, options = {}) {
|
|
|
129
129
|
incomingBytes: incomingDelta,
|
|
130
130
|
});
|
|
131
131
|
}
|
|
132
|
-
|
|
132
|
+
// #3042: contain cache entry writes against project root (parent of cacheRoot).
|
|
133
|
+
const projectRoot = dirname(resolve(cacheRoot));
|
|
134
|
+
atomicWriteText(join(edir, "raw.json"), rawText, { projectRoot });
|
|
133
135
|
const authoritativeSize = fileSize(join(edir, "raw.json"));
|
|
134
136
|
const rendered = renderContent(source, raw);
|
|
135
137
|
const scanResult = scan(rendered, utcIso(clock, fetched));
|
|
136
138
|
const contentPath = join(edir, "content.md");
|
|
137
139
|
let contentWritten = false;
|
|
138
140
|
if (scanResult.passed) {
|
|
139
|
-
atomicWriteText(contentPath, scanResult.transformed_content);
|
|
141
|
+
atomicWriteText(contentPath, scanResult.transformed_content, { projectRoot });
|
|
140
142
|
contentWritten = true;
|
|
141
143
|
}
|
|
142
144
|
else if (existsSync(contentPath)) {
|
|
@@ -158,7 +160,7 @@ export function cachePut(source, key, raw, options = {}) {
|
|
|
158
160
|
clock,
|
|
159
161
|
});
|
|
160
162
|
validateMeta(meta);
|
|
161
|
-
atomicWriteText(join(edir, "meta.json"), pythonJsonDump(meta));
|
|
163
|
+
atomicWriteText(join(edir, "meta.json"), pythonJsonDump(meta), { projectRoot });
|
|
162
164
|
appendAudit({
|
|
163
165
|
event: "cache:put",
|
|
164
166
|
source,
|
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-l2-adapter.js";
|
|
10
11
|
export * from "./openclaw-skills.js";
|
|
11
12
|
export * from "./paths.js";
|
|
12
13
|
export * from "./payload-staleness.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-l2-adapter.js";
|
|
10
11
|
export * from "./openclaw-skills.js";
|
|
11
12
|
export * from "./paths.js";
|
|
12
13
|
export * from "./payload-staleness.js";
|
package/dist/doctor/main.js
CHANGED
|
@@ -4,6 +4,7 @@ import { VBRIEF_VERSION } from "@deftai/directive-types";
|
|
|
4
4
|
import { evaluate as evaluateAgentsMdAdvisory } from "../agents-md-advisory/evaluate.js";
|
|
5
5
|
import { contentRoot } from "../content-root.js";
|
|
6
6
|
import { resolveProjectDefinitionPath } from "../layout/resolve.js";
|
|
7
|
+
import { DEFT_DIRECTIVE_DISABLE_FLAG_NAME, DEFT_DIRECTIVE_DISABLE_STATUS, DEFT_DIRECTIVE_DISABLE_TRACKED_WARNING, detectDeftDirectiveDisable, formatDeftDirectiveDisableMessage, isDeftDirectiveDisableActive, } from "../policy/deft-directive-disable.js";
|
|
7
8
|
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";
|
|
8
9
|
import { describeShadowedPlanExtension, detectShadowedPlanExtensions, } from "../policy/plan-extensions.js";
|
|
9
10
|
import { loadProjectDefinition } from "../policy/resolve.js";
|
|
@@ -21,6 +22,7 @@ import { formatAllowedFlagsHint, formatUnknownFlagsError, parseDoctorFlags } fro
|
|
|
21
22
|
import { pythonJsonDump } from "./json.js";
|
|
22
23
|
import { parseInstallRootFromAgentsMd } from "./manifest.js";
|
|
23
24
|
import { runNpmRegistryMirrorCheck } from "./npm-registry.js";
|
|
25
|
+
import { runOpenClawL2AdapterCheck } from "./openclaw-l2-adapter.js";
|
|
24
26
|
import { runOpenClawSkillPinsCheck } from "./openclaw-skills.js";
|
|
25
27
|
import { createPlainSink } from "./output.js";
|
|
26
28
|
import { readTextSafe, resolveFrameworkRootForProject, resolvePath, resolveVersion, runningInsideDeftRepo, } from "./paths.js";
|
|
@@ -70,6 +72,42 @@ export function cmdDoctor(args, seams = {}) {
|
|
|
70
72
|
const consumerContext = resolve(projectRoot) !== resolve(frameworkRoot);
|
|
71
73
|
const whichFn = seams.whichFn ?? defaultWhich;
|
|
72
74
|
const nowFn = seams.now ?? (() => new Date());
|
|
75
|
+
// #3039: temporary test kill-switch. Active (untracked) → disabled short-circuit.
|
|
76
|
+
// Tracked/committed flag → warn only and continue normal doctor (no enforcement bypass).
|
|
77
|
+
const killSwitch = detectDeftDirectiveDisable(projectRoot, { skipTrackedCache: true });
|
|
78
|
+
if (killSwitch.present &&
|
|
79
|
+
killSwitch.trackedByGit &&
|
|
80
|
+
!isDeftDirectiveDisableActive(projectRoot, { skipTrackedCache: true })) {
|
|
81
|
+
if (!jsonMode && !quietMode) {
|
|
82
|
+
process.stderr.write(`${DEFT_DIRECTIVE_DISABLE_TRACKED_WARNING}\n`);
|
|
83
|
+
}
|
|
84
|
+
// Continue into full doctor; do not short-circuit.
|
|
85
|
+
}
|
|
86
|
+
else if (isDeftDirectiveDisableActive(projectRoot, { skipTrackedCache: true })) {
|
|
87
|
+
const optOutAlso = detectNoDeftDirective(projectRoot);
|
|
88
|
+
const message = formatDeftDirectiveDisableMessage({
|
|
89
|
+
permanentOptOutAlsoPresent: optOutAlso.present,
|
|
90
|
+
trackedByGit: false,
|
|
91
|
+
});
|
|
92
|
+
if (jsonMode) {
|
|
93
|
+
const payload = {
|
|
94
|
+
status: DEFT_DIRECTIVE_DISABLE_STATUS,
|
|
95
|
+
disabled: true,
|
|
96
|
+
disabled_via: DEFT_DIRECTIVE_DISABLE_FLAG_NAME,
|
|
97
|
+
kill_switch: true,
|
|
98
|
+
inconsistent: false,
|
|
99
|
+
deposit_present: killSwitch.depositPresent,
|
|
100
|
+
tracked_by_git: false,
|
|
101
|
+
permanent_opt_out_also_present: optOutAlso.present,
|
|
102
|
+
message,
|
|
103
|
+
};
|
|
104
|
+
process.stdout.write(`${pythonJsonDump(payload)}\n`);
|
|
105
|
+
}
|
|
106
|
+
else if (!quietMode) {
|
|
107
|
+
process.stdout.write(`${message}\n`);
|
|
108
|
+
}
|
|
109
|
+
return 0;
|
|
110
|
+
}
|
|
73
111
|
// #2926: official root opt-out — short-circuit Directive doctor when clean;
|
|
74
112
|
// diagnose flag+deposit inconsistency (warn; exit dirty).
|
|
75
113
|
const optOut = detectNoDeftDirective(projectRoot);
|
|
@@ -372,6 +410,17 @@ export function cmdDoctor(args, seams = {}) {
|
|
|
372
410
|
if (!jsonMode) {
|
|
373
411
|
sink.blank();
|
|
374
412
|
}
|
|
413
|
+
sink.info("Checking OpenClaw L2 product-command skills...");
|
|
414
|
+
runOpenClawL2AdapterCheck(sink, addFinding, {
|
|
415
|
+
projectRoot,
|
|
416
|
+
fixMode,
|
|
417
|
+
jsonMode,
|
|
418
|
+
allAgents: flags.openclawAllAgents,
|
|
419
|
+
seams,
|
|
420
|
+
});
|
|
421
|
+
if (!jsonMode) {
|
|
422
|
+
sink.blank();
|
|
423
|
+
}
|
|
375
424
|
sink.info("Checking xBRIEF project envelope version...");
|
|
376
425
|
runXbriefEnvelopeVersionCheck(projectRoot, sink, addFinding, seams);
|
|
377
426
|
let resolution = null;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Doctor check + --fix wire for OpenClaw L2 product-command skills (#3064 D5).
|
|
3
|
+
*
|
|
4
|
+
* Primary operator recovery path when OpenClaw is detected. Deposits thin
|
|
5
|
+
* user-invocable router + 13 product skills into workspace skills roots.
|
|
6
|
+
* Fail-closed when OC signals are absent. Policy opt-out:
|
|
7
|
+
* `plan.policy.openClawProductCommands: false`.
|
|
8
|
+
*/
|
|
9
|
+
import { type OpenClawL2DepositResult } from "../slash/openclaw-deposit.js";
|
|
10
|
+
import type { OutputSink } from "./output.js";
|
|
11
|
+
import type { DoctorSeams, Finding } from "./types.js";
|
|
12
|
+
/** Stable doctor check id for JSON findings. */
|
|
13
|
+
export declare const OPENCLAW_L2_ADAPTER_CHECK = "openclaw-l2-product-commands";
|
|
14
|
+
export interface RunOpenClawL2AdapterOptions {
|
|
15
|
+
readonly projectRoot: string;
|
|
16
|
+
readonly fixMode: boolean;
|
|
17
|
+
readonly jsonMode: boolean;
|
|
18
|
+
readonly allAgents: boolean;
|
|
19
|
+
readonly seams?: DoctorSeams;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Doctor check: OpenClaw L2 product-command skills present and current.
|
|
23
|
+
* No-ops when OpenClaw is not detected. Fix mode deposits managed skills.
|
|
24
|
+
*/
|
|
25
|
+
export declare function runOpenClawL2AdapterCheck(sink: OutputSink, addFinding: (finding: Finding) => void, options: RunOpenClawL2AdapterOptions): OpenClawL2DepositResult | null;
|
|
26
|
+
//# sourceMappingURL=openclaw-l2-adapter.d.ts.map
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Doctor check + --fix wire for OpenClaw L2 product-command skills (#3064 D5).
|
|
3
|
+
*
|
|
4
|
+
* Primary operator recovery path when OpenClaw is detected. Deposits thin
|
|
5
|
+
* user-invocable router + 13 product skills into workspace skills roots.
|
|
6
|
+
* Fail-closed when OC signals are absent. Policy opt-out:
|
|
7
|
+
* `plan.policy.openClawProductCommands: false`.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
10
|
+
import { homedir } from "node:os";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { generateOpenClawSkillArtifacts, isManagedOpenClawL2Skill, listOpenClawManagedSkillSlugs, } from "../slash/openclaw-adapter.js";
|
|
13
|
+
import { depositOpenClawL2ProductCommands, loadOpenClawProductCommandsPolicyFromProject, } from "../slash/openclaw-deposit.js";
|
|
14
|
+
import { detectOpenClaw, listInScopeSkillsDirs } from "./openclaw-skills.js";
|
|
15
|
+
/** Stable doctor check id for JSON findings. */
|
|
16
|
+
export const OPENCLAW_L2_ADAPTER_CHECK = "openclaw-l2-product-commands";
|
|
17
|
+
const DOC_OPENCLAW_HOST = "docs/openclaw-agent-host.md";
|
|
18
|
+
const DOC_SLASH_MULTI = "docs/slash-multi-host.md";
|
|
19
|
+
const REMEDIATION_FIX = "deft doctor --fix";
|
|
20
|
+
function defaultIsDir(path) {
|
|
21
|
+
try {
|
|
22
|
+
return statSync(path).isDirectory();
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function assessGaps(skillsDirs) {
|
|
29
|
+
const artifacts = generateOpenClawSkillArtifacts();
|
|
30
|
+
const missing = [];
|
|
31
|
+
const stale = [];
|
|
32
|
+
let present = 0;
|
|
33
|
+
for (const skillsDir of skillsDirs) {
|
|
34
|
+
for (const art of artifacts) {
|
|
35
|
+
const path = join(skillsDir, art.slug, "SKILL.md");
|
|
36
|
+
if (!existsSync(path)) {
|
|
37
|
+
missing.push(`${skillsDir}/${art.slug}`);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
let raw;
|
|
41
|
+
try {
|
|
42
|
+
raw = readFileSync(path, "utf8");
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
missing.push(`${skillsDir}/${art.slug}`);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (!isManagedOpenClawL2Skill(raw)) {
|
|
49
|
+
// Consumer customization — not a gap for doctor (preserve).
|
|
50
|
+
present += 1;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (raw === art.skillMarkdown) {
|
|
54
|
+
present += 1;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
stale.push(`${skillsDir}/${art.slug}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return { missing, stale, present };
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Doctor check: OpenClaw L2 product-command skills present and current.
|
|
65
|
+
* No-ops when OpenClaw is not detected. Fix mode deposits managed skills.
|
|
66
|
+
*/
|
|
67
|
+
export function runOpenClawL2AdapterCheck(sink, addFinding, options) {
|
|
68
|
+
const seams = options.seams ?? {};
|
|
69
|
+
const env = seams.openclawEnv ?? process.env;
|
|
70
|
+
const homeDirFn = seams.openclawHomeDir ?? (() => homedir());
|
|
71
|
+
const isDir = seams.isDir ?? defaultIsDir;
|
|
72
|
+
const home = homeDirFn();
|
|
73
|
+
const detect = detectOpenClaw(env, { homeDir: home, isDir });
|
|
74
|
+
if (!detect.detected) {
|
|
75
|
+
sink.info(`${OPENCLAW_L2_ADAPTER_CHECK}: skip -- OpenClaw not detected`);
|
|
76
|
+
addFinding({
|
|
77
|
+
severity: "skip",
|
|
78
|
+
message: "OpenClaw not detected",
|
|
79
|
+
check: OPENCLAW_L2_ADAPTER_CHECK,
|
|
80
|
+
status: "skip",
|
|
81
|
+
reason: "openclaw-not-detected",
|
|
82
|
+
});
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
const policy = loadOpenClawProductCommandsPolicyFromProject(options.projectRoot);
|
|
86
|
+
if (!policy) {
|
|
87
|
+
// Opt-out: under --fix, strip managed L2 skills so the adapter does not
|
|
88
|
+
// stay active after openClawProductCommands=false (#3064 Greptile P1).
|
|
89
|
+
let depositResult = null;
|
|
90
|
+
if (options.fixMode) {
|
|
91
|
+
depositResult = depositOpenClawL2ProductCommands({
|
|
92
|
+
projectRoot: options.projectRoot,
|
|
93
|
+
env,
|
|
94
|
+
homeDir: home,
|
|
95
|
+
allAgents: options.allAgents,
|
|
96
|
+
policy: false,
|
|
97
|
+
printf: (t) => {
|
|
98
|
+
if (!options.jsonMode)
|
|
99
|
+
sink.info(t.trimEnd());
|
|
100
|
+
},
|
|
101
|
+
isDir,
|
|
102
|
+
});
|
|
103
|
+
const message = `${OPENCLAW_L2_ADAPTER_CHECK}: opted out (plan.policy.openClawProductCommands=false); ` +
|
|
104
|
+
(depositResult.removedPaths.length > 0
|
|
105
|
+
? `removed ${depositResult.removedPaths.length} managed skill path(s)`
|
|
106
|
+
: "no managed L2 skills to remove");
|
|
107
|
+
sink.success(message);
|
|
108
|
+
addFinding({
|
|
109
|
+
severity: "skip",
|
|
110
|
+
message,
|
|
111
|
+
check: OPENCLAW_L2_ADAPTER_CHECK,
|
|
112
|
+
status: "opted-out-fixed",
|
|
113
|
+
reason: "policy-false",
|
|
114
|
+
removed: depositResult.removedPaths,
|
|
115
|
+
detect_reasons: detect.reasons,
|
|
116
|
+
});
|
|
117
|
+
return depositResult;
|
|
118
|
+
}
|
|
119
|
+
sink.info(`${OPENCLAW_L2_ADAPTER_CHECK}: skip -- plan.policy.openClawProductCommands=false`);
|
|
120
|
+
addFinding({
|
|
121
|
+
severity: "skip",
|
|
122
|
+
message: "OpenClaw L2 product commands opted out via policy; run `deft doctor --fix` to remove managed skills",
|
|
123
|
+
check: OPENCLAW_L2_ADAPTER_CHECK,
|
|
124
|
+
status: "opted-out",
|
|
125
|
+
reason: "policy-false",
|
|
126
|
+
});
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
const skillsDirs = listInScopeSkillsDirs(detect.stateDir, options.allAgents, {
|
|
130
|
+
isDir,
|
|
131
|
+
});
|
|
132
|
+
const gaps = assessGaps(skillsDirs);
|
|
133
|
+
const expectedCount = listOpenClawManagedSkillSlugs().length * skillsDirs.length;
|
|
134
|
+
if (gaps.missing.length === 0 && gaps.stale.length === 0) {
|
|
135
|
+
const message = `${OPENCLAW_L2_ADAPTER_CHECK}: OpenClaw L2 product-command skills present ` +
|
|
136
|
+
`(router + 13) in ${options.allAgents ? "main + workspace-* seats" : "main workspace"}`;
|
|
137
|
+
sink.success(message);
|
|
138
|
+
addFinding({
|
|
139
|
+
severity: "skip",
|
|
140
|
+
message,
|
|
141
|
+
check: OPENCLAW_L2_ADAPTER_CHECK,
|
|
142
|
+
status: "present",
|
|
143
|
+
skills_dirs: skillsDirs,
|
|
144
|
+
expected: expectedCount,
|
|
145
|
+
present: gaps.present,
|
|
146
|
+
detect_reasons: detect.reasons,
|
|
147
|
+
});
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
let depositResult = null;
|
|
151
|
+
if (options.fixMode) {
|
|
152
|
+
depositResult = depositOpenClawL2ProductCommands({
|
|
153
|
+
projectRoot: options.projectRoot,
|
|
154
|
+
env,
|
|
155
|
+
homeDir: home,
|
|
156
|
+
allAgents: options.allAgents,
|
|
157
|
+
policy: true,
|
|
158
|
+
printf: (t) => {
|
|
159
|
+
if (!options.jsonMode)
|
|
160
|
+
sink.info(t.trimEnd());
|
|
161
|
+
},
|
|
162
|
+
isDir,
|
|
163
|
+
});
|
|
164
|
+
const post = assessGaps(skillsDirs);
|
|
165
|
+
if (post.missing.length === 0 && post.stale.length === 0) {
|
|
166
|
+
const message = `${OPENCLAW_L2_ADAPTER_CHECK}: deposited OpenClaw L2 product-command skills; ` +
|
|
167
|
+
"restart the OpenClaw gateway or start a new session so available_skills refreshes";
|
|
168
|
+
sink.success(message);
|
|
169
|
+
addFinding({
|
|
170
|
+
severity: "skip",
|
|
171
|
+
message,
|
|
172
|
+
check: OPENCLAW_L2_ADAPTER_CHECK,
|
|
173
|
+
status: "fixed",
|
|
174
|
+
skills_dirs: skillsDirs,
|
|
175
|
+
written: depositResult.writtenPaths,
|
|
176
|
+
detect_reasons: detect.reasons,
|
|
177
|
+
});
|
|
178
|
+
return depositResult;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const message = `${OPENCLAW_L2_ADAPTER_CHECK}: OpenClaw L2 product-command skills incomplete ` +
|
|
182
|
+
`(missing: ${gaps.missing.length}, stale: ${gaps.stale.length}) under ${skillsDirs.join(", ")}. ` +
|
|
183
|
+
`Remediation: ${REMEDIATION_FIX}. See ${DOC_OPENCLAW_HOST}, ${DOC_SLASH_MULTI}.`;
|
|
184
|
+
sink.warn(message);
|
|
185
|
+
addFinding({
|
|
186
|
+
severity: "warning",
|
|
187
|
+
message,
|
|
188
|
+
check: OPENCLAW_L2_ADAPTER_CHECK,
|
|
189
|
+
status: "missing",
|
|
190
|
+
missing: gaps.missing,
|
|
191
|
+
stale: gaps.stale,
|
|
192
|
+
skills_dirs: skillsDirs,
|
|
193
|
+
suggestion: REMEDIATION_FIX,
|
|
194
|
+
docs: [DOC_OPENCLAW_HOST, DOC_SLASH_MULTI],
|
|
195
|
+
detect_reasons: detect.reasons,
|
|
196
|
+
});
|
|
197
|
+
return depositResult;
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=openclaw-l2-adapter.js.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type AuthzState, type HumanOriginGrant } from "../authz/index.js";
|
|
2
|
+
import { detectDeftDirectiveDisable } from "../policy/deft-directive-disable.js";
|
|
2
3
|
import { detectNoDeftDirective } from "../policy/no-deft-directive.js";
|
|
3
4
|
import { type RuntimeAuthorityPolicy } from "../policy/runtime-authority.js";
|
|
4
5
|
import { type VerifyResult } from "../session/verify-session-ritual.js";
|
|
@@ -16,7 +17,9 @@ export type CompactHookHost = (typeof COMPACT_HOOK_HOSTS)[number];
|
|
|
16
17
|
/** Hosts without a native compact hook surface — deposit skips cleanly (#2113). */
|
|
17
18
|
export declare const COMPACT_HOOK_SKIP_HOSTS: readonly ["codex"];
|
|
18
19
|
export type HookVerdict = "allow" | "deny";
|
|
19
|
-
export type HookDecisionCode = "session-start" | "session-start-disabled" | "session-start-degraded"
|
|
20
|
+
export type HookDecisionCode = "session-start" | "session-start-disabled" | "session-start-degraded"
|
|
21
|
+
/** Enforcement skipped: root `.deft-directive-disable` test kill-switch (#3039). */
|
|
22
|
+
| "directive-disabled" | "session-compact-rearm" | "session-compact-rearm-degraded" | "session-compact-noop" | "not-direct-write" | "invalid-input"
|
|
20
23
|
/** Host closed stdin with zero bytes — integration failure, not a policy gate (#2864). */
|
|
21
24
|
| "stdin-empty" | "ritual-not-ready" | "scope-not-ready" | "write-propose-ready" | "write-ready" | "read-only-deny" | "spawn-explore-ready" | "spawn-ready" | "spawn-not-ready" | "runtime-policy-deny-path" | "runtime-policy-deny-scope"
|
|
22
25
|
/** Shell/MCP classifiable push/merge allowed under runtimeAuthority (#2711). */
|
|
@@ -56,6 +59,8 @@ export interface HookPolicySeams {
|
|
|
56
59
|
};
|
|
57
60
|
/** Test seam for #2926 root opt-out on SessionStart. */
|
|
58
61
|
readonly detectNoDeftDirective?: typeof detectNoDeftDirective;
|
|
62
|
+
/** Test seam for #3039 root test kill-switch (precedence over #2926 for enforcement). */
|
|
63
|
+
readonly detectDeftDirectiveDisable?: typeof detectDeftDirectiveDisable;
|
|
59
64
|
readonly markCompactStale?: (projectRoot: string) => {
|
|
60
65
|
changed: boolean;
|
|
61
66
|
statePath: string;
|
package/dist/hooks/dispatcher.js
CHANGED
|
@@ -2,6 +2,7 @@ import { realpathSync } from "node:fs";
|
|
|
2
2
|
import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
3
3
|
import { appendAuthzAudit, classifyHookAuthzOps, evaluateAuthzMutation, evidenceSatisfiesImplementationApproval, listActiveHumanGrants, loadAuthzStateResult, markGrantUsed, shouldConsumeSingleUseGrant, utcIso, } from "../authz/index.js";
|
|
4
4
|
import { hasArtifactSuffix } from "../layout/resolve.js";
|
|
5
|
+
import { detectDeftDirectiveDisable, formatDeftDirectiveDisableMessage, isDeftDirectiveDisableActive, } from "../policy/deft-directive-disable.js";
|
|
5
6
|
import { evaluateIntentCeilingFromEnv } from "../policy/intent-ceiling.js";
|
|
6
7
|
import { detectNoDeftDirective, NO_DEFT_DIRECTIVE_DISABLED_MESSAGE, NO_DEFT_DIRECTIVE_INCONSISTENT_MESSAGE, } from "../policy/no-deft-directive.js";
|
|
7
8
|
import { classifyMcpTool, DEFAULT_RUNTIME_AUTHORITY_POLICY, evaluateRuntimeAuthorityDirectWrite, evaluateRuntimeAuthorityShellOp, listShellOps, loadRuntimeAuthorityFromProject, } from "../policy/runtime-authority.js";
|
|
@@ -570,6 +571,35 @@ function inspectMutationGates(input, toolName, seams, options) {
|
|
|
570
571
|
/** Decide a normalized event using only the P0 direct-write policy. */
|
|
571
572
|
export function decideHook(input, seams = {}) {
|
|
572
573
|
const projectRoot = resolve(input.projectRoot);
|
|
574
|
+
// #3039: local (untracked) `.deft-directive-disable` wins for enforcement
|
|
575
|
+
// short-circuit (SessionStart / compact / PreToolUse). Deposit may remain.
|
|
576
|
+
// Tracked/committed flags do NOT bypass gates (repo-controlled content must
|
|
577
|
+
// not disable enforcement for clones) — doctor warns instead.
|
|
578
|
+
{
|
|
579
|
+
const detectKill = seams.detectDeftDirectiveDisable ?? detectDeftDirectiveDisable;
|
|
580
|
+
const kill = detectKill(projectRoot);
|
|
581
|
+
const killActive = seams.detectDeftDirectiveDisable !== undefined
|
|
582
|
+
? kill.active
|
|
583
|
+
: isDeftDirectiveDisableActive(projectRoot);
|
|
584
|
+
if (killActive) {
|
|
585
|
+
const detectOptOut = seams.detectNoDeftDirective ?? detectNoDeftDirective;
|
|
586
|
+
const optOut = detectOptOut(projectRoot);
|
|
587
|
+
const message = formatDeftDirectiveDisableMessage({
|
|
588
|
+
permanentOptOutAlsoPresent: optOut.present,
|
|
589
|
+
trackedByGit: false,
|
|
590
|
+
});
|
|
591
|
+
return {
|
|
592
|
+
verdict: "allow",
|
|
593
|
+
code: input.event === "session.start" ? "session-start-disabled" : "directive-disabled",
|
|
594
|
+
event: input.event,
|
|
595
|
+
host: input.host,
|
|
596
|
+
toolName: null,
|
|
597
|
+
projectRoot,
|
|
598
|
+
message,
|
|
599
|
+
scopePath: null,
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
}
|
|
573
603
|
if (input.event === "session.compact") {
|
|
574
604
|
try {
|
|
575
605
|
const result = (seams.markCompactStale ?? markRitualStaleAfterCompact)(projectRoot);
|
package/dist/index.d.ts
CHANGED
|
@@ -50,6 +50,7 @@ export * as resolution from "./resolution/index.js";
|
|
|
50
50
|
export * as scm from "./scm/index.js";
|
|
51
51
|
export * as scope from "./scope/index.js";
|
|
52
52
|
export * as session from "./session/index.js";
|
|
53
|
+
export * as slash from "./slash/index.js";
|
|
53
54
|
export * as slice from "./slice/index.js";
|
|
54
55
|
export * as storyReady from "./story-ready/index.js";
|
|
55
56
|
export * as swarm from "./swarm/index.js";
|
|
@@ -65,6 +66,7 @@ export * as vbriefValidation from "./vbrief-validation/index.js";
|
|
|
65
66
|
export * as verifyEnv from "./verify-env/index.js";
|
|
66
67
|
export * as verifySource from "./verify-source/index.js";
|
|
67
68
|
export * as wipCap from "./wip-cap/index.js";
|
|
69
|
+
export * as xbrief from "./xbrief/index.js";
|
|
68
70
|
export * as xbriefMigrate from "./xbrief-migrate/index.js";
|
|
69
71
|
export declare const CORE_PACKAGE: "@deftai/directive-core";
|
|
70
72
|
/** Returns identifying metadata for the core engine package. */
|
package/dist/index.js
CHANGED
|
@@ -51,6 +51,7 @@ export * as resolution from "./resolution/index.js";
|
|
|
51
51
|
export * as scm from "./scm/index.js";
|
|
52
52
|
export * as scope from "./scope/index.js";
|
|
53
53
|
export * as session from "./session/index.js";
|
|
54
|
+
export * as slash from "./slash/index.js";
|
|
54
55
|
export * as slice from "./slice/index.js";
|
|
55
56
|
export * as storyReady from "./story-ready/index.js";
|
|
56
57
|
export * as swarm from "./swarm/index.js";
|
|
@@ -66,6 +67,7 @@ export * as vbriefValidation from "./vbrief-validation/index.js";
|
|
|
66
67
|
export * as verifyEnv from "./verify-env/index.js";
|
|
67
68
|
export * as verifySource from "./verify-source/index.js";
|
|
68
69
|
export * as wipCap from "./wip-cap/index.js";
|
|
70
|
+
export * as xbrief from "./xbrief/index.js";
|
|
69
71
|
export * as xbriefMigrate from "./xbrief-migrate/index.js";
|
|
70
72
|
export const CORE_PACKAGE = "@deftai/directive-core";
|
|
71
73
|
/** Returns identifying metadata for the core engine package. */
|
|
@@ -13,6 +13,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
13
13
|
import { join, resolve } from "node:path";
|
|
14
14
|
import { containedWrite } from "../fs/contained-write.js";
|
|
15
15
|
import { assertWriteTargetSafe, ProjectionContainmentError } from "../fs/projection-containment.js";
|
|
16
|
+
import { DEFT_DIRECTIVE_DISABLE_GITIGNORE_LINE } from "../policy/deft-directive-disable.js";
|
|
16
17
|
import { FORBIDDEN_BLANKET_EVAL_LINES, stripGitignoreInlineComment, } from "../triage/bootstrap/gitignore.js";
|
|
17
18
|
/** Directory ignore entry for the hybrid deposit (greenfield only). */
|
|
18
19
|
export const GITIGNORE_DEFT_CORE_LINE = ".deft/core/";
|
|
@@ -29,6 +30,8 @@ export const CANONICAL_GITIGNORE_BASELINE = [
|
|
|
29
30
|
".deft/ritual-state.json",
|
|
30
31
|
".deft/last-session.json",
|
|
31
32
|
".deft/routing.local.json",
|
|
33
|
+
// Temporary test/local kill-switch — must stay untracked (#3039).
|
|
34
|
+
DEFT_DIRECTIVE_DISABLE_GITIGNORE_LINE,
|
|
32
35
|
"vbrief/.triage-cache/candidates.jsonl",
|
|
33
36
|
"vbrief/.triage-cache/summary-history.jsonl",
|
|
34
37
|
"vbrief/.triage-cache/scope-lifecycle.jsonl",
|
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
* Scoped staging + installer-managed allowlist for TS-native init/update (#1453).
|
|
3
3
|
*
|
|
4
4
|
* Mirrors cmd/deft-install/hygiene.go + deposit.go installerManagedMatchers.
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
|
+
* CRITICAL (#1430 / #3030): the allowlist MUST honor the SPEC consumer-path
|
|
7
|
+
* denylist (`CONSUMER_GUARD_MUST_FIRE`). Consumer-authored PROJECT-DEFINITION
|
|
8
|
+
* and scope briefs are never installer-managed; if they reappear in
|
|
9
|
+
* `installerManagedMatchers()`, unit tests and deposit-time assert fail closed.
|
|
10
|
+
*
|
|
11
|
+
* Refs #1576, #1453, #1430, #3029, #3030.
|
|
6
12
|
*/
|
|
7
13
|
import { type InitDepositIo } from "./constants.js";
|
|
8
14
|
export declare const CODEQL_CONFIG_REL = ".github/codeql/codeql-config.yml";
|
|
@@ -11,11 +17,47 @@ export interface InstallerManagedMatcher {
|
|
|
11
17
|
readonly exact?: string;
|
|
12
18
|
readonly prefix?: string;
|
|
13
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Consumer paths that MUST trip no-mixed-core-and-app when mixed with
|
|
22
|
+
* `.deft/core/**` (#1430 SPEC). These probe paths must never match
|
|
23
|
+
* `installerManagedMatchers()` / the deposited guard ERE.
|
|
24
|
+
*
|
|
25
|
+
* Legitimate installer scaffolding (xbrief/.deft-version, lifecycle .gitkeep,
|
|
26
|
+
* schemas/, migration/, xbrief.md) is NOT in this denylist — see #2277.
|
|
27
|
+
* Init may still *create* PROJECT-DEFINITION (#3013); create ≠ allowlist.
|
|
28
|
+
*
|
|
29
|
+
* Refs #3030, #3029, #1430.
|
|
30
|
+
*/
|
|
31
|
+
export declare const CONSUMER_GUARD_MUST_FIRE: readonly string[];
|
|
14
32
|
/** Single source of truth for installer-managed paths (#1440 / #1576). */
|
|
15
33
|
export declare function installerManagedMatchers(): InstallerManagedMatcher[];
|
|
34
|
+
/**
|
|
35
|
+
* Fail closed when the installer-managed allowlist would exempt consumer
|
|
36
|
+
* PROJECT-DEFINITION or scope briefs (#3030 / #1430). Pure over `matchers` so
|
|
37
|
+
* tests can inject a bad matcher without mutating production state.
|
|
38
|
+
*
|
|
39
|
+
* Checks both:
|
|
40
|
+
* 1. Explicit probe paths in {@link CONSUMER_GUARD_MUST_FIRE}
|
|
41
|
+
* 2. Structural patterns (any exact consumer scope brief / PD; forbidden prefixes)
|
|
42
|
+
* so an unlisted `xbrief/active/another-scope.xbrief.json` matcher still fails.
|
|
43
|
+
*/
|
|
44
|
+
export declare function assertInstallerAllowlistHonors1430(matchers?: readonly InstallerManagedMatcher[]): void;
|
|
16
45
|
/** POSIX ERE alternation embedded in the deposited deft-core-guard workflow. */
|
|
17
46
|
export declare function installerManagedGuardEre(): string;
|
|
18
47
|
export declare function isInstallerManagedPath(path: string): boolean;
|
|
48
|
+
export interface MixedCoreAndAppClassification {
|
|
49
|
+
readonly core: string[];
|
|
50
|
+
readonly installerManaged: string[];
|
|
51
|
+
readonly app: string[];
|
|
52
|
+
/** True when both core and app are non-empty — the deposited guard fails. */
|
|
53
|
+
readonly wouldFail: boolean;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* TS twin of Go `classifyChangedPaths` / deposited shell guard (#1430).
|
|
57
|
+
* Core = `.deft/core/**`; installer-managed = allowlist; app = everything else.
|
|
58
|
+
* Guard fails iff both core and app are non-empty.
|
|
59
|
+
*/
|
|
60
|
+
export declare function classifyMixedCoreAndApp(changedPaths: readonly string[], matchers?: readonly InstallerManagedMatcher[]): MixedCoreAndAppClassification;
|
|
19
61
|
export interface FrameworkStagePathsOptions {
|
|
20
62
|
/**
|
|
21
63
|
* Include the vendored `.deft/core` payload in the stage set. Defaults to
|