@deftai/directive-core 0.104.0 → 0.105.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.
Files changed (225) hide show
  1. package/dist/authz/classify.js +526 -42
  2. package/dist/check/cached-orchestrator.d.ts +1 -1
  3. package/dist/check/cached-orchestrator.js +2 -2
  4. package/dist/check/named-cause.d.ts +1 -1
  5. package/dist/check/named-cause.js +33 -3
  6. package/dist/codebase/default-extractor.d.ts +5 -0
  7. package/dist/codebase/default-extractor.js +7 -15
  8. package/dist/deposit/copy-tree.js +60 -0
  9. package/dist/deposit/python-free.js +26 -18
  10. package/dist/doctor/checks.d.ts +8 -0
  11. package/dist/doctor/checks.js +37 -25
  12. package/dist/doctor/doctor-state.d.ts +4 -0
  13. package/dist/doctor/doctor-state.js +7 -1
  14. package/dist/doctor/main.js +9 -19
  15. package/dist/doctor/types.d.ts +9 -0
  16. package/dist/fs/contained-write.d.ts +115 -1
  17. package/dist/fs/contained-write.js +241 -5
  18. package/dist/fs/mutation-ledger.d.ts +54 -0
  19. package/dist/fs/mutation-ledger.js +133 -0
  20. package/dist/fs/non-product-dirs.d.ts +79 -0
  21. package/dist/fs/non-product-dirs.js +96 -0
  22. package/dist/hooks/dispatcher.d.ts +3 -1
  23. package/dist/hooks/dispatcher.js +14 -0
  24. package/dist/index.d.ts +1 -0
  25. package/dist/index.js +2 -0
  26. package/dist/init-deposit/agent-hooks.js +17 -15
  27. package/dist/init-deposit/core-guard-pin-content.d.ts +7 -0
  28. package/dist/init-deposit/core-guard-pin-content.js +393 -0
  29. package/dist/init-deposit/gitignore.js +9 -0
  30. package/dist/init-deposit/hygiene.d.ts +47 -11
  31. package/dist/init-deposit/hygiene.js +172 -37
  32. package/dist/init-deposit/legacy-detect.js +6 -2
  33. package/dist/init-deposit/refresh.d.ts +21 -1
  34. package/dist/init-deposit/refresh.js +106 -9
  35. package/dist/init-deposit/scaffold.js +28 -279
  36. package/dist/init-deposit/slash-deposit.js +13 -7
  37. package/dist/init-deposit/xbrief-projections.d.ts +8 -1
  38. package/dist/init-deposit/xbrief-projections.js +24 -11
  39. package/dist/intake/clause-derivation.d.ts +38 -1
  40. package/dist/intake/clause-derivation.js +211 -9
  41. package/dist/intake/issue-ingest.d.ts +3 -1
  42. package/dist/intake/issue-ingest.js +35 -6
  43. package/dist/lifecycle/completed-tracked-on-delivery.d.ts +5 -0
  44. package/dist/lifecycle/completed-tracked-on-delivery.js +85 -18
  45. package/dist/literal-acceptance/capture.d.ts +10 -0
  46. package/dist/literal-acceptance/capture.js +224 -75
  47. package/dist/literal-acceptance/evaluate.d.ts +29 -4
  48. package/dist/literal-acceptance/evaluate.js +70 -2
  49. package/dist/literal-acceptance/index.d.ts +3 -3
  50. package/dist/literal-acceptance/index.js +3 -3
  51. package/dist/literal-acceptance/safety.d.ts +41 -0
  52. package/dist/literal-acceptance/safety.js +126 -2
  53. package/dist/literal-acceptance/types.d.ts +8 -0
  54. package/dist/orphan-active/evaluate.d.ts +7 -1
  55. package/dist/orphan-active/evaluate.js +102 -23
  56. package/dist/platform/platform-capabilities.js +2 -3
  57. package/dist/policy/base-branch.d.ts +37 -0
  58. package/dist/policy/base-branch.js +114 -0
  59. package/dist/policy/branch-sync.d.ts +80 -0
  60. package/dist/policy/branch-sync.js +211 -0
  61. package/dist/policy/ceremony-dial-escalation.js +1 -0
  62. package/dist/policy/ceremony-dial.js +4 -14
  63. package/dist/policy/delivery-branch.d.ts +5 -3
  64. package/dist/policy/delivery-branch.js +7 -3
  65. package/dist/policy/file-size-thresholds.d.ts +24 -0
  66. package/dist/policy/file-size-thresholds.js +23 -0
  67. package/dist/policy/forge-outage-retry.d.ts +47 -0
  68. package/dist/policy/forge-outage-retry.js +157 -0
  69. package/dist/policy/index.d.ts +7 -0
  70. package/dist/policy/index.js +66 -7
  71. package/dist/policy/project-invariants.d.ts +50 -0
  72. package/dist/policy/project-invariants.js +205 -0
  73. package/dist/policy/sync-default.d.ts +129 -0
  74. package/dist/policy/sync-default.js +452 -0
  75. package/dist/policy/sync-max-files.d.ts +93 -0
  76. package/dist/policy/sync-max-files.js +192 -0
  77. package/dist/pr-monitor/absent-required.d.ts +11 -0
  78. package/dist/pr-monitor/absent-required.js +61 -0
  79. package/dist/pr-monitor/constants.d.ts +7 -0
  80. package/dist/pr-monitor/constants.js +7 -0
  81. package/dist/pr-monitor/index.d.ts +2 -1
  82. package/dist/pr-monitor/index.js +2 -1
  83. package/dist/pr-monitor/main.js +4 -0
  84. package/dist/pr-monitor/monitor.js +24 -1
  85. package/dist/pr-wait-mergeable/classify.js +6 -0
  86. package/dist/preflight/evaluate.d.ts +4 -0
  87. package/dist/preflight/evaluate.js +35 -1
  88. package/dist/preflight/index.d.ts +4 -0
  89. package/dist/preflight/index.js +2 -0
  90. package/dist/preflight/intended-placement.d.ts +62 -0
  91. package/dist/preflight/intended-placement.js +275 -0
  92. package/dist/preflight/project-invariants-gate.d.ts +29 -0
  93. package/dist/preflight/project-invariants-gate.js +82 -0
  94. package/dist/product-first-done-gate/acceptance-resolver.d.ts +128 -0
  95. package/dist/product-first-done-gate/acceptance-resolver.js +144 -0
  96. package/dist/product-first-done-gate/acceptance.d.ts +7 -4
  97. package/dist/product-first-done-gate/acceptance.js +79 -8
  98. package/dist/product-first-done-gate/empty-resolution.d.ts +4 -1
  99. package/dist/product-first-done-gate/empty-resolution.js +12 -1
  100. package/dist/product-first-done-gate/evaluate.d.ts +12 -0
  101. package/dist/product-first-done-gate/evaluate.js +254 -31
  102. package/dist/product-first-done-gate/index.d.ts +2 -0
  103. package/dist/product-first-done-gate/index.js +1 -0
  104. package/dist/release/build-dist.d.ts +101 -0
  105. package/dist/release/build-dist.js +428 -46
  106. package/dist/run-summary/emit.d.ts +16 -10
  107. package/dist/run-summary/emit.js +26 -15
  108. package/dist/run-summary/index.d.ts +3 -2
  109. package/dist/run-summary/index.js +2 -1
  110. package/dist/run-summary/session-id.d.ts +21 -0
  111. package/dist/run-summary/session-id.js +92 -0
  112. package/dist/run-summary/types.d.ts +29 -4
  113. package/dist/run-summary/types.js +1 -0
  114. package/dist/scope/acceptance-evidence.d.ts +19 -7
  115. package/dist/scope/acceptance-evidence.js +38 -11
  116. package/dist/scope/delivery-evidence.d.ts +3 -3
  117. package/dist/scope/delivery-evidence.js +22 -27
  118. package/dist/scope/index.d.ts +1 -0
  119. package/dist/scope/index.js +1 -0
  120. package/dist/scope/parent-lineage.js +7 -6
  121. package/dist/scope/project-invariant-coverage.d.ts +54 -0
  122. package/dist/scope/project-invariant-coverage.js +322 -0
  123. package/dist/scope/transition.js +1 -1
  124. package/dist/scope-provenance/compare-intent.d.ts +27 -0
  125. package/dist/scope-provenance/compare-intent.js +233 -0
  126. package/dist/scope-provenance/digest.d.ts +18 -1
  127. package/dist/scope-provenance/digest.js +16 -11
  128. package/dist/scope-provenance/evaluate.d.ts +5 -1
  129. package/dist/scope-provenance/evaluate.js +64 -4
  130. package/dist/scope-provenance/extract-intent.d.ts +43 -0
  131. package/dist/scope-provenance/extract-intent.js +262 -0
  132. package/dist/scope-provenance/index.d.ts +7 -1
  133. package/dist/scope-provenance/index.js +7 -1
  134. package/dist/scope-provenance/intent-digest.d.ts +12 -0
  135. package/dist/scope-provenance/intent-digest.js +33 -0
  136. package/dist/scope-provenance/intent-evaluate.d.ts +43 -0
  137. package/dist/scope-provenance/intent-evaluate.js +149 -0
  138. package/dist/scope-provenance/json-tokenizer.d.ts +19 -0
  139. package/dist/scope-provenance/json-tokenizer.js +225 -0
  140. package/dist/scope-provenance/known-machine.d.ts +38 -0
  141. package/dist/scope-provenance/known-machine.js +157 -0
  142. package/dist/scope-provenance/mint-artifacts.d.ts +102 -0
  143. package/dist/scope-provenance/mint-artifacts.js +425 -0
  144. package/dist/session/ac-pass-banking.d.ts +4 -36
  145. package/dist/session/ac-pass-banking.js +30 -77
  146. package/dist/session/ac-pass-reuse.d.ts +53 -0
  147. package/dist/session/ac-pass-reuse.js +95 -0
  148. package/dist/session/git.js +19 -4
  149. package/dist/session/index.d.ts +4 -0
  150. package/dist/session/index.js +4 -0
  151. package/dist/session/occupancy-stress-worker.d.ts +7 -0
  152. package/dist/session/occupancy-stress-worker.js +36 -0
  153. package/dist/session/occupancy.d.ts +97 -0
  154. package/dist/session/occupancy.js +422 -0
  155. package/dist/session/openclaw-soft-rebind-deposit.js +6 -6
  156. package/dist/session/product-state-hash.d.ts +26 -0
  157. package/dist/session/product-state-hash.js +683 -0
  158. package/dist/session/session-ready.d.ts +2 -0
  159. package/dist/session/session-ready.js +52 -30
  160. package/dist/session/session-start.d.ts +7 -0
  161. package/dist/session/session-start.js +71 -7
  162. package/dist/session/verify-ac-session-cache.d.ts +42 -0
  163. package/dist/session/verify-ac-session-cache.js +126 -0
  164. package/dist/session/verify-session-ritual.d.ts +5 -0
  165. package/dist/session/verify-session-ritual.js +9 -0
  166. package/dist/slash/openclaw-deposit.js +13 -9
  167. package/dist/slice/constants.d.ts +2 -2
  168. package/dist/slice/constants.js +2 -2
  169. package/dist/slice/existing.js +9 -3
  170. package/dist/slice/lock.d.ts +16 -1
  171. package/dist/slice/lock.js +137 -11
  172. package/dist/story-ready/evaluate.d.ts +2 -0
  173. package/dist/story-ready/evaluate.js +13 -0
  174. package/dist/swarm/complete-cohort.d.ts +3 -0
  175. package/dist/swarm/complete-cohort.js +59 -11
  176. package/dist/swarm/finalize-cohort.js +33 -2
  177. package/dist/swarm/launch.d.ts +22 -0
  178. package/dist/swarm/launch.js +155 -0
  179. package/dist/swarm/routing-set-cli.d.ts +11 -1
  180. package/dist/swarm/routing-set-cli.js +13 -3
  181. package/dist/swarm/routing-verify.d.ts +12 -0
  182. package/dist/swarm/routing-verify.js +59 -20
  183. package/dist/swarm/routing.d.ts +14 -0
  184. package/dist/swarm/routing.js +53 -3
  185. package/dist/telemetry-coverage/fake-trial.js +10 -0
  186. package/dist/telemetry-coverage/kinds.js +2 -0
  187. package/dist/triage/actions/index.js +4 -1
  188. package/dist/ts-check-lane/index.d.ts +3 -0
  189. package/dist/ts-check-lane/index.js +2 -0
  190. package/dist/ts-check-lane/progress-reporter.d.ts +17 -0
  191. package/dist/ts-check-lane/progress-reporter.js +38 -0
  192. package/dist/ts-check-lane/progress.d.ts +32 -0
  193. package/dist/ts-check-lane/progress.js +57 -0
  194. package/dist/ts-check-lane/run-lane.d.ts +3 -1
  195. package/dist/ts-check-lane/run-lane.js +8 -6
  196. package/dist/validate-content/validate-links.d.ts +8 -0
  197. package/dist/validate-content/validate-links.js +9 -15
  198. package/dist/value/feedback-file.js +12 -2
  199. package/dist/vbrief-build/index.d.ts +1 -0
  200. package/dist/vbrief-build/index.js +1 -0
  201. package/dist/vbrief-build/project-invariants-io.d.ts +16 -0
  202. package/dist/vbrief-build/project-invariants-io.js +41 -0
  203. package/dist/vbrief-reconcile/graph.js +18 -1
  204. package/dist/vbrief-reconcile/index.d.ts +1 -1
  205. package/dist/vbrief-reconcile/index.js +1 -1
  206. package/dist/vbrief-reconcile/types.d.ts +13 -0
  207. package/dist/vbrief-reconcile/umbrellas.d.ts +14 -0
  208. package/dist/vbrief-reconcile/umbrellas.js +261 -26
  209. package/dist/vbrief-validate/index.d.ts +1 -1
  210. package/dist/vbrief-validate/index.js +1 -1
  211. package/dist/vbrief-validate/plan-hooks.d.ts +4 -0
  212. package/dist/vbrief-validate/plan-hooks.js +68 -0
  213. package/dist/verify-ac/evaluate.d.ts +7 -1
  214. package/dist/verify-ac/evaluate.js +34 -26
  215. package/dist/verify-ac/flag.d.ts +4 -0
  216. package/dist/verify-ac/flag.js +16 -0
  217. package/dist/verify-ac/index.d.ts +2 -2
  218. package/dist/verify-ac/index.js +2 -2
  219. package/dist/verify-source/contained-writes.js +2 -0
  220. package/dist/verify-source/verify-stubs.d.ts +15 -1
  221. package/dist/verify-source/verify-stubs.js +20 -16
  222. package/dist/vitest-runner/win32-coverage-tmp-setup.d.ts +5 -6
  223. package/dist/vitest-runner/win32-coverage-tmp-setup.js +5 -6
  224. package/dist/xbrief-migrate/migrate-project.js +2 -5
  225. package/package.json +3 -3
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { existsSync, readFileSync } from "node:fs";
5
5
  import { resolve } from "node:path";
