@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
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-host slash-command deposit policy (#3054 / epic #55 L6).
|
|
3
|
+
*
|
|
4
|
+
* Parallel to {@link plan.policy.hostHooks}: default multi-host enablement for
|
|
5
|
+
* every host that has a real emitter (no stubs). Per-host `false` opts out.
|
|
6
|
+
*/
|
|
7
|
+
import { type SlashEmitterHostId } from "../slash/emitters.js";
|
|
8
|
+
export declare const FIELD_HOST_SLASH_COMMANDS = "plan.policy.hostSlashCommands";
|
|
9
|
+
export declare const FIELD_HOST_SLASH_COMMANDS_CLI_ALIAS = "hostSlashCommands";
|
|
10
|
+
/** Per-host Directive slash-command deposit toggles (#3054). */
|
|
11
|
+
export type HostSlashCommandsPolicy = Record<SlashEmitterHostId, boolean>;
|
|
12
|
+
/** Default = all hosts with real emitters enabled (L6; not single-host-only). */
|
|
13
|
+
export declare const DEFAULT_HOST_SLASH_COMMANDS_POLICY: HostSlashCommandsPolicy;
|
|
14
|
+
export interface HostSlashCommandsPolicyField {
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly current: HostSlashCommandsPolicy;
|
|
17
|
+
readonly default: HostSlashCommandsPolicy;
|
|
18
|
+
readonly source: string;
|
|
19
|
+
}
|
|
20
|
+
/** Resolve typed slash-command deposit policy from raw PROJECT-DEFINITION value. */
|
|
21
|
+
export declare function resolveHostSlashCommandsPolicy(raw: unknown): HostSlashCommandsPolicy;
|
|
22
|
+
export declare function validateHostSlashCommands(value: unknown): string[];
|
|
23
|
+
export declare function isHostSlashCommandDepositEnabled(host: SlashEmitterHostId, policy?: HostSlashCommandsPolicy): boolean;
|
|
24
|
+
/** Inspector row for `policy:show --field=hostSlashCommands`. */
|
|
25
|
+
export declare function inspectHostSlashCommands(data: Record<string, unknown> | null): HostSlashCommandsPolicyField;
|
|
26
|
+
/** Resolve slash-command deposit policy from PROJECT-DEFINITION on disk. */
|
|
27
|
+
export declare function loadHostSlashCommandsPolicyFromProject(projectRoot: string): HostSlashCommandsPolicy;
|
|
28
|
+
//# sourceMappingURL=host-slash-commands.d.ts.map
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-host slash-command deposit policy (#3054 / epic #55 L6).
|
|
3
|
+
*
|
|
4
|
+
* Parallel to {@link plan.policy.hostHooks}: default multi-host enablement for
|
|
5
|
+
* every host that has a real emitter (no stubs). Per-host `false` opts out.
|
|
6
|
+
*/
|
|
7
|
+
import { isSlashEmitterHostId, SLASH_EMITTER_HOSTS, } from "../slash/emitters.js";
|
|
8
|
+
import { readPlanPolicy } from "./plan-extensions.js";
|
|
9
|
+
import { loadProjectDefinition } from "./resolve.js";
|
|
10
|
+
export const FIELD_HOST_SLASH_COMMANDS = "plan.policy.hostSlashCommands";
|
|
11
|
+
export const FIELD_HOST_SLASH_COMMANDS_CLI_ALIAS = "hostSlashCommands";
|
|
12
|
+
/** Default = all hosts with real emitters enabled (L6; not single-host-only). */
|
|
13
|
+
export const DEFAULT_HOST_SLASH_COMMANDS_POLICY = Object.freeze({
|
|
14
|
+
claude: true,
|
|
15
|
+
cursor: true,
|
|
16
|
+
grok: true,
|
|
17
|
+
codex: true,
|
|
18
|
+
});
|
|
19
|
+
function readHostBoolean(rec, host, fallback) {
|
|
20
|
+
if (host in rec && typeof rec[host] === "boolean") {
|
|
21
|
+
return rec[host];
|
|
22
|
+
}
|
|
23
|
+
return fallback;
|
|
24
|
+
}
|
|
25
|
+
/** Resolve typed slash-command deposit policy from raw PROJECT-DEFINITION value. */
|
|
26
|
+
export function resolveHostSlashCommandsPolicy(raw) {
|
|
27
|
+
if (raw === null || raw === undefined) {
|
|
28
|
+
return { ...DEFAULT_HOST_SLASH_COMMANDS_POLICY };
|
|
29
|
+
}
|
|
30
|
+
if (typeof raw !== "object" || Array.isArray(raw)) {
|
|
31
|
+
return { ...DEFAULT_HOST_SLASH_COMMANDS_POLICY };
|
|
32
|
+
}
|
|
33
|
+
const rec = raw;
|
|
34
|
+
return {
|
|
35
|
+
claude: readHostBoolean(rec, "claude", DEFAULT_HOST_SLASH_COMMANDS_POLICY.claude),
|
|
36
|
+
cursor: readHostBoolean(rec, "cursor", DEFAULT_HOST_SLASH_COMMANDS_POLICY.cursor),
|
|
37
|
+
grok: readHostBoolean(rec, "grok", DEFAULT_HOST_SLASH_COMMANDS_POLICY.grok),
|
|
38
|
+
codex: readHostBoolean(rec, "codex", DEFAULT_HOST_SLASH_COMMANDS_POLICY.codex),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export function validateHostSlashCommands(value) {
|
|
42
|
+
if (value === null || value === undefined) {
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
if (typeof value !== "object" || Array.isArray(value)) {
|
|
46
|
+
return [`${FIELD_HOST_SLASH_COMMANDS} must be an object; got ${typeof value}`];
|
|
47
|
+
}
|
|
48
|
+
const rec = value;
|
|
49
|
+
const errors = [];
|
|
50
|
+
for (const host of SLASH_EMITTER_HOSTS) {
|
|
51
|
+
if (host in rec && typeof rec[host] !== "boolean") {
|
|
52
|
+
errors.push(`${FIELD_HOST_SLASH_COMMANDS}.${host} must be a boolean`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
for (const key of Object.keys(rec)) {
|
|
56
|
+
if (!isSlashEmitterHostId(key)) {
|
|
57
|
+
errors.push(`${FIELD_HOST_SLASH_COMMANDS}.${key} is not a slash emitter host (${SLASH_EMITTER_HOSTS.join(", ")})`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return errors;
|
|
61
|
+
}
|
|
62
|
+
export function isHostSlashCommandDepositEnabled(host, policy = DEFAULT_HOST_SLASH_COMMANDS_POLICY) {
|
|
63
|
+
return policy[host];
|
|
64
|
+
}
|
|
65
|
+
function fieldFromResolved(resolved, source) {
|
|
66
|
+
return {
|
|
67
|
+
name: FIELD_HOST_SLASH_COMMANDS,
|
|
68
|
+
current: resolved,
|
|
69
|
+
default: { ...DEFAULT_HOST_SLASH_COMMANDS_POLICY },
|
|
70
|
+
source,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/** Inspector row for `policy:show --field=hostSlashCommands`. */
|
|
74
|
+
export function inspectHostSlashCommands(data) {
|
|
75
|
+
if (data === null) {
|
|
76
|
+
return fieldFromResolved({ ...DEFAULT_HOST_SLASH_COMMANDS_POLICY }, "default");
|
|
77
|
+
}
|
|
78
|
+
const policyBlock = readPlanPolicy(data.plan);
|
|
79
|
+
if (typeof policyBlock !== "object" ||
|
|
80
|
+
policyBlock === null ||
|
|
81
|
+
Array.isArray(policyBlock) ||
|
|
82
|
+
!("hostSlashCommands" in policyBlock)) {
|
|
83
|
+
return fieldFromResolved({ ...DEFAULT_HOST_SLASH_COMMANDS_POLICY }, "default");
|
|
84
|
+
}
|
|
85
|
+
const resolved = resolveHostSlashCommandsPolicy(policyBlock.hostSlashCommands);
|
|
86
|
+
return fieldFromResolved(resolved, "typed");
|
|
87
|
+
}
|
|
88
|
+
/** Resolve slash-command deposit policy from PROJECT-DEFINITION on disk. */
|
|
89
|
+
export function loadHostSlashCommandsPolicyFromProject(projectRoot) {
|
|
90
|
+
const [data] = loadProjectDefinition(projectRoot);
|
|
91
|
+
if (data === null) {
|
|
92
|
+
return { ...DEFAULT_HOST_SLASH_COMMANDS_POLICY };
|
|
93
|
+
}
|
|
94
|
+
const policyBlock = readPlanPolicy(data.plan);
|
|
95
|
+
if (typeof policyBlock !== "object" ||
|
|
96
|
+
policyBlock === null ||
|
|
97
|
+
Array.isArray(policyBlock) ||
|
|
98
|
+
!("hostSlashCommands" in policyBlock)) {
|
|
99
|
+
return { ...DEFAULT_HOST_SLASH_COMMANDS_POLICY };
|
|
100
|
+
}
|
|
101
|
+
return resolveHostSlashCommandsPolicy(policyBlock.hostSlashCommands);
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=host-slash-commands.js.map
|
package/dist/policy/index.d.ts
CHANGED
|
@@ -2,8 +2,11 @@ export * from "./agents-md-advisory.js";
|
|
|
2
2
|
export * from "./autonomy.js";
|
|
3
3
|
export * from "./capacity.js";
|
|
4
4
|
export * from "./decisions.js";
|
|
5
|
+
export * from "./deft-directive-disable.js";
|
|
6
|
+
export * from "./delivery-branch.js";
|
|
5
7
|
export * from "./disclosure.js";
|
|
6
8
|
export * from "./host-hooks.js";
|
|
9
|
+
export * from "./host-slash-commands.js";
|
|
7
10
|
export * from "./hotfix-criteria.js";
|
|
8
11
|
export * from "./intent-ceiling.js";
|
|
9
12
|
export * from "./no-deft-directive.js";
|
package/dist/policy/index.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import { FIELD_HOST_SKILL_DISCOVERY, FIELD_HOST_SKILL_DISCOVERY_CLI_ALIAS, inspectHostSkillDiscovery, } from "../init-deposit/skill-discovery-hosts.js";
|
|
2
|
+
import { FIELD_OPENCLAW_PRODUCT_COMMANDS, FIELD_OPENCLAW_PRODUCT_COMMANDS_CLI_ALIAS, inspectOpenClawProductCommands, } from "../slash/openclaw-deposit.js";
|
|
3
|
+
import { FIELD_DELIVERY_BRANCH, FIELD_DELIVERY_BRANCH_CLI_ALIAS, inspectDeliveryBranch, } from "./delivery-branch.js";
|
|
1
4
|
import { FIELD_HOST_HOOKS, FIELD_HOST_HOOKS_CLI_ALIAS, inspectHostHooks } from "./host-hooks.js";
|
|
5
|
+
import { FIELD_HOST_SLASH_COMMANDS, FIELD_HOST_SLASH_COMMANDS_CLI_ALIAS, inspectHostSlashCommands, } from "./host-slash-commands.js";
|
|
2
6
|
import { FIELD_HOTFIX_CRITERIA, FIELD_HOTFIX_CRITERIA_CLI_ALIAS, inspectHotfixCriteria, } from "./hotfix-criteria.js";
|
|
3
7
|
import { readPlanPolicy } from "./plan-extensions.js";
|
|
4
8
|
import { FIELD_PRODUCT_SIGNAL, FIELD_PRODUCT_SIGNAL_CLI_ALIAS, inspectProductSignal, } from "./product-signal.js";
|
|
@@ -12,8 +16,11 @@ export * from "./agents-md-advisory.js";
|
|
|
12
16
|
export * from "./autonomy.js";
|
|
13
17
|
export * from "./capacity.js";
|
|
14
18
|
export * from "./decisions.js";
|
|
19
|
+
export * from "./deft-directive-disable.js";
|
|
20
|
+
export * from "./delivery-branch.js";
|
|
15
21
|
export * from "./disclosure.js";
|
|
16
22
|
export * from "./host-hooks.js";
|
|
23
|
+
export * from "./host-slash-commands.js";
|
|
17
24
|
export * from "./hotfix-criteria.js";
|
|
18
25
|
export * from "./intent-ceiling.js";
|
|
19
26
|
export * from "./no-deft-directive.js";
|
|
@@ -38,6 +45,7 @@ export const FIELD_TRIAGE_RANKING_LABELS = "plan.policy.triageRankingLabels";
|
|
|
38
45
|
export const FIELD_TRIAGE_AUTO_CLASSIFY = "plan.policy.triageAutoClassify";
|
|
39
46
|
export const FIELD_TRIAGE_HOLD_MARKERS = "plan.policy.triageHoldMarkers";
|
|
40
47
|
export const FIELD_SWARM_SUBAGENT_BACKEND = "plan.policy.swarmSubagentBackend";
|
|
48
|
+
// deliveryBranch also exported from delivery-branch.js via export *
|
|
41
49
|
export const DEFAULT_SESSION_RITUAL_STALENESS_HOURS = 4;
|
|
42
50
|
export const DEFAULT_TRIAGE_SCOPE_VALUE = [
|
|
43
51
|
{ rule: "all-open" },
|
|
@@ -278,6 +286,33 @@ function inspectHostHooksField(data) {
|
|
|
278
286
|
source: field.source,
|
|
279
287
|
};
|
|
280
288
|
}
|
|
289
|
+
function inspectHostSlashCommandsField(data) {
|
|
290
|
+
const field = inspectHostSlashCommands(data);
|
|
291
|
+
return {
|
|
292
|
+
name: field.name,
|
|
293
|
+
current: field.current,
|
|
294
|
+
default: field.default,
|
|
295
|
+
source: field.source,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
function inspectOpenClawProductCommandsField(data) {
|
|
299
|
+
const field = inspectOpenClawProductCommands(data);
|
|
300
|
+
return {
|
|
301
|
+
name: field.name,
|
|
302
|
+
current: field.current,
|
|
303
|
+
default: field.default,
|
|
304
|
+
source: field.source,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
function inspectHostSkillDiscoveryField(data) {
|
|
308
|
+
const field = inspectHostSkillDiscovery(data);
|
|
309
|
+
return {
|
|
310
|
+
name: field.name,
|
|
311
|
+
current: field.current,
|
|
312
|
+
default: field.default,
|
|
313
|
+
source: field.source,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
281
316
|
function inspectRequireHumanMergeField(data, projectRoot) {
|
|
282
317
|
const field = inspectRequireHumanMerge(data, projectRoot);
|
|
283
318
|
return {
|
|
@@ -296,6 +331,15 @@ function inspectHotfixCriteriaField(data) {
|
|
|
296
331
|
source: field.source,
|
|
297
332
|
};
|
|
298
333
|
}
|
|
334
|
+
function inspectDeliveryBranchField(data, projectRoot) {
|
|
335
|
+
const field = inspectDeliveryBranch(data, projectRoot);
|
|
336
|
+
return {
|
|
337
|
+
name: field.name,
|
|
338
|
+
current: field.current,
|
|
339
|
+
default: field.default,
|
|
340
|
+
source: field.source,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
299
343
|
const REGISTERED_POLICIES = [
|
|
300
344
|
inspectAllowDirectCommits,
|
|
301
345
|
inspectWipCap,
|
|
@@ -308,7 +352,11 @@ const REGISTERED_POLICIES = [
|
|
|
308
352
|
emptyIsTyped: true,
|
|
309
353
|
}),
|
|
310
354
|
inspectSwarmSubagentBackend,
|
|
355
|
+
inspectDeliveryBranchField,
|
|
311
356
|
inspectHostHooksField,
|
|
357
|
+
inspectHostSlashCommandsField,
|
|
358
|
+
inspectOpenClawProductCommandsField,
|
|
359
|
+
inspectHostSkillDiscoveryField,
|
|
312
360
|
inspectStalenessTicklerField,
|
|
313
361
|
inspectRuntimeAuthorityField,
|
|
314
362
|
inspectProductSignalField,
|
|
@@ -333,11 +381,19 @@ export function inspectOnePolicy(name, projectRoot) {
|
|
|
333
381
|
? FIELD_RUNTIME_AUTHORITY
|
|
334
382
|
: name === FIELD_HOST_HOOKS_CLI_ALIAS
|
|
335
383
|
? FIELD_HOST_HOOKS
|
|
336
|
-
: name ===
|
|
337
|
-
?
|
|
338
|
-
: name ===
|
|
339
|
-
?
|
|
340
|
-
: name
|
|
384
|
+
: name === FIELD_HOST_SLASH_COMMANDS_CLI_ALIAS
|
|
385
|
+
? FIELD_HOST_SLASH_COMMANDS
|
|
386
|
+
: name === FIELD_OPENCLAW_PRODUCT_COMMANDS_CLI_ALIAS
|
|
387
|
+
? FIELD_OPENCLAW_PRODUCT_COMMANDS
|
|
388
|
+
: name === FIELD_HOST_SKILL_DISCOVERY_CLI_ALIAS
|
|
389
|
+
? FIELD_HOST_SKILL_DISCOVERY
|
|
390
|
+
: name === FIELD_REQUIRE_HUMAN_MERGE_CLI_ALIAS
|
|
391
|
+
? FIELD_REQUIRE_HUMAN_MERGE
|
|
392
|
+
: name === FIELD_HOTFIX_CRITERIA_CLI_ALIAS
|
|
393
|
+
? FIELD_HOTFIX_CRITERIA
|
|
394
|
+
: name === FIELD_DELIVERY_BRANCH_CLI_ALIAS
|
|
395
|
+
? FIELD_DELIVERY_BRANCH
|
|
396
|
+
: name;
|
|
341
397
|
for (const field of inspectAllPolicies(projectRoot)) {
|
|
342
398
|
if (field.name === normalized)
|
|
343
399
|
return field;
|
package/dist/scope/brief-io.d.ts
CHANGED
|
@@ -22,5 +22,7 @@ export type AtomicWriteBriefResult = {
|
|
|
22
22
|
readonly message: string;
|
|
23
23
|
};
|
|
24
24
|
/** Validate then atomically persist a brief (temp file + rename). */
|
|
25
|
-
export declare function atomicWriteBrief(filePath: string, data: JsonObject, vbriefRoot: string
|
|
25
|
+
export declare function atomicWriteBrief(filePath: string, data: JsonObject, vbriefRoot: string, options?: {
|
|
26
|
+
readonly projectRoot?: string;
|
|
27
|
+
}): AtomicWriteBriefResult;
|
|
26
28
|
//# sourceMappingURL=brief-io.d.ts.map
|
package/dist/scope/brief-io.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
-
import { resolve } from "node:path";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
3
|
import { atomicWriteText } from "../cache/io.js";
|
|
4
4
|
import { hasArtifactSuffix } from "../layout/resolve.js";
|
|
5
5
|
import { pythonJsonPretty } from "../vbrief-build/json.js";
|
|
@@ -60,13 +60,15 @@ export function validateBriefForPersist(filePath, data, vbriefRoot) {
|
|
|
60
60
|
return errors.join("; ");
|
|
61
61
|
}
|
|
62
62
|
/** Validate then atomically persist a brief (temp file + rename). */
|
|
63
|
-
export function atomicWriteBrief(filePath, data, vbriefRoot) {
|
|
63
|
+
export function atomicWriteBrief(filePath, data, vbriefRoot, options = {}) {
|
|
64
64
|
const validationError = validateBriefForPersist(filePath, data, vbriefRoot);
|
|
65
65
|
if (validationError !== null) {
|
|
66
66
|
return { ok: false, message: validationError };
|
|
67
67
|
}
|
|
68
|
+
// #3042: contain against projectRoot (parent of xbrief/), not dirname(filePath).
|
|
69
|
+
const projectRoot = options.projectRoot ?? dirname(resolve(vbriefRoot));
|
|
68
70
|
try {
|
|
69
|
-
atomicWriteText(filePath, formatBriefJson(data));
|
|
71
|
+
atomicWriteText(filePath, formatBriefJson(data), { projectRoot });
|
|
70
72
|
return { ok: true };
|
|
71
73
|
}
|
|
72
74
|
catch (err) {
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delivery integrity for scope completion (#3041).
|
|
3
|
+
*
|
|
4
|
+
* A code-bearing scope must not acquire a delivered disposition unless the
|
|
5
|
+
* merge/delivered commit is an ancestor of the refreshed remote delivery ref,
|
|
6
|
+
* or an explicit auditable non-delivery disposition is recorded.
|
|
7
|
+
*
|
|
8
|
+
* Deploy / UAT are separate axes and MUST NOT be inferred from Git alone.
|
|
9
|
+
*/
|
|
10
|
+
import { type GitRunner } from "../session/git.js";
|
|
11
|
+
/** Handoff states that Git delivery can assert (deploy/UAT never inferred). */
|
|
12
|
+
export declare const HANDOFF_STATES: readonly ["implemented", "pr_open", "merged_to_integration", "delivered"];
|
|
13
|
+
export type HandoffState = (typeof HANDOFF_STATES)[number];
|
|
14
|
+
/** Explicit non-delivery terminal dispositions (never render as shipped). */
|
|
15
|
+
export declare const NON_DELIVERY_DISPOSITIONS: readonly ["cancelled", "superseded", "experiment_archived", "accepted_not_delivered"];
|
|
16
|
+
export type NonDeliveryDisposition = (typeof NON_DELIVERY_DISPOSITIONS)[number];
|
|
17
|
+
/** Delivery verification outcome for completion provenance. */
|
|
18
|
+
export type DeliveryDisposition = "delivered" | "merged_to_integration" | "not_delivered" | NonDeliveryDisposition | "unknown" | "unverified";
|
|
19
|
+
export interface CompletionProvenance {
|
|
20
|
+
readonly repository: string | null;
|
|
21
|
+
readonly implementationCommit: string | null;
|
|
22
|
+
readonly prNumber: number | null;
|
|
23
|
+
readonly prBase: string | null;
|
|
24
|
+
readonly mergeCommit: string | null;
|
|
25
|
+
readonly deliveryBranch: string;
|
|
26
|
+
readonly deliveryCommit: string | null;
|
|
27
|
+
readonly verifiedAt: string;
|
|
28
|
+
readonly verifier: string;
|
|
29
|
+
readonly disposition: DeliveryDisposition;
|
|
30
|
+
readonly handoffState: HandoffState | "unknown";
|
|
31
|
+
/** Always null unless explicitly supplied — never inferred from Git (#3041). */
|
|
32
|
+
readonly deployed: boolean | null;
|
|
33
|
+
/** Always null unless explicitly supplied — never inferred from Git (#3041). */
|
|
34
|
+
readonly uatVerified: boolean | null;
|
|
35
|
+
}
|
|
36
|
+
export interface DeliveryEvidenceInput {
|
|
37
|
+
readonly repository?: string | null;
|
|
38
|
+
readonly implementationCommit?: string | null;
|
|
39
|
+
readonly prNumber?: number | null;
|
|
40
|
+
readonly prBase?: string | null;
|
|
41
|
+
readonly mergeCommit?: string | null;
|
|
42
|
+
readonly deliveryBranch?: string | null;
|
|
43
|
+
readonly deliveryCommit?: string | null;
|
|
44
|
+
readonly mergedAt?: string | null;
|
|
45
|
+
/** Explicit deploy/UAT (optional; never auto-filled from Git). */
|
|
46
|
+
readonly deployed?: boolean | null;
|
|
47
|
+
readonly uatVerified?: boolean | null;
|
|
48
|
+
readonly verifier?: string | null;
|
|
49
|
+
}
|
|
50
|
+
export interface DeliveryGateOptions {
|
|
51
|
+
readonly projectRoot: string;
|
|
52
|
+
readonly plan: Record<string, unknown>;
|
|
53
|
+
readonly nowIso: string;
|
|
54
|
+
readonly evidence?: DeliveryEvidenceInput | null;
|
|
55
|
+
readonly nonDeliveryDisposition?: NonDeliveryDisposition | null;
|
|
56
|
+
readonly runGit?: GitRunner;
|
|
57
|
+
readonly verifier?: string;
|
|
58
|
+
/**
|
|
59
|
+
* When true, skip remote refresh + ancestry (tests only that inject pre-validated
|
|
60
|
+
* evidence). Production callers leave this false.
|
|
61
|
+
*/
|
|
62
|
+
readonly assumeEvidenceValidated?: boolean;
|
|
63
|
+
}
|
|
64
|
+
export interface DeliveryGateResult {
|
|
65
|
+
readonly ok: boolean;
|
|
66
|
+
readonly message: string;
|
|
67
|
+
readonly provenance: CompletionProvenance | null;
|
|
68
|
+
readonly codeBearing: boolean;
|
|
69
|
+
}
|
|
70
|
+
export declare function isNonDeliveryDisposition(value: unknown): value is NonDeliveryDisposition;
|
|
71
|
+
/** True when the brief is treated as code-bearing for the delivery gate (#3041). */
|
|
72
|
+
export declare function isCodeBearingScope(plan: Record<string, unknown>): boolean;
|
|
73
|
+
export declare function hasGithubIssueRef(plan: Record<string, unknown>): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Classify stored completion provenance for read paths.
|
|
76
|
+
* Legacy completed records without provenance → unknown/unverified (not delivered).
|
|
77
|
+
*/
|
|
78
|
+
export declare function classifyStoredDeliveryDisposition(plan: Record<string, unknown>): DeliveryDisposition;
|
|
79
|
+
/**
|
|
80
|
+
* Refresh the remote delivery ref. Failure blocks delivered completion (#3041).
|
|
81
|
+
*/
|
|
82
|
+
export declare function refreshRemoteDeliveryRef(projectRoot: string, deliveryBranch: string, runGit?: GitRunner): {
|
|
83
|
+
ok: boolean;
|
|
84
|
+
error: string | null;
|
|
85
|
+
remoteRef: string;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Validate that mergeCommit is an ancestor of the refreshed remote delivery ref.
|
|
89
|
+
*/
|
|
90
|
+
export declare function verifyDeliveryAncestry(projectRoot: string, mergeCommit: string, deliveryBranch: string, runGit?: GitRunner): {
|
|
91
|
+
ok: boolean;
|
|
92
|
+
error: string | null;
|
|
93
|
+
remoteTip: string | null;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Gate delivered completion for a code-bearing scope (#3041).
|
|
97
|
+
*
|
|
98
|
+
* Returns ok=true with provenance when:
|
|
99
|
+
* - scope is not code-bearing (provenance may be null or non-code note), OR
|
|
100
|
+
* - explicit non-delivery disposition is provided, OR
|
|
101
|
+
* - durable delivery evidence validates (PR base == deliveryBranch, merge commit
|
|
102
|
+
* ancestor of refreshed remote delivery ref).
|
|
103
|
+
*/
|
|
104
|
+
export declare function evaluateDeliveryGate(options: DeliveryGateOptions): DeliveryGateResult;
|
|
105
|
+
/** Stamp completion provenance onto plan.metadata (mutates plan). */
|
|
106
|
+
export declare function stampDeliveryProvenance(plan: Record<string, unknown>, provenance: CompletionProvenance): void;
|
|
107
|
+
/**
|
|
108
|
+
* Parse a PR REST payload into delivery evidence fields.
|
|
109
|
+
* Expects GitHub pulls API shape (merged_at, base.ref, merge_commit_sha, …).
|
|
110
|
+
*/
|
|
111
|
+
export declare function evidenceFromPrPayload(payload: Record<string, unknown>, prNumber: number, repository: string | null, deliveryBranch?: string | null): DeliveryEvidenceInput;
|
|
112
|
+
//# sourceMappingURL=delivery-evidence.d.ts.map
|