@deftai/directive-core 0.95.0 → 0.97.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/archive.d.ts +134 -0
- package/dist/cache/archive.js +636 -0
- package/dist/cache/index.d.ts +1 -0
- package/dist/cache/index.js +1 -0
- package/dist/cache/main.js +298 -1
- package/dist/check/gate-lists.js +8 -0
- package/dist/consumer-check-contract/evaluate.d.ts +124 -0
- package/dist/consumer-check-contract/evaluate.js +699 -0
- package/dist/consumer-check-contract/index.d.ts +5 -0
- package/dist/consumer-check-contract/index.js +5 -0
- package/dist/content-contracts/skills/helpers.d.ts +1 -1
- package/dist/content-contracts/skills/helpers.js +1 -0
- package/dist/delivery-attempt/disk-begin.d.ts +51 -0
- package/dist/delivery-attempt/disk-begin.js +68 -0
- package/dist/delivery-attempt/evaluate.d.ts +26 -0
- package/dist/delivery-attempt/evaluate.js +443 -0
- package/dist/delivery-attempt/fingerprint.d.ts +32 -0
- package/dist/delivery-attempt/fingerprint.js +100 -0
- package/dist/delivery-attempt/handoff.d.ts +25 -0
- package/dist/delivery-attempt/handoff.js +102 -0
- package/dist/delivery-attempt/index.d.ts +17 -0
- package/dist/delivery-attempt/index.js +17 -0
- package/dist/delivery-attempt/ledger.d.ts +169 -0
- package/dist/delivery-attempt/ledger.js +758 -0
- package/dist/delivery-attempt/material-delta.d.ts +38 -0
- package/dist/delivery-attempt/material-delta.js +126 -0
- package/dist/delivery-attempt/types.d.ts +210 -0
- package/dist/delivery-attempt/types.js +77 -0
- package/dist/doctor/index.d.ts +1 -0
- package/dist/doctor/index.js +1 -0
- package/dist/doctor/main.js +12 -0
- package/dist/doctor/openclaw-soft-rebind.d.ts +26 -0
- package/dist/doctor/openclaw-soft-rebind.js +164 -0
- package/dist/hooks/dispatcher.d.ts +2 -1
- package/dist/hooks/dispatcher.js +63 -9
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/init-deposit/gitignore.js +7 -0
- package/dist/init-deposit/hygiene.d.ts +1 -1
- package/dist/init-deposit/hygiene.js +16 -4
- package/dist/init-deposit/init-deposit.js +5 -0
- package/dist/init-deposit/refresh.js +3 -0
- package/dist/init-deposit/scaffold.js +6 -5
- package/dist/parent-turn-shape/evaluate.d.ts +84 -0
- package/dist/parent-turn-shape/evaluate.js +353 -0
- package/dist/parent-turn-shape/index.d.ts +8 -0
- package/dist/parent-turn-shape/index.js +8 -0
- package/dist/pr-merge-readiness/ci-gate.d.ts +29 -1
- package/dist/pr-merge-readiness/ci-gate.js +191 -24
- package/dist/pr-merge-readiness/compute.js +10 -1
- package/dist/pr-merge-readiness/index.d.ts +2 -1
- package/dist/pr-merge-readiness/index.js +2 -1
- package/dist/pr-merge-readiness/output.js +14 -0
- package/dist/pr-merge-readiness/platform-status.d.ts +29 -0
- package/dist/pr-merge-readiness/platform-status.js +49 -0
- package/dist/pr-watch/constants.d.ts +10 -0
- package/dist/pr-watch/constants.js +12 -1
- package/dist/pr-watch/main.js +16 -1
- package/dist/pr-watch/probe.js +13 -1
- package/dist/pr-watch/types.d.ts +3 -2
- package/dist/pr-watch/watch.js +14 -7
- package/dist/review-monitor/constants.js +3 -2
- package/dist/review-monitor/tier-detection.d.ts +7 -3
- package/dist/review-monitor/tier-detection.js +18 -1
- package/dist/review-monitor/verify.js +18 -0
- package/dist/scope/index.d.ts +2 -0
- package/dist/scope/index.js +2 -0
- package/dist/scope/main.d.ts +10 -0
- package/dist/scope/main.js +109 -24
- package/dist/scope/promote-from-issue.d.ts +49 -0
- package/dist/scope/promote-from-issue.js +367 -0
- package/dist/scope/promote-path.d.ts +39 -0
- package/dist/scope/promote-path.js +105 -0
- package/dist/scope-provenance/digest.d.ts +67 -0
- package/dist/scope-provenance/digest.js +188 -0
- package/dist/scope-provenance/evaluate.d.ts +82 -0
- package/dist/scope-provenance/evaluate.js +528 -0
- package/dist/scope-provenance/index.d.ts +6 -0
- package/dist/scope-provenance/index.js +6 -0
- package/dist/session/compact-ritual.d.ts +96 -0
- package/dist/session/compact-ritual.js +237 -0
- package/dist/session/compact-ritual.spec.d.ts +2 -0
- package/dist/session/compact-ritual.spec.js +21 -0
- package/dist/session/index.d.ts +2 -0
- package/dist/session/index.js +2 -0
- package/dist/session/openclaw-soft-rebind-deposit.d.ts +46 -0
- package/dist/session/openclaw-soft-rebind-deposit.js +165 -0
- package/dist/swarm/routing.d.ts +4 -2
- package/dist/swarm/routing.js +26 -4
- package/dist/test-boundary/evaluate.d.ts +54 -0
- package/dist/test-boundary/evaluate.js +368 -0
- package/dist/test-boundary/index.d.ts +6 -0
- package/dist/test-boundary/index.js +6 -0
- package/dist/test-boundary/policy.d.ts +52 -0
- package/dist/test-boundary/policy.js +182 -0
- package/dist/triage/actions/index.js +62 -2
- package/dist/triage/actions/types.d.ts +8 -1
- package/dist/triage/author-filter.d.ts +51 -0
- package/dist/triage/author-filter.js +152 -0
- package/dist/triage/bootstrap/gitignore.d.ts +1 -1
- package/dist/triage/bootstrap/gitignore.js +15 -1
- package/dist/triage/classify/index.d.ts +2 -2
- package/dist/triage/classify/index.js +2 -2
- package/dist/triage/classify/label-mirror.d.ts +68 -5
- package/dist/triage/classify/label-mirror.js +261 -31
- package/dist/triage/help/registry-data.d.ts +49 -38
- package/dist/triage/help/registry-data.js +115 -40
- package/dist/triage/index.d.ts +1 -0
- package/dist/triage/index.js +1 -0
- package/dist/triage/queue/index.d.ts +1 -0
- package/dist/triage/queue/index.js +1 -0
- package/dist/triage/queue/render.d.ts +2 -0
- package/dist/triage/queue/render.js +6 -0
- package/dist/vbrief-activate/activate.js +22 -6
- package/dist/xbrief/styles.js +33 -17
- package/package.json +11 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MONITORING_TIER_1, MONITORING_TIER_2, MONITORING_TIER_3 } from "./constants.js";
|
|
2
|
-
/** Canonical Approach-1 platform primitives for review-monitor register/verify (#2655 / #2876). */
|
|
3
|
-
export type PlatformPrimitive = "start_agent" | "spawn_subagent" | "cursor-task" | "sessions_spawn" | "openclaw-sessions-spawn";
|
|
2
|
+
/** Canonical Approach-1 platform primitives for review-monitor register/verify (#2655 / #2876 / #3134). */
|
|
3
|
+
export type PlatformPrimitive = "start_agent" | "spawn_subagent" | "cursor-task" | "claude-agent" | "sessions_spawn" | "openclaw-sessions-spawn";
|
|
4
4
|
/** Accepted `--platform-primitive` values (register CLI + help text). */
|
|
5
5
|
export declare const PLATFORM_PRIMITIVES: readonly PlatformPrimitive[];
|
|
6
6
|
export declare const PLATFORM_PRIMITIVE_SET: Set<string>;
|
|
@@ -11,8 +11,12 @@ export interface MonitoringTierProbe {
|
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
13
|
* Inline Tier-1 detection aligned with the swarm Phase 3 / review-cycle matrix
|
|
14
|
-
* (#1877 / #2655 / #2876). Prefer `task platform:capabilities` when available (#1357);
|
|
14
|
+
* (#1877 / #2655 / #2876 / #3134). Prefer `task platform:capabilities` when available (#1357);
|
|
15
15
|
* this probe does not block MVP.
|
|
16
|
+
*
|
|
17
|
+
* Ordered env probe (must match skill matrix placement; Claude after Cursor so bare
|
|
18
|
+
* Task / CURSOR_* never misclassify Claude Code as cursor-composer):
|
|
19
|
+
* start_agent → WARP_* → Cursor → Claude Code → OpenClaw → grok-build → Tier2 → Tier3.
|
|
16
20
|
*/
|
|
17
21
|
export declare function probeMonitoringTier(environ?: NodeJS.ProcessEnv): MonitoringTierProbe;
|
|
18
22
|
export declare function isTier1(probe: MonitoringTierProbe): boolean;
|
|
@@ -5,6 +5,7 @@ export const PLATFORM_PRIMITIVES = [
|
|
|
5
5
|
"start_agent",
|
|
6
6
|
"spawn_subagent",
|
|
7
7
|
"cursor-task",
|
|
8
|
+
"claude-agent",
|
|
8
9
|
"sessions_spawn",
|
|
9
10
|
"openclaw-sessions-spawn",
|
|
10
11
|
];
|
|
@@ -28,8 +29,12 @@ function probeOverride(environ) {
|
|
|
28
29
|
}
|
|
29
30
|
/**
|
|
30
31
|
* Inline Tier-1 detection aligned with the swarm Phase 3 / review-cycle matrix
|
|
31
|
-
* (#1877 / #2655 / #2876). Prefer `task platform:capabilities` when available (#1357);
|
|
32
|
+
* (#1877 / #2655 / #2876 / #3134). Prefer `task platform:capabilities` when available (#1357);
|
|
32
33
|
* this probe does not block MVP.
|
|
34
|
+
*
|
|
35
|
+
* Ordered env probe (must match skill matrix placement; Claude after Cursor so bare
|
|
36
|
+
* Task / CURSOR_* never misclassify Claude Code as cursor-composer):
|
|
37
|
+
* start_agent → WARP_* → Cursor → Claude Code → OpenClaw → grok-build → Tier2 → Tier3.
|
|
33
38
|
*/
|
|
34
39
|
export function probeMonitoringTier(environ = process.env) {
|
|
35
40
|
const override = probeOverride(environ);
|
|
@@ -53,6 +58,18 @@ export function probeMonitoringTier(environ = process.env) {
|
|
|
53
58
|
};
|
|
54
59
|
}
|
|
55
60
|
const runtime = (environ.DEFT_AGENT_RUNTIME ?? "").trim().toLowerCase();
|
|
61
|
+
// Claude Code: Claude-unique env signals only — never bare "Task" (#3134).
|
|
62
|
+
// CLAUDECODE is set in Claude Code tool/hook subprocesses (Anthropic docs).
|
|
63
|
+
// DEFT_PROBE_CLAUDE_CODE / DEFT_AGENT_RUNTIME=claude-code are explicit overrides.
|
|
64
|
+
// Cursor already short-circuited above, so CURSOR_* never falls into this branch.
|
|
65
|
+
if (envTruthy(environ, "DEFT_PROBE_CLAUDE_CODE") ||
|
|
66
|
+
envTruthy(environ, "DEFT_HAS_CLAUDE_AGENT") ||
|
|
67
|
+
envTruthy(environ, "CLAUDECODE") ||
|
|
68
|
+
envTruthy(environ, "CLAUDE_CODE") ||
|
|
69
|
+
runtime === "claude-code" ||
|
|
70
|
+
runtime === "claude") {
|
|
71
|
+
return { tier: MONITORING_TIER_1, primitive: "claude-agent", descriptor: "claude-code" };
|
|
72
|
+
}
|
|
56
73
|
// OpenClaw: sessions_spawn is the Tier-1 Approach 1 primitive (#2876).
|
|
57
74
|
// Alias openclaw-sessions-spawn accepted on register for explicit naming.
|
|
58
75
|
if (envTruthy(environ, "DEFT_PROBE_SESSIONS_SPAWN") ||
|
|
@@ -7,6 +7,24 @@ import { defaultSubagentStatusDir, fetchActiveMonitorFromGithub, readReviewMonit
|
|
|
7
7
|
import { isTier1, probeMonitoringTier } from "./tier-detection.js";
|
|
8
8
|
function spawnRedirect(probe) {
|
|
9
9
|
const primitive = probe.primitive ?? "sub-agent";
|
|
10
|
+
// Claude Code / Cursor nested-leaf boundary (#2797 / #3134): lead with leaf-safe
|
|
11
|
+
// ownership so implementation leaves never treat nested Task/Agent spawn as the
|
|
12
|
+
// default instruction. Top-level parents that own the primitive still get the
|
|
13
|
+
// Approach 1 background path second.
|
|
14
|
+
if (primitive === "claude-agent" || primitive === "cursor-task") {
|
|
15
|
+
return (`Ownership path for ${primitive} (#2797 / #3134):\n` +
|
|
16
|
+
" 1. Implementation leaf (drive-to: merge-ready): keep ownership in THIS process " +
|
|
17
|
+
"via blocking dual-invoke `pr:watch` (`deft pr:watch <N>` then `task deft:pr:watch -- <N>`). " +
|
|
18
|
+
`Do NOT nested-spawn another ${primitive} review-monitor.\n` +
|
|
19
|
+
" 2. Or scope leaf `stop-at: pr-open` so the parent/orchestrator that owns " +
|
|
20
|
+
`${primitive} spawns a sibling monitor and registers it.\n` +
|
|
21
|
+
" 3. Top-level parent/orchestrator only: spawn Approach 1 via " +
|
|
22
|
+
`${primitive} (background), include templates/agent-prompt-preamble.md and ` +
|
|
23
|
+
"templates/swarm-greptile-poller-prompt.md, then:\n" +
|
|
24
|
+
" task review-monitor:register -- --pr <N> --monitor-agent-id <id> " +
|
|
25
|
+
`--platform-primitive ${primitive}\n` +
|
|
26
|
+
"Re-run: task verify:review-monitor -- --pr <N>");
|
|
27
|
+
}
|
|
10
28
|
return (`Spawn an Approach 1 review-monitor via ${primitive} (background), include ` +
|
|
11
29
|
"`templates/agent-prompt-preamble.md` and `templates/swarm-greptile-poller-prompt.md`, " +
|
|
12
30
|
"then register:\n" +
|
package/dist/scope/index.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export * from "./demote.js";
|
|
|
7
7
|
export * from "./main.js";
|
|
8
8
|
export * from "./open-umbrella-warning.js";
|
|
9
9
|
export * from "./project-context.js";
|
|
10
|
+
export * from "./promote-from-issue.js";
|
|
11
|
+
export * from "./promote-path.js";
|
|
10
12
|
export * from "./transition.js";
|
|
11
13
|
export * from "./undo.js";
|
|
12
14
|
export * from "./vbrief-json.js";
|
package/dist/scope/index.js
CHANGED
|
@@ -7,6 +7,8 @@ export * from "./demote.js";
|
|
|
7
7
|
export * from "./main.js";
|
|
8
8
|
export * from "./open-umbrella-warning.js";
|
|
9
9
|
export * from "./project-context.js";
|
|
10
|
+
export * from "./promote-from-issue.js";
|
|
11
|
+
export * from "./promote-path.js";
|
|
10
12
|
export * from "./transition.js";
|
|
11
13
|
export * from "./undo.js";
|
|
12
14
|
export * from "./vbrief-json.js";
|
package/dist/scope/main.d.ts
CHANGED
|
@@ -6,6 +6,16 @@ export interface LifecycleArgs {
|
|
|
6
6
|
force?: boolean;
|
|
7
7
|
batch?: boolean;
|
|
8
8
|
batchFiles?: string[];
|
|
9
|
+
/** Promote from triage-cache issue number (#1136). */
|
|
10
|
+
fromIssue?: number;
|
|
11
|
+
/** Repo slug for --from-issue (#1136). */
|
|
12
|
+
repo?: string;
|
|
13
|
+
/** Missing decision hard-fails (#1136). */
|
|
14
|
+
strict?: boolean;
|
|
15
|
+
/** Skip triage reciprocity gate (#1136). */
|
|
16
|
+
forceNoCache?: boolean;
|
|
17
|
+
/** Disambiguate multiple proposed artifacts for --from-issue (#1136). */
|
|
18
|
+
pathFlag?: string;
|
|
9
19
|
/** Explicit non-delivery disposition for code-bearing complete (#3041). */
|
|
10
20
|
nonDeliveryDisposition?: NonDeliveryDisposition;
|
|
11
21
|
/** Optional delivery evidence flags for complete (#3041). */
|
package/dist/scope/main.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import { dirname
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
3
|
import { maybeRunStalenessTickler } from "../staleness-tickler/run.js";
|
|
4
4
|
import { reconcileUmbrellas, renderUmbrellasReport } from "../vbrief-reconcile/umbrellas.js";
|
|
5
5
|
import { canonicalLogPath, readAll } from "./audit-log.js";
|
|
@@ -9,14 +9,18 @@ import { isNonDeliveryDisposition, } from "./delivery-evidence.js";
|
|
|
9
9
|
import { batchDemote, DEFAULT_OLDER_THAN_DAYS, demoteOne, resolveDemoteFilePath, resolveFilePath, resolveProjectRootStrict, } from "./demote.js";
|
|
10
10
|
import { completedPathForScopeMove, findOpenUmbrellaReferences, renderOpenUmbrellaWarning, } from "./open-umbrella-warning.js";
|
|
11
11
|
import { resolveProjectRoot } from "./project-context.js";
|
|
12
|
-
import {
|
|
12
|
+
import { promoteFromIssue } from "./promote-from-issue.js";
|
|
13
|
+
import { promotePath } from "./promote-path.js";
|
|
14
|
+
import { runTransition } from "./transition.js";
|
|
13
15
|
import { findByDecisionId, isAlreadyUndone, REVERSIBLE_ACTIONS, undoBatch, undoOne, } from "./undo.js";
|
|
14
|
-
import { checkWipCap, formatWipCapRefusal } from "./wip-cap-check.js";
|
|
15
16
|
const LIFECYCLE_USAGE_STDERR = "usage: scope_lifecycle.py [-h] [--project-root PROJECT_ROOT] [--force] [--batch]\n" +
|
|
17
|
+
" [--from-issue N] [--repo OWNER/NAME] [--strict] [--force-no-cache]\n" +
|
|
18
|
+
" [--path PATH]\n" +
|
|
16
19
|
" {activate,block,cancel,complete,fail,promote,restore,unblock}\n" +
|
|
17
20
|
" [file ...]\n" +
|
|
18
21
|
"scope_lifecycle.py: error: the following arguments are required: action, file\n" +
|
|
19
|
-
"(promote --batch may omit file and promotes all proposed/ scopes; #3011)\n"
|
|
22
|
+
"(promote --batch may omit file and promotes all proposed/ scopes; #3011)\n" +
|
|
23
|
+
"(promote --from-issue=N may omit file; #1136)\n";
|
|
20
24
|
function parseLifecycleArgv(argv) {
|
|
21
25
|
if (argv.length < 1) {
|
|
22
26
|
return { args: null, error: "usage" };
|
|
@@ -30,6 +34,10 @@ function parseLifecycleArgv(argv) {
|
|
|
30
34
|
let force = false;
|
|
31
35
|
let batch = false;
|
|
32
36
|
const batchFiles = [];
|
|
37
|
+
let fromIssue;
|
|
38
|
+
let strict = false;
|
|
39
|
+
let forceNoCache = false;
|
|
40
|
+
let pathFlag;
|
|
33
41
|
let nonDeliveryDisposition;
|
|
34
42
|
let prNumber;
|
|
35
43
|
let mergeCommit;
|
|
@@ -48,6 +56,37 @@ function parseLifecycleArgv(argv) {
|
|
|
48
56
|
else if (arg === "--batch") {
|
|
49
57
|
batch = true;
|
|
50
58
|
}
|
|
59
|
+
else if (arg === "--strict") {
|
|
60
|
+
strict = true;
|
|
61
|
+
}
|
|
62
|
+
else if (arg === "--force-no-cache") {
|
|
63
|
+
forceNoCache = true;
|
|
64
|
+
}
|
|
65
|
+
else if (arg === "--from-issue") {
|
|
66
|
+
const raw = argv[i + 1];
|
|
67
|
+
i += 1;
|
|
68
|
+
if (raw === undefined || !/^[1-9]\d*$/.test(raw)) {
|
|
69
|
+
return { args: null, error: "usage" };
|
|
70
|
+
}
|
|
71
|
+
fromIssue = Number.parseInt(raw, 10);
|
|
72
|
+
}
|
|
73
|
+
else if (arg?.startsWith("--from-issue=")) {
|
|
74
|
+
const raw = arg.slice("--from-issue=".length);
|
|
75
|
+
if (!/^[1-9]\d*$/.test(raw)) {
|
|
76
|
+
return { args: null, error: "usage" };
|
|
77
|
+
}
|
|
78
|
+
fromIssue = Number.parseInt(raw, 10);
|
|
79
|
+
}
|
|
80
|
+
else if (arg === "--path") {
|
|
81
|
+
pathFlag = argv[i + 1];
|
|
82
|
+
i += 1;
|
|
83
|
+
if (pathFlag === undefined) {
|
|
84
|
+
return { args: null, error: "usage" };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else if (arg?.startsWith("--path=")) {
|
|
88
|
+
pathFlag = arg.slice("--path=".length);
|
|
89
|
+
}
|
|
51
90
|
else if (arg === "--project-root") {
|
|
52
91
|
projectRoot = argv[i + 1];
|
|
53
92
|
i += 1;
|
|
@@ -127,18 +166,20 @@ function parseLifecycleArgv(argv) {
|
|
|
127
166
|
return { args: null, error: "usage" };
|
|
128
167
|
}
|
|
129
168
|
}
|
|
169
|
+
// Delivery evidence uses --repo as repository; --from-issue also uses --repo as triage slug.
|
|
170
|
+
// Prefer treating --repo as triage slug when --from-issue is set (#1136).
|
|
130
171
|
const deliveryEvidence = prNumber !== undefined ||
|
|
131
172
|
mergeCommit !== undefined ||
|
|
132
173
|
prBase !== undefined ||
|
|
133
174
|
deliveryBranch !== undefined ||
|
|
134
|
-
repo !== undefined ||
|
|
175
|
+
(repo !== undefined && fromIssue === undefined) ||
|
|
135
176
|
mergedAt !== undefined
|
|
136
177
|
? {
|
|
137
178
|
prNumber: prNumber !== undefined && Number.isFinite(prNumber) ? prNumber : null,
|
|
138
179
|
mergeCommit: mergeCommit ?? null,
|
|
139
180
|
prBase: prBase ?? null,
|
|
140
181
|
deliveryBranch: deliveryBranch ?? null,
|
|
141
|
-
repository: repo ?? null,
|
|
182
|
+
repository: fromIssue === undefined ? (repo ?? null) : null,
|
|
142
183
|
mergedAt: mergedAt ?? (mergeCommit !== undefined ? "supplied" : null),
|
|
143
184
|
verifier: "scope:complete",
|
|
144
185
|
}
|
|
@@ -158,6 +199,27 @@ function parseLifecycleArgv(argv) {
|
|
|
158
199
|
},
|
|
159
200
|
};
|
|
160
201
|
}
|
|
202
|
+
if (fromIssue !== undefined) {
|
|
203
|
+
if (action !== "promote") {
|
|
204
|
+
return { args: null, error: "usage" };
|
|
205
|
+
}
|
|
206
|
+
if (Number.isNaN(fromIssue) || fromIssue < 1) {
|
|
207
|
+
return { args: null, error: "usage" };
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
args: {
|
|
211
|
+
action,
|
|
212
|
+
file: file.length > 0 ? file : (pathFlag ?? ""),
|
|
213
|
+
projectRoot,
|
|
214
|
+
force,
|
|
215
|
+
fromIssue,
|
|
216
|
+
repo,
|
|
217
|
+
strict,
|
|
218
|
+
forceNoCache,
|
|
219
|
+
pathFlag: pathFlag ?? (file.length > 0 ? file : undefined),
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
}
|
|
161
223
|
if (file.length === 0) {
|
|
162
224
|
return { args: null, error: "usage" };
|
|
163
225
|
}
|
|
@@ -181,7 +243,7 @@ export function lifecycleMain(argv) {
|
|
|
181
243
|
}
|
|
182
244
|
return 2;
|
|
183
245
|
}
|
|
184
|
-
const { action, file, projectRoot, force, batch, batchFiles, nonDeliveryDisposition, deliveryEvidence, } = parsed.args;
|
|
246
|
+
const { action, file, projectRoot, force, batch, batchFiles, fromIssue, repo, strict, forceNoCache, pathFlag, nonDeliveryDisposition, deliveryEvidence, } = parsed.args;
|
|
185
247
|
if (batch === true && action === "promote") {
|
|
186
248
|
const result = batchPromote({
|
|
187
249
|
files: batchFiles && batchFiles.length > 0 ? batchFiles : undefined,
|
|
@@ -203,21 +265,54 @@ export function lifecycleMain(argv) {
|
|
|
203
265
|
}
|
|
204
266
|
return result.exitCode;
|
|
205
267
|
}
|
|
268
|
+
if (fromIssue !== undefined && action === "promote") {
|
|
269
|
+
const result = promoteFromIssue({
|
|
270
|
+
issueNumber: fromIssue,
|
|
271
|
+
repo: repo ?? null,
|
|
272
|
+
projectRoot,
|
|
273
|
+
force: force === true,
|
|
274
|
+
forceNoCache: forceNoCache === true,
|
|
275
|
+
strict: strict === true,
|
|
276
|
+
explicitPath: pathFlag,
|
|
277
|
+
});
|
|
278
|
+
for (const line of result.warnings) {
|
|
279
|
+
process.stderr.write(`${line}\n`);
|
|
280
|
+
}
|
|
281
|
+
if (result.ok) {
|
|
282
|
+
process.stdout.write(`${result.message}\n`);
|
|
283
|
+
if (result.wipCapOverride) {
|
|
284
|
+
process.stderr.write("\u26a0 WIP cap exceeded; promote allowed via --force. " +
|
|
285
|
+
"audit: scope-lifecycle.jsonl entry tagged wip_cap_override (#1124).\n");
|
|
286
|
+
}
|
|
287
|
+
return 0;
|
|
288
|
+
}
|
|
289
|
+
process.stderr.write(`Error: ${result.message}\n`);
|
|
290
|
+
return result.exitCode;
|
|
291
|
+
}
|
|
206
292
|
const [filePath, error] = resolveFilePath(file, projectRoot);
|
|
207
293
|
if (error !== null || filePath === null) {
|
|
208
294
|
process.stderr.write(`Error: ${error}\n`);
|
|
209
295
|
return 2;
|
|
210
296
|
}
|
|
211
|
-
|
|
297
|
+
// Path-based promote uses shared promotePath for WIP + optional audit consistency (#1136).
|
|
212
298
|
if (action === "promote") {
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
299
|
+
const promoteResult = promotePath(filePath, {
|
|
300
|
+
projectRoot,
|
|
301
|
+
force: force === true,
|
|
302
|
+
});
|
|
303
|
+
if (promoteResult.ok) {
|
|
304
|
+
process.stdout.write(`${promoteResult.message}\n`);
|
|
305
|
+
if (promoteResult.wipCapOverride) {
|
|
306
|
+
process.stderr.write("\u26a0 WIP cap exceeded " +
|
|
307
|
+
`(promote allowed via --force). ` +
|
|
308
|
+
"audit: scope-lifecycle.jsonl entry tagged wip_cap_override (#1124).\n");
|
|
219
309
|
}
|
|
310
|
+
return 0;
|
|
220
311
|
}
|
|
312
|
+
process.stderr.write(promoteResult.exitCode === 1 && promoteResult.message.includes("WIP")
|
|
313
|
+
? `${promoteResult.message}\n`
|
|
314
|
+
: `Error: ${promoteResult.message}\n`);
|
|
315
|
+
return promoteResult.exitCode;
|
|
221
316
|
}
|
|
222
317
|
const transitionOptions = {
|
|
223
318
|
nonDeliveryDisposition,
|
|
@@ -226,16 +321,6 @@ export function lifecycleMain(argv) {
|
|
|
226
321
|
};
|
|
227
322
|
const result = runTransition(action, filePath, new Date(), transitionOptions);
|
|
228
323
|
if (result.ok) {
|
|
229
|
-
if (action === "promote" && capCheck !== null && capCheck.forceOverride) {
|
|
230
|
-
const rootForAudit = resolveProjectRoot(projectRoot);
|
|
231
|
-
if (rootForAudit !== null) {
|
|
232
|
-
const newPath = join(rootForAudit, "vbrief", "pending", filePath.split(/[/\\]/).pop() ?? "");
|
|
233
|
-
recordWipCapOverride(newPath, rootForAudit, capCheck);
|
|
234
|
-
}
|
|
235
|
-
process.stderr.write("\u26a0 WIP cap exceeded " +
|
|
236
|
-
`(count=${capCheck.count}, cap=${capCheck.cap}); promote allowed via --force. ` +
|
|
237
|
-
"audit: vbrief/.eval/scope-lifecycle.jsonl entry tagged wip_cap_override (#1124).\n");
|
|
238
|
-
}
|
|
239
324
|
process.stdout.write(`${result.message}\n`);
|
|
240
325
|
if (action === "complete") {
|
|
241
326
|
try {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scope:promote --from-issue reciprocity gate (#1136 / D18).
|
|
3
|
+
*
|
|
4
|
+
* Gates promote of a proposed scope on the latest triage-cache decision for
|
|
5
|
+
* the issue, locates the proposed artifact via provenance scan, and runs the
|
|
6
|
+
* shared promotePath path (WIP rules unchanged).
|
|
7
|
+
*/
|
|
8
|
+
import type { AuditEntry } from "../triage/actions/types.js";
|
|
9
|
+
import { type PromotePathResult } from "./promote-path.js";
|
|
10
|
+
export interface PromoteFromIssueOptions {
|
|
11
|
+
readonly issueNumber: number;
|
|
12
|
+
readonly repo?: string | null;
|
|
13
|
+
readonly projectRoot?: string;
|
|
14
|
+
/** WIP-cap override. */
|
|
15
|
+
readonly force?: boolean;
|
|
16
|
+
/** Skip reciprocity gate; still audit that force was used. */
|
|
17
|
+
readonly forceNoCache?: boolean;
|
|
18
|
+
/** Missing decision becomes hard fail (default: soft warn + proceed). */
|
|
19
|
+
readonly strict?: boolean;
|
|
20
|
+
readonly actor?: string;
|
|
21
|
+
/** Explicit path when multiple proposed artifacts match the issue. */
|
|
22
|
+
readonly explicitPath?: string;
|
|
23
|
+
readonly now?: Date;
|
|
24
|
+
/** Optional candidates-log path override (tests). */
|
|
25
|
+
readonly candidatesLogPath?: string;
|
|
26
|
+
/** Inject latest decision (tests). */
|
|
27
|
+
readonly latestDecision?: AuditEntry | null;
|
|
28
|
+
}
|
|
29
|
+
export interface PromoteFromIssueResult extends PromotePathResult {
|
|
30
|
+
readonly warnings: string[];
|
|
31
|
+
readonly repo: string | null;
|
|
32
|
+
readonly matchedPaths: string[];
|
|
33
|
+
readonly cacheStateAtPromote: string | null;
|
|
34
|
+
readonly cacheDecisionId: string | null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Locate lifecycle artifacts whose provenance owns ``issueNumber`` (optionally repo-scoped).
|
|
38
|
+
*/
|
|
39
|
+
export declare function findLifecycleArtifactsForIssue(projectRoot: string, issueNumber: number, options?: {
|
|
40
|
+
folder?: "proposed" | "pending";
|
|
41
|
+
repo?: string | null;
|
|
42
|
+
}): string[];
|
|
43
|
+
/** Locate proposed/ artifacts for issue N (repo-scoped when provided). */
|
|
44
|
+
export declare function findProposedArtifactsForIssue(projectRoot: string, issueNumber: number, repo?: string | null): string[];
|
|
45
|
+
/**
|
|
46
|
+
* Promote the proposed scope for an issue, gated on triage-cache latestDecision.
|
|
47
|
+
*/
|
|
48
|
+
export declare function promoteFromIssue(options: PromoteFromIssueOptions): PromoteFromIssueResult;
|
|
49
|
+
//# sourceMappingURL=promote-from-issue.d.ts.map
|