6
- import { captureLiteralAcceptanceCommandsDetailed, formatRejectedLedger, readStoredLiteralAcceptanceDetailed, } from "./capture.js";
6
+ import { captureLiteralAcceptanceCommandsDetailed, formatRejectedLedger, isProseDerivedRejection, readStoredLiteralAcceptanceDetailed, } from "./capture.js";
7
7
  import { runLiteralAcceptanceCommands } from "./run.js";
8
8
  function asRecord(value) {
9
9
  if (typeof value === "object" && value !== null && !Array.isArray(value)) {
@@ -14,6 +14,24 @@ function asRecord(value) {
14
14
  function planOf(data) {
15
15
  return asRecord(data.plan);
16
16
  }
17
+ /**
18
+ * Prose-derived rejections are advisory (#3484 / #3511). A scraper misread must
19
+ * not block completion, whether or not the plan states structured commands —
20
+ * blocking on a capture the extractor itself rejected is backwards. Rejections
21
+ * from structured fields (`swarm.verify_commands`, plan items, explicit metadata)
22
+ * keep blocking — those are real commands the author asked for.
23
+ */
24
+ function partitionRejected(rejected) {
25
+ const blocking = [];
26
+ const advisory = [];
27
+ for (const r of rejected) {
28
+ if (isProseDerivedRejection(r))
29
+ advisory.push(r);
30
+ else
31
+ blocking.push(r);
32
+ }
33
+ return { blocking, advisory };
34
+ }
17
35
  /**
18
36
  * Resolve commands + rejected ledger.
19
37
  * Stored first; when captureFromNarratives is true (default), also re-scan narratives
@@ -21,6 +39,16 @@ function planOf(data) {
21
39
  * (Greptile conf residual).
22
40
  */
23
41
  export function resolveLiteralAcceptanceDetailed(plan, options = {}) {
42
+ const raw = resolveRawLiteralAcceptance(plan, options);
43
+ const split = partitionRejected(raw.rejected);
44
+ return {
45
+ commands: raw.commands,
46
+ rejected: split.blocking,
47
+ advisoryRejected: split.advisory,
48
+ transcriptPromptSkipped: raw.transcriptPromptSkipped,
49
+ };
50
+ }
51
+ function resolveRawLiteralAcceptance(plan, options = {}) {
24
52
  const stored = readStoredLiteralAcceptanceDetailed(plan);
25
53
  if (options.captureFromNarratives === false) {
26
54
  return stored;
@@ -74,7 +102,11 @@ export function resolveLiteralAcceptanceDetailed(plan, options = {}) {
74
102
  rejectedSeen.add(k);
75
103
  rejected.push(r);
76
104
  }
77
- return { commands, rejected };
105
+ return {
106
+ commands,
107
+ rejected,
108
+ transcriptPromptSkipped: captured.transcriptPromptSkipped,
109
+ };
78
110
  }
79
111
  /**
80
112
  * Resolve commands: stored first; optional narrative re-capture when empty.
@@ -82,6 +114,36 @@ export function resolveLiteralAcceptanceDetailed(plan, options = {}) {
82
114
  export function resolveLiteralAcceptanceCommands(plan, options = {}) {
83
115
  return [...resolveLiteralAcceptanceDetailed(plan, options).commands];
84
116
  }
117
+ /**
118
+ * Marker that opens the #3484 advisory block. Consumers strip from here to the end
119
+ * before any free-text inspection of a literal-AC message: the block quotes refusal
120
+ * reasons that were explicitly demoted and must not be read back as blocking (#3497).
121
+ */
122
+ export const LITERAL_ACCEPTANCE_ADVISORY_MARKER = "Literal acceptance advisory (#3484):";
123
+ /** Render the #3484 advisory block (reported, never blocking). */
124
+ export function formatLiteralAcceptanceAdvisory(advisory) {
125
+ if (advisory.length === 0)
126
+ return "";
127
+ return (`${LITERAL_ACCEPTANCE_ADVISORY_MARKER} ${advisory.length} ` +
128
+ `prose/fence-derived capture(s) were safety-rejected but do NOT block — ` +
129
+ `the extractor is not confident these are stated acceptance commands (#3511).\n` +
130
+ formatRejectedLedger(advisory));
131
+ }
132
+ /** Append the #3484 advisory block to a message tail. */
133
+ export function appendLiteralAcceptanceAdvisory(message, advisory) {
134
+ const block = formatLiteralAcceptanceAdvisory(advisory);
135
+ if (block.length === 0)
136
+ return message;
137
+ return message.length > 0 ? `${message}\n${block}` : block;
138
+ }
139
+ /**
140
+ * Drop the #3484 advisory block from a rendered message.
141
+ * The block is always the tail, so an index cut is exact.
142
+ */
143
+ export function stripLiteralAcceptanceAdvisory(message) {
144
+ const at = message.indexOf(LITERAL_ACCEPTANCE_ADVISORY_MARKER);
145
+ return at === -1 ? message : message.slice(0, at);
146
+ }
85
147
  function appendRejectedNote(message, rejected) {
86
148
  const ledger = formatRejectedLedger(rejected);
87
149
  if (ledger.length === 0)
@@ -120,11 +182,17 @@ export function evaluateLiteralAcceptanceFromPlan(plan, options = {}) {
120
182
  ledger +
121
183
  (result.message.length > 0 ? `\n${result.message}` : "");
122
184
  }
185
+ // Prose/fence-derived rejections (#3484 / #3511) are reported, never blocking.
186
+ if (resolved.advisoryRejected.length > 0) {
187
+ message = appendLiteralAcceptanceAdvisory(message, resolved.advisoryRejected);
188
+ }
123
189
  const withRejected = {
124
190
  ...result,
125
191
  ok,
126
192
  code,
127
193
  rejected: resolved.rejected,
194
+ advisoryRejected: resolved.advisoryRejected,
195
+ transcriptPromptSkipped: resolved.transcriptPromptSkipped,
128
196
  message,
129
197
  };
130
198
  if (options.quiet === true && withRejected.ok) {
@@ -4,9 +4,9 @@
4
4
  * Capture exact stated shell commands at intake; run them verbatim before done.
5
5
  * Extends #973; survives ceremony dial rapid/minimal (#3214).
6
6
  */
7
- export { attachLiteralAcceptanceCommands, type CaptureLiteralAcceptanceResult, captureAndAttachLiteralAcceptance, captureLiteralAcceptanceCommands, captureLiteralAcceptanceCommandsDetailed, formatRejectedLedger, readStoredLiteralAcceptanceCommands, readStoredLiteralAcceptanceDetailed, } from "./capture.js";
8
- export { type EvaluateLiteralAcceptanceOptions, evaluateLiteralAcceptanceFromPath, evaluateLiteralAcceptanceFromPlan, isLiteralAcceptanceRequiredAtCeremonyDepth, resolveLiteralAcceptanceCommands, resolveLiteralAcceptanceDetailed, } from "./evaluate.js";
7
+ export { attachLiteralAcceptanceCommands, type CaptureLiteralAcceptanceResult, captureAndAttachLiteralAcceptance, captureLiteralAcceptanceCommands, captureLiteralAcceptanceCommandsDetailed, formatRejectedLedger, hasStructuredAcceptanceCommands, isProseDerivedRejection, readStoredLiteralAcceptanceCommands, readStoredLiteralAcceptanceDetailed, } from "./capture.js";
8
+ export { appendLiteralAcceptanceAdvisory, type EvaluateLiteralAcceptanceOptions, evaluateLiteralAcceptanceFromPath, evaluateLiteralAcceptanceFromPlan, formatLiteralAcceptanceAdvisory, isLiteralAcceptanceRequiredAtCeremonyDepth, LITERAL_ACCEPTANCE_ADVISORY_MARKER, type ResolvedLiteralAcceptance, resolveLiteralAcceptanceCommands, resolveLiteralAcceptanceDetailed, stripLiteralAcceptanceAdvisory, } from "./evaluate.js";
9
9
  export { defaultLiteralAcceptanceRunner, runLiteralAcceptanceCommand, runLiteralAcceptanceCommands, } from "./run.js";
10
- export { type CommandSafetyResult, evaluateCommandSafety, isExecutableLiteralSource, } from "./safety.js";
10
+ export { type CommandSafetyResult, evaluateCommandSafety, evaluateNoopDenylist, evaluateStampAcceptanceSafety, isExecutableLiteralSource, isNoopRefusalReason, isVerbatimStatementSpan, NOOP_ACCEPTANCE_REMEDIATION, REJECTED_NOOP_OUTCOME, type RejectedNoopOutcome, type StampAcceptanceCommand, type StampAcceptanceSafetyInput, type StampAcceptanceSafetyResult, type StampSourceRung, } from "./safety.js";
11
11
  export { EXECUTABLE_LITERAL_SOURCES, LITERAL_ACCEPTANCE_METADATA_KEY, LITERAL_ACCEPTANCE_METADATA_KEY_CAMEL, LITERAL_ACCEPTANCE_REJECTED_METADATA_KEY, type LiteralAcceptanceCommand, type LiteralAcceptanceGateResult, type LiteralAcceptanceRunner, type LiteralAcceptanceRunResult, type LiteralAcceptanceSource, type RejectedLiteralCommand, } from "./types.js";
12
12
  //# sourceMappingURL=index.d.ts.map
@@ -4,9 +4,9 @@
4
4
  * Capture exact stated shell commands at intake; run them verbatim before done.
5
5
  * Extends #973; survives ceremony dial rapid/minimal (#3214).
6
6
  */
7
- export { attachLiteralAcceptanceCommands, captureAndAttachLiteralAcceptance, captureLiteralAcceptanceCommands, captureLiteralAcceptanceCommandsDetailed, formatRejectedLedger, readStoredLiteralAcceptanceCommands, readStoredLiteralAcceptanceDetailed, } from "./capture.js";
8
- export { evaluateLiteralAcceptanceFromPath, evaluateLiteralAcceptanceFromPlan, isLiteralAcceptanceRequiredAtCeremonyDepth, resolveLiteralAcceptanceCommands, resolveLiteralAcceptanceDetailed, } from "./evaluate.js";
7
+ export { attachLiteralAcceptanceCommands, captureAndAttachLiteralAcceptance, captureLiteralAcceptanceCommands, captureLiteralAcceptanceCommandsDetailed, formatRejectedLedger, hasStructuredAcceptanceCommands, isProseDerivedRejection, readStoredLiteralAcceptanceCommands, readStoredLiteralAcceptanceDetailed, } from "./capture.js";
8
+ export { appendLiteralAcceptanceAdvisory, evaluateLiteralAcceptanceFromPath, evaluateLiteralAcceptanceFromPlan, formatLiteralAcceptanceAdvisory, isLiteralAcceptanceRequiredAtCeremonyDepth, LITERAL_ACCEPTANCE_ADVISORY_MARKER, resolveLiteralAcceptanceCommands, resolveLiteralAcceptanceDetailed, stripLiteralAcceptanceAdvisory, } from "./evaluate.js";
9
9
  export { defaultLiteralAcceptanceRunner, runLiteralAcceptanceCommand, runLiteralAcceptanceCommands, } from "./run.js";
10
- export { evaluateCommandSafety, isExecutableLiteralSource, } from "./safety.js";
10
+ export { evaluateCommandSafety, evaluateNoopDenylist, evaluateStampAcceptanceSafety, isExecutableLiteralSource, isNoopRefusalReason, isVerbatimStatementSpan, NOOP_ACCEPTANCE_REMEDIATION, REJECTED_NOOP_OUTCOME, } from "./safety.js";
11
11
  export { EXECUTABLE_LITERAL_SOURCES, LITERAL_ACCEPTANCE_METADATA_KEY, LITERAL_ACCEPTANCE_METADATA_KEY_CAMEL, LITERAL_ACCEPTANCE_REJECTED_METADATA_KEY, } from "./types.js";
12
12
  //# sourceMappingURL=index.js.map
@@ -10,10 +10,51 @@
10
10
  * mutations cannot ride an acceptance command (#3267 residual).
11
11
  */
12
12
  import type { LiteralAcceptanceSource } from "./types.js";
13
+ /** One remediation when a command cannot fail (#3396). */
14
+ export declare const NOOP_ACCEPTANCE_REMEDIATION = "acceptance commands must be able to fail; name a command that exercises the artifact";
15
+ /** Capture/stamp outcome recorded on the acceptance event (#3396). */
16
+ export declare const REJECTED_NOOP_OUTCOME: "rejected-noop";
17
+ export type RejectedNoopOutcome = typeof REJECTED_NOOP_OUTCOME;
13
18
  export interface CommandSafetyResult {
14
19
  readonly ok: boolean;
15
20
  readonly reason: string | null;
21
+ /** Set when the command is a denylisted no-op (#3396). */
22
+ readonly outcome?: RejectedNoopOutcome;
16
23
  }
24
+ /**
25
+ * Unconditional no-ops cannot be acceptance oracles (#3396).
26
+ * `test` with only constant args is a no-op; `test -f path` is an assertion.
27
+ */
28
+ export declare function evaluateNoopDenylist(command: string): CommandSafetyResult;
29
+ /** True when a refusal reason is the #3396 no-op remediation. */
30
+ export declare function isNoopRefusalReason(reason: string | null | undefined): boolean;
31
+ /**
32
+ * Capture records verbatim statement spans as fence@ / labeled@ / prompt@ / inline@.
33
+ * Metadata and plan.acceptance mirrors are not statement provenance.
34
+ */
35
+ export declare function isVerbatimStatementSpan(sourceSpan: string | null | undefined): boolean;
36
+ export type StampSourceRung = "stated" | "derived" | "project_floor";
37
+ export interface StampAcceptanceCommand {
38
+ readonly command: string;
39
+ readonly source?: string;
40
+ readonly sourceSpan?: string | null;
41
+ }
42
+ export interface StampAcceptanceSafetyInput {
43
+ readonly commands: readonly StampAcceptanceCommand[];
44
+ readonly previousRung?: StampSourceRung | null;
45
+ }
46
+ export interface StampAcceptanceSafetyResult {
47
+ readonly ok: boolean;
48
+ readonly reason: string | null;
49
+ readonly outcome?: RejectedNoopOutcome;
50
+ readonly sourceRung: StampSourceRung;
51
+ readonly hasVerbatimStatementSpan: boolean;
52
+ }
53
+ /**
54
+ * Stamp-time no-op refuse + stated-only-with-span (#3396).
55
+ * A restamp cannot raise the rung to stated without a recorded statement span.
56
+ */
57
+ export declare function evaluateStampAcceptanceSafety(input: StampAcceptanceSafetyInput): StampAcceptanceSafetyResult;
17
58
  /** Whether this provenance is allowed to spawn a shell (#3267). */
18
59
  export declare function isExecutableLiteralSource(source: LiteralAcceptanceSource | string): boolean;
19
60
  /**
@@ -43,8 +43,6 @@ const ALLOWED_FIRST_TOKENS = new Set([
43
43
  "yarn",
44
44
  "bun",
45
45
  "vitest",
46
- "true",
47
- "false",
48
46
  ]);
49
47
  /**
50
48
  * Exact wrapper subcommands that are verification-shaped (no scope/policy/scm/swarm
@@ -65,6 +63,128 @@ const ALLOWED_WRAPPER_SUBCOMMANDS = new Set([
65
63
  * `verify:` / `verify-` cover task verify:* family; bare `verify ` is the space form.
66
64
  */
67
65
  const ALLOWED_WRAPPER_PREFIXES = ["verify:", "verify-", "verify "];
66
+ /** One remediation when a command cannot fail (#3396). */
67
+ export const NOOP_ACCEPTANCE_REMEDIATION = "acceptance commands must be able to fail; name a command that exercises the artifact";
68
+ /** Capture/stamp outcome recorded on the acceptance event (#3396). */
69
+ export const REJECTED_NOOP_OUTCOME = "rejected-noop";
70
+ /** First tokens that always succeed or always fail without exercising an artifact. */
71
+ const NOOP_FIRST_TOKENS = new Set(["true", "false", ":", "echo", "printf"]);
72
+ /** `test` operators that inspect a path (not a constant comparison). */
73
+ const TEST_FILE_OPERATORS = new Set([
74
+ "-b",
75
+ "-c",
76
+ "-d",
77
+ "-e",
78
+ "-f",
79
+ "-g",
80
+ "-h",
81
+ "-k",
82
+ "-L",
83
+ "-p",
84
+ "-r",
85
+ "-S",
86
+ "-s",
87
+ "-t",
88
+ "-u",
89
+ "-w",
90
+ "-x",
91
+ ]);
92
+ function firstTokenAndRest(trimmed) {
93
+ let end = 0;
94
+ while (end < trimmed.length && trimmed[end] !== " " && trimmed[end] !== "\t") {
95
+ end += 1;
96
+ }
97
+ return { first: trimmed.slice(0, end).toLowerCase(), rest: trimmed.slice(end).trim() };
98
+ }
99
+ function noopRefusal() {
100
+ return {
101
+ ok: false,
102
+ reason: NOOP_ACCEPTANCE_REMEDIATION,
103
+ outcome: REJECTED_NOOP_OUTCOME,
104
+ };
105
+ }
106
+ /**
107
+ * Unconditional no-ops cannot be acceptance oracles (#3396).
108
+ * `test` with only constant args is a no-op; `test -f path` is an assertion.
109
+ */
110
+ export function evaluateNoopDenylist(command) {
111
+ if (typeof command !== "string") {
112
+ return { ok: true, reason: null };
113
+ }
114
+ const trimmed = command.trim();
115
+ if (trimmed.length === 0) {
116
+ return { ok: true, reason: null };
117
+ }
118
+ const { first, rest } = firstTokenAndRest(trimmed);
119
+ if (NOOP_FIRST_TOKENS.has(first)) {
120
+ return noopRefusal();
121
+ }
122
+ if (first === "exit" && rest.length === 0) {
123
+ return noopRefusal();
124
+ }
125
+ if (first === "test") {
126
+ const tokens = rest.length === 0 ? [] : rest.split(/\s+/);
127
+ if (!tokens.some((token) => TEST_FILE_OPERATORS.has(token))) {
128
+ return noopRefusal();
129
+ }
130
+ }
131
+ return { ok: true, reason: null };
132
+ }
133
+ /** True when a refusal reason is the #3396 no-op remediation. */
134
+ export function isNoopRefusalReason(reason) {
135
+ return typeof reason === "string" && reason.includes("acceptance commands must be able to fail");
136
+ }
137
+ /**
138
+ * Capture records verbatim statement spans as fence@ / labeled@ / prompt@ / inline@.
139
+ * Metadata and plan.acceptance mirrors are not statement provenance.
140
+ */
141
+ export function isVerbatimStatementSpan(sourceSpan) {
142
+ if (typeof sourceSpan !== "string" || sourceSpan.trim().length === 0) {
143
+ return false;
144
+ }
145
+ return /^(fence|labeled|prompt|inline)@/i.test(sourceSpan.trim());
146
+ }
147
+ function commandHasStatementProvenance(cmd) {
148
+ if (cmd.source !== undefined && cmd.source !== "task_statement") {
149
+ return false;
150
+ }
151
+ return isVerbatimStatementSpan(cmd.sourceSpan ?? null);
152
+ }
153
+ /**
154
+ * Stamp-time no-op refuse + stated-only-with-span (#3396).
155
+ * A restamp cannot raise the rung to stated without a recorded statement span.
156
+ */
157
+ export function evaluateStampAcceptanceSafety(input) {
158
+ const hasVerbatimStatementSpan = input.commands.some(commandHasStatementProvenance);
159
+ let sourceRung;
160
+ if (input.commands.length === 0) {
161
+ sourceRung = input.previousRung ?? "project_floor";
162
+ }
163
+ else if (hasVerbatimStatementSpan) {
164
+ sourceRung = "stated";
165
+ }
166
+ else {
167
+ sourceRung = "derived";
168
+ }
169
+ for (const cmd of input.commands) {
170
+ const noop = evaluateNoopDenylist(cmd.command);
171
+ if (!noop.ok) {
172
+ return {
173
+ ok: false,
174
+ reason: noop.reason,
175
+ outcome: REJECTED_NOOP_OUTCOME,
176
+ sourceRung,
177
+ hasVerbatimStatementSpan,
178
+ };
179
+ }
180
+ }
181
+ return {
182
+ ok: true,
183
+ reason: null,
184
+ sourceRung,
185
+ hasVerbatimStatementSpan,
186
+ };
187
+ }
68
188
  /** Whether this provenance is allowed to spawn a shell (#3267). */
69
189
  export function isExecutableLiteralSource(source) {
70
190
  return EXECUTABLE_LITERAL_SOURCES.includes(source);
@@ -81,6 +201,10 @@ export function evaluateCommandSafety(command) {
81
201
  if (trimmed.length > 500) {
82
202
  return { ok: false, reason: "command exceeds 500 characters" };
83
203
  }
204
+ const noop = evaluateNoopDenylist(trimmed);
205
+ if (!noop.ok) {
206
+ return noop;
207
+ }
84
208
  for (let i = 0; i < trimmed.length; i += 1) {
85
209
  const ch = trimmed[i];
86
210
  if (SHELL_META_CHARS.has(ch)) {
@@ -63,6 +63,14 @@ export interface LiteralAcceptanceGateResult {
63
63
  readonly runs: readonly LiteralAcceptanceRunResult[];
64
64
  /** Safety-rejected shell-shaped lines (fail-loud ledger; may be empty). */
65
65
  readonly rejected?: readonly RejectedLiteralCommand[];
66
+ /**
67
+ * Prose/fence/inline-derived rejections demoted to advisory (#3484 / #3511).
68
+ * Reported, never blocking — consumers MUST NOT read these back as a blocking
69
+ * ledger, and must not sniff the rendered message for their reasons (#3497).
70
+ */
71
+ readonly advisoryRejected?: readonly RejectedLiteralCommand[];
72
+ /** Prompt lines skipped inside a transcript-shaped fence (#3511). */
73
+ readonly transcriptPromptSkipped?: number;
66
74
  }
67
75
  /** Metadata key for operator-visible rejected command ledger (#3267). */
68
76
  export declare const LITERAL_ACCEPTANCE_REJECTED_METADATA_KEY: "literal_acceptance_rejected";
@@ -1,8 +1,10 @@
1
1
  import type { RunGhFn } from "../pr-protected-issues/types.js";
2
2
  export type OutputStream = "stdout" | "stderr" | "none";
3
+ export type OrphanKind = "shipped" | "unresolved";
3
4
  export interface OrphanActiveBrief {
4
5
  readonly path: string;
5
6
  readonly reason: string;
7
+ readonly kind: OrphanKind;
6
8
  }
7
9
  export interface EvaluateResult {
8
10
  readonly code: 0 | 1 | 2;
@@ -15,11 +17,15 @@ export interface EvaluateOptions {
15
17
  readonly repo?: string | null;
16
18
  readonly runGh?: RunGhFn;
17
19
  readonly skipGh?: boolean;
20
+ /** When set, scan only active/running briefs that reference this issue (#3429). */
21
+ readonly issue?: number | null;
18
22
  }
19
23
  /**
20
- * Pure evaluator for orphaned active/running xBRIEF detection (#2321).
24
+ * Pure evaluator for orphaned active/running xBRIEF detection (#2321 / #3429).
21
25
  * Fails when active/ briefs with plan.status==running reference only closed
22
26
  * issues and/or a merged PR — the stop-at:pr-open orphan signature.
27
+ * Pass `issue` to scan one origin after merge. Confirmed shipped prints
28
+ * scope:complete; unresolved lookup still exits 1 with a retry remediation.
23
29
  */
24
30
  export declare function evaluate(projectRoot: string, options?: EvaluateOptions): EvaluateResult;
25
31
  //# sourceMappingURL=evaluate.d.ts.map
@@ -137,55 +137,127 @@ function fetchPrMerged(ref, runGh) {
137
137
  return null;
138
138
  }
139
139
  }
140
- function assessOrphanSignature(issueRefs, prRefs, projectRoot, runGh, skipGh) {
140
+ const PASS = { orphaned: false, reason: null, kind: null };
141
+ function shipped(reason) {
142
+ return { orphaned: true, reason, kind: "shipped" };
143
+ }
144
+ function unresolved(reason) {
145
+ return { orphaned: true, reason, kind: "unresolved" };
146
+ }
147
+ function assessOrphanSignature(issueRefs, prRefs, projectRoot, runGh, skipGh, selectedIssue) {
148
+ if (selectedIssue !== null) {
149
+ // Confirmed closed origin is shipped even if a linked PR lookup fails.
150
+ const selectedRef = issueRefs.find((ref) => ref.number === selectedIssue);
151
+ const selectedState = selectedRef === undefined ? null : resolveIssueState(selectedRef, projectRoot, runGh, skipGh);
152
+ if (selectedState === "closed") {
153
+ return shipped(`issue #${selectedIssue} is closed`);
154
+ }
155
+ for (const pr of prRefs) {
156
+ if (skipGh) {
157
+ return unresolved(`linked PR #${pr.number} state could not be resolved`);
158
+ }
159
+ const merged = fetchPrMerged(pr, runGh);
160
+ if (merged === true) {
161
+ return shipped(`linked PR #${pr.number} is merged`);
162
+ }
163
+ if (merged === null) {
164
+ return unresolved(`linked PR #${pr.number} state could not be resolved`);
165
+ }
166
+ }
167
+ // --issue N is one origin: sibling open/unknown must not mask it (#3429).
168
+ if (selectedRef !== undefined) {
169
+ if (selectedState === null) {
170
+ return unresolved(`issue #${selectedIssue} state could not be resolved`);
171
+ }
172
+ return PASS;
173
+ }
174
+ const issueStates = issueRefs.map((ref) => ({
175
+ ref,
176
+ state: resolveIssueState(ref, projectRoot, runGh, skipGh),
177
+ }));
178
+ const unknownIssue = issueStates.find((row) => row.state === null);
179
+ if (unknownIssue !== undefined) {
180
+ return unresolved(`issue #${unknownIssue.ref.number} state could not be resolved`);
181
+ }
182
+ if (issueStates.some((row) => row.state === "closed")) {
183
+ return shipped("all referenced issues are closed");
184
+ }
185
+ if (prRefs.length > 0 && skipGh) {
186
+ return unresolved(`linked PR #${prRefs[0]?.number} state could not be resolved`);
187
+ }
188
+ return PASS;
189
+ }
141
190
  for (const pr of prRefs) {
142
191
  if (skipGh) {
143
192
  continue;
144
193
  }
145
194
  const merged = fetchPrMerged(pr, runGh);
146
195
  if (merged === true) {
147
- return { orphaned: true, reason: `linked PR #${pr.number} is merged` };
196
+ return shipped(`linked PR #${pr.number} is merged`);
148
197
  }
149
198
  }
150
199
  if (issueRefs.length === 0) {
151
- return { orphaned: false, reason: null };
200
+ return PASS;
152
201
  }
153
202
  let resolved = 0;
154
203
  for (const ref of issueRefs) {
155
204
  const state = resolveIssueState(ref, projectRoot, runGh, skipGh);
156
205
  if (state === null) {
157
- return { orphaned: false, reason: null };
206
+ return PASS;
158
207
  }
159
208
  resolved += 1;
160
209
  if (state !== "closed") {
161
- return { orphaned: false, reason: null };
210
+ return PASS;
162
211
  }
163
212
  }
164
213
  if (resolved > 0) {
165
- return { orphaned: true, reason: "all referenced issues are closed" };
214
+ return shipped("all referenced issues are closed");
166
215
  }
167
- return { orphaned: false, reason: null };
216
+ return PASS;
168
217
  }
169
- function formatRefusal(orphans, projectRoot) {
170
- const lines = [
171
- `verify:orphan-active: ${orphans.length} active/running xBRIEF${orphans.length === 1 ? "" : "s"} look shipped but still consume WIP (project_root=${projectRoot}).`,
172
- " Remediation: move each brief out of active/ with lifecycle ownership:",
173
- " task scope:complete -- xbrief/active/<file>.xbrief.json",
174
- " task scope:cancel -- xbrief/active/<file>.xbrief.json # when abandoning",
175
- " For stop-at:pr-open workers the orchestrator owns post-merge complete/cancel;",
176
- " for drive-to:merge-ready workers scope:complete is part of the worker unit (#2321).",
177
- " Or run task swarm:finalize-cohort / task swarm:complete-cohort after cohort merge.",
178
- " Offending briefs:",
179
- ];
218
+ function briefReferencesIssue(issues, issue) {
219
+ return issues.some((ref) => ref.number === issue);
220
+ }
221
+ function formatRefusal(orphans, projectRoot, issueFilter) {
222
+ const shippedOrphans = orphans.filter((orphan) => orphan.kind === "shipped");
223
+ const unresolvedOrphans = orphans.filter((orphan) => orphan.kind === "unresolved");
224
+ const noun = orphans.length === 1 ? "" : "s";
225
+ let headline;
226
+ if (unresolvedOrphans.length > 0 && shippedOrphans.length === 0) {
227
+ headline = `verify:orphan-active: ${unresolvedOrphans.length} active/running xBRIEF${unresolvedOrphans.length === 1 ? "" : "s"} have unresolved GitHub state (cannot confirm shipped) (project_root=${projectRoot}).`;
228
+ }
229
+ else if (shippedOrphans.length > 0 && unresolvedOrphans.length === 0) {
230
+ headline = `verify:orphan-active: ${shippedOrphans.length} active/running xBRIEF${shippedOrphans.length === 1 ? "" : "s"} look shipped but still consume WIP (project_root=${projectRoot}).`;
231
+ }
232
+ else {
233
+ headline = `verify:orphan-active: ${orphans.length} active/running xBRIEF${noun} failed the after-merge check (project_root=${projectRoot}).`;
234
+ }
235
+ const lines = [headline];
236
+ if (shippedOrphans.length > 0) {
237
+ lines.push(" Remediation: move each confirmed-shipped brief out of active/ with lifecycle ownership:");
238
+ for (const orphan of shippedOrphans) {
239
+ lines.push(` task scope:complete -- ${orphan.path}`);
240
+ }
241
+ lines.push(" task scope:cancel -- xbrief/active/<file>.xbrief.json # when abandoning", " For stop-at:pr-open workers the orchestrator owns post-merge complete/cancel;", " for drive-to:merge-ready workers scope:complete is part of the worker unit (#2321 / #3429).", " Or run task swarm:finalize-cohort / task swarm:complete-cohort after cohort merge.");
242
+ }
243
+ if (unresolvedOrphans.length > 0) {
244
+ const retry = issueFilter === null
245
+ ? "task verify:orphan-active"
246
+ : `task verify:orphan-active -- --issue ${issueFilter}`;
247
+ lines.push(" Remediation: retry the GitHub lookup (auth, rate-limit, network, skipGh) then re-run:", ` ${retry}`, " Do not run task scope:complete until the origin is confirmed closed or the linked PR is confirmed merged.");
248
+ }
249
+ lines.push(" Offending briefs:");
180
250
  for (const orphan of orphans) {
181
251
  lines.push(` - ${orphan.path} (${orphan.reason})`);
182
252
  }
183
253
  return lines.join("\n");
184
254
  }
185
255
  /**
186
- * Pure evaluator for orphaned active/running xBRIEF detection (#2321).
256
+ * Pure evaluator for orphaned active/running xBRIEF detection (#2321 / #3429).
187
257
  * Fails when active/ briefs with plan.status==running reference only closed
188
258
  * issues and/or a merged PR — the stop-at:pr-open orphan signature.
259
+ * Pass `issue` to scan one origin after merge. Confirmed shipped prints
260
+ * scope:complete; unresolved lookup still exits 1 with a retry remediation.
189
261
  */
190
262
  export function evaluate(projectRoot, options = {}) {
191
263
  const root = resolve(projectRoot);
@@ -238,24 +310,30 @@ export function evaluate(projectRoot, options = {}) {
238
310
  orphans: [],
239
311
  };
240
312
  }
313
+ const issueFilter = options.issue ?? null;
241
314
  const orphans = [];
242
315
  for (const brief of listActiveRunningBriefs(root)) {
243
316
  const { issues, prs } = collectGithubRefs(brief.plan, defaultRepo);
317
+ // --issue N is one origin: briefs that name that issue. PR-only briefs stay on the unscoped scan (#3429).
318
+ if (issueFilter !== null && !briefReferencesIssue(issues, issueFilter)) {
319
+ continue;
320
+ }
244
321
  if (issues.length === 0 && prs.length === 0) {
245
322
  continue;
246
323
  }
247
- const assessment = assessOrphanSignature(issues, prs, root, runGh, skipGh);
248
- if (assessment.orphaned && assessment.reason !== null) {
324
+ const assessment = assessOrphanSignature(issues, prs, root, runGh, skipGh, issueFilter);
325
+ if (assessment.orphaned && assessment.reason !== null && assessment.kind !== null) {
249
326
  orphans.push({
250
327
  path: relBriefPath(brief.path, root),
251
328
  reason: assessment.reason,
329
+ kind: assessment.kind,
252
330
  });
253
331
  }
254
332
  }
255
333
  if (orphans.length > 0) {
256
334
  return {
257
335
  code: 1,
258
- message: formatRefusal(orphans, root),
336
+ message: formatRefusal(orphans, root, issueFilter),
259
337
  stream: "stderr",
260
338
  orphans,
261
339
  };
@@ -264,9 +342,10 @@ export function evaluate(projectRoot, options = {}) {
264
342
  return { code: 0, message: "", stream: "none", orphans: [] };
265
343
  }
266
344
  const scanned = listActiveRunningBriefs(root).length;
345
+ const issueNote = issueFilter === null ? "" : ` for issue #${issueFilter}`;
267
346
  return {
268
347
  code: 0,
269
- message: `verify:orphan-active: no orphaned active/running xBRIEFs ` +
348
+ message: `verify:orphan-active: no orphaned active/running xBRIEFs${issueNote} ` +
270
349
  `(scanned ${scanned} running brief${scanned === 1 ? "" : "s"} in active/).`,
271
350
  stream: "stdout",
272
351
  orphans: [],
@@ -72,10 +72,9 @@ export function classifyIdentityKind(options) {
72
72
  function isCloudHeadless(environ) {
73
73
  if (envTruthy(environ, "CURSOR_AGENT"))
74
74
  return true;
75
- if (envTruthy(environ, "GROK_BUILD"))
76
- return true;
75
+ // GROK_BUILD / DEFT_AGENT_RUNTIME=grok-build identify a local TUI, not CI (#3469).
77
76
  const runtime = (environ.DEFT_AGENT_RUNTIME ?? "").trim().toLowerCase();
78
- if (runtime === "grok-build" || runtime === "cloud" || runtime === "headless")
77
+ if (runtime === "cloud" || runtime === "headless")
79
78
  return true;
80
79
  if (envTruthy(environ, "GITHUB_ACTIONS") || envTruthy(environ, "BUILDKITE"))
81
80
  return true;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Typed plan.policy.baseBranch (#3388).
3
+ *
4
+ * Integration-branch source for the shared branch-sync detector. Distinct from
5
+ * deliveryBranch (dest). Unset or invalid baseBranch resolves to dest so sync
6
+ * is a no-op. origin/develop is never identity; it may only emit a hint.
7
+ */
8
+ import { type GitRunner } from "../session/git.js";
9
+ export declare const FIELD_BASE_BRANCH = "plan.policy.baseBranch";
10
+ export declare const FIELD_BASE_BRANCH_CLI_ALIAS = "baseBranch";
11
+ /** Nudge only — never used as dest or source identity (#3388 / #3377 Q1). */
12
+ export declare const ORIGIN_DEVELOP_HINT = "origin/develop exists; set plan.policy.baseBranch if this repo uses an integration branch";
13
+ export type BaseBranchSource = "typed" | "equals-dest" | "default-on-error";
14
+ export interface BaseBranchResult {
15
+ readonly branch: string;
16
+ readonly dest: string;
17
+ readonly source: BaseBranchSource;
18
+ readonly typed: boolean;
19
+ readonly error: string | null;
20
+ readonly developHint: string | null;
21
+ }
22
+ /**
23
+ * Resolve plan.policy.baseBranch (#3388).
24
+ *
25
+ * Unset or invalid values equal dest (deliveryBranch). origin/develop is never
26
+ * substituted as the source.
27
+ */
28
+ export declare function resolveBaseBranch(projectRoot: string, runGit?: GitRunner): BaseBranchResult;
29
+ export interface BaseBranchPolicyField {
30
+ readonly name: string;
31
+ readonly current: string;
32
+ readonly default: string;
33
+ readonly source: string;
34
+ }
35
+ /** Inspector row for `task policy:show --field=baseBranch` (#3388). */
36
+ export declare function inspectBaseBranch(_data: Record<string, unknown> | null, projectRoot?: string): BaseBranchPolicyField;
37
+ //# sourceMappingURL=base-branch.d.ts.map