@deftai/directive-runtime 0.129.5 → 0.129.7

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 (222) hide show
  1. package/Taskfile.yml +316 -0
  2. package/UPGRADING.md +1 -0
  3. package/commands.md +5 -3
  4. package/contracts/design-critique.md +1 -1
  5. package/contracts/path-write-fence.md +6 -0
  6. package/dist/applying-host-release.d.ts +16 -0
  7. package/dist/applying-host-release.js +98 -0
  8. package/dist/authz.d.ts +1 -1
  9. package/dist/authz.js +1 -1
  10. package/dist/check.d.ts +1 -0
  11. package/dist/check.js +27 -4
  12. package/dist/design-critique-ensure-arc-dest.d.ts +16 -0
  13. package/dist/design-critique-ensure-arc-dest.js +168 -0
  14. package/dist/dispatch.d.ts +1 -1
  15. package/dist/dispatch.js +8 -0
  16. package/dist/hook-dispatch.js +3 -2
  17. package/dist/human-presence-mint.d.ts +6 -1
  18. package/dist/human-presence-mint.js +20 -6
  19. package/dist/session-start.d.ts +8 -2
  20. package/dist/session-start.js +70 -15
  21. package/dist/setup-wiring.d.ts +36 -0
  22. package/dist/setup-wiring.js +169 -14
  23. package/dist/vbrief-preflight.d.ts +4 -0
  24. package/dist/vbrief-preflight.js +34 -0
  25. package/dist/verify-scope-provenance.d.ts +13 -1
  26. package/dist/verify-scope-provenance.js +44 -1
  27. package/dist/verify-source-cli/verify-deposit-closure.js +5 -5
  28. package/dist/windows-bin-ps1.d.ts +2 -2
  29. package/dist/windows-bin-ps1.js +5 -11
  30. package/docs/deft-directive-disable.md +3 -3
  31. package/docs/getting-started.md +2 -0
  32. package/docs/scope-provenance.md +15 -1
  33. package/package.json +2 -3
  34. package/packs/lessons/lessons-pack-0.1.json +15 -0
  35. package/packs/skills/skills-pack-0.1.json +3 -3
  36. package/skills/deft-directive-design-critique/SKILL.md +1 -1
  37. package/skills/deft-directive-release/SKILL.md +31 -1
  38. package/skills/deft-directive-review-cycle/SKILL.md +15 -6
  39. package/skills/deft-directive-swarm/references/host-grok-build.md +3 -2
  40. package/vendor/directive-content/Taskfile.yml +316 -0
  41. package/vendor/directive-content/UPGRADING.md +1 -0
  42. package/vendor/directive-content/commands.md +5 -3
  43. package/vendor/directive-content/contracts/design-critique.md +1 -1
  44. package/vendor/directive-content/contracts/path-write-fence.md +6 -0
  45. package/vendor/directive-content/docs/deft-directive-disable.md +3 -3
  46. package/vendor/directive-content/docs/getting-started.md +2 -0
  47. package/vendor/directive-content/docs/scope-provenance.md +15 -1
  48. package/vendor/directive-content/packs/lessons/lessons-pack-0.1.json +15 -0
  49. package/vendor/directive-content/packs/skills/skills-pack-0.1.json +3 -3
  50. package/vendor/directive-content/skills/deft-directive-design-critique/SKILL.md +1 -1
  51. package/vendor/directive-content/skills/deft-directive-release/SKILL.md +31 -1
  52. package/vendor/directive-content/skills/deft-directive-review-cycle/SKILL.md +15 -6
  53. package/vendor/directive-content/skills/deft-directive-swarm/references/host-grok-build.md +3 -2
  54. package/vendor/directive-core/dist/.tsbuildinfo +1 -1
  55. package/vendor/directive-core/dist/authz/classify.d.ts +12 -0
  56. package/vendor/directive-core/dist/authz/classify.d.ts.map +1 -1
  57. package/vendor/directive-core/dist/authz/classify.js +40 -12
  58. package/vendor/directive-core/dist/authz/classify.js.map +1 -1
  59. package/vendor/directive-core/dist/authz/templates.d.ts +2 -2
  60. package/vendor/directive-core/dist/authz/templates.d.ts.map +1 -1
  61. package/vendor/directive-core/dist/authz/templates.js +1 -0
  62. package/vendor/directive-core/dist/authz/templates.js.map +1 -1
  63. package/vendor/directive-core/dist/authz/types.d.ts +1 -1
  64. package/vendor/directive-core/dist/authz/types.d.ts.map +1 -1
  65. package/vendor/directive-core/dist/authz/types.js +2 -0
  66. package/vendor/directive-core/dist/authz/types.js.map +1 -1
  67. package/vendor/directive-core/dist/authz/verb-classification.d.ts.map +1 -1
  68. package/vendor/directive-core/dist/authz/verb-classification.js +30 -3
  69. package/vendor/directive-core/dist/authz/verb-classification.js.map +1 -1
  70. package/vendor/directive-core/dist/cache/fetch.d.ts.map +1 -1
  71. package/vendor/directive-core/dist/cache/fetch.js +50 -4
  72. package/vendor/directive-core/dist/cache/fetch.js.map +1 -1
  73. package/vendor/directive-core/dist/design-critique/arc-dest.d.ts +22 -5
  74. package/vendor/directive-core/dist/design-critique/arc-dest.d.ts.map +1 -1
  75. package/vendor/directive-core/dist/design-critique/arc-dest.js +61 -0
  76. package/vendor/directive-core/dist/design-critique/arc-dest.js.map +1 -1
  77. package/vendor/directive-core/dist/design-critique/run-posture.d.ts +7 -2
  78. package/vendor/directive-core/dist/design-critique/run-posture.d.ts.map +1 -1
  79. package/vendor/directive-core/dist/design-critique/run-posture.js +6 -1
  80. package/vendor/directive-core/dist/design-critique/run-posture.js.map +1 -1
  81. package/vendor/directive-core/dist/fs/contained-write.d.ts +8 -2
  82. package/vendor/directive-core/dist/fs/contained-write.d.ts.map +1 -1
  83. package/vendor/directive-core/dist/fs/contained-write.js +22 -6
  84. package/vendor/directive-core/dist/fs/contained-write.js.map +1 -1
  85. package/vendor/directive-core/dist/hooks/dispatcher.d.ts +1 -1
  86. package/vendor/directive-core/dist/hooks/dispatcher.d.ts.map +1 -1
  87. package/vendor/directive-core/dist/hooks/dispatcher.js +290 -16
  88. package/vendor/directive-core/dist/hooks/dispatcher.js.map +1 -1
  89. package/vendor/directive-core/dist/hooks/shell-write-targets.d.ts +5 -0
  90. package/vendor/directive-core/dist/hooks/shell-write-targets.d.ts.map +1 -1
  91. package/vendor/directive-core/dist/hooks/shell-write-targets.js +18 -1
  92. package/vendor/directive-core/dist/hooks/shell-write-targets.js.map +1 -1
  93. package/vendor/directive-core/dist/init-deposit/agent-hooks.d.ts +26 -1
  94. package/vendor/directive-core/dist/init-deposit/agent-hooks.d.ts.map +1 -1
  95. package/vendor/directive-core/dist/init-deposit/agent-hooks.js +52 -3
  96. package/vendor/directive-core/dist/init-deposit/agent-hooks.js.map +1 -1
  97. package/vendor/directive-core/dist/init-deposit/host-hook-outer.d.ts +48 -0
  98. package/vendor/directive-core/dist/init-deposit/host-hook-outer.d.ts.map +1 -1
  99. package/vendor/directive-core/dist/init-deposit/host-hook-outer.js +170 -9
  100. package/vendor/directive-core/dist/init-deposit/host-hook-outer.js.map +1 -1
  101. package/vendor/directive-core/dist/init-deposit/scaffold.d.ts +8 -1
  102. package/vendor/directive-core/dist/init-deposit/scaffold.d.ts.map +1 -1
  103. package/vendor/directive-core/dist/init-deposit/scaffold.js +38 -4
  104. package/vendor/directive-core/dist/init-deposit/scaffold.js.map +1 -1
  105. package/vendor/directive-core/dist/install-health/cheap.d.ts +2 -1
  106. package/vendor/directive-core/dist/install-health/cheap.d.ts.map +1 -1
  107. package/vendor/directive-core/dist/install-health/cheap.js +4 -3
  108. package/vendor/directive-core/dist/install-health/cheap.js.map +1 -1
  109. package/vendor/directive-core/dist/install-health/constants.d.ts +18 -2
  110. package/vendor/directive-core/dist/install-health/constants.d.ts.map +1 -1
  111. package/vendor/directive-core/dist/install-health/constants.js +18 -2
  112. package/vendor/directive-core/dist/install-health/constants.js.map +1 -1
  113. package/vendor/directive-core/dist/policy/deft-directive-disable.d.ts +42 -5
  114. package/vendor/directive-core/dist/policy/deft-directive-disable.d.ts.map +1 -1
  115. package/vendor/directive-core/dist/policy/deft-directive-disable.js +71 -41
  116. package/vendor/directive-core/dist/policy/deft-directive-disable.js.map +1 -1
  117. package/vendor/directive-core/dist/pr-closeout-attestable/evaluate.d.ts +6 -1
  118. package/vendor/directive-core/dist/pr-closeout-attestable/evaluate.d.ts.map +1 -1
  119. package/vendor/directive-core/dist/pr-closeout-attestable/evaluate.js +24 -12
  120. package/vendor/directive-core/dist/pr-closeout-attestable/evaluate.js.map +1 -1
  121. package/vendor/directive-core/dist/pr-closeout-attestable/pr-head-assert.d.ts +68 -14
  122. package/vendor/directive-core/dist/pr-closeout-attestable/pr-head-assert.d.ts.map +1 -1
  123. package/vendor/directive-core/dist/pr-closeout-attestable/pr-head-assert.js +278 -47
  124. package/vendor/directive-core/dist/pr-closeout-attestable/pr-head-assert.js.map +1 -1
  125. package/vendor/directive-core/dist/pr-merge-readiness/slizard-gate.d.ts +10 -5
  126. package/vendor/directive-core/dist/pr-merge-readiness/slizard-gate.d.ts.map +1 -1
  127. package/vendor/directive-core/dist/pr-merge-readiness/slizard-gate.js +41 -18
  128. package/vendor/directive-core/dist/pr-merge-readiness/slizard-gate.js.map +1 -1
  129. package/vendor/directive-core/dist/preflight-gh/pre-push.d.ts +3 -2
  130. package/vendor/directive-core/dist/preflight-gh/pre-push.d.ts.map +1 -1
  131. package/vendor/directive-core/dist/preflight-gh/pre-push.js +19 -18
  132. package/vendor/directive-core/dist/preflight-gh/pre-push.js.map +1 -1
  133. package/vendor/directive-core/dist/release/gh.d.ts.map +1 -1
  134. package/vendor/directive-core/dist/release/gh.js +2 -1
  135. package/vendor/directive-core/dist/release/gh.js.map +1 -1
  136. package/vendor/directive-core/dist/release/version.d.ts +4 -2
  137. package/vendor/directive-core/dist/release/version.d.ts.map +1 -1
  138. package/vendor/directive-core/dist/release/version.js +4 -2
  139. package/vendor/directive-core/dist/release/version.js.map +1 -1
  140. package/vendor/directive-core/dist/release-publish/gh-api.d.ts.map +1 -1
  141. package/vendor/directive-core/dist/release-publish/gh-api.js +4 -2
  142. package/vendor/directive-core/dist/release-publish/gh-api.js.map +1 -1
  143. package/vendor/directive-core/dist/release-publish/main.d.ts.map +1 -1
  144. package/vendor/directive-core/dist/release-publish/main.js +15 -4
  145. package/vendor/directive-core/dist/release-publish/main.js.map +1 -1
  146. package/vendor/directive-core/dist/release-publish/pipeline.d.ts +11 -0
  147. package/vendor/directive-core/dist/release-publish/pipeline.d.ts.map +1 -1
  148. package/vendor/directive-core/dist/release-publish/pipeline.js +143 -2
  149. package/vendor/directive-core/dist/release-publish/pipeline.js.map +1 -1
  150. package/vendor/directive-core/dist/release-rollback/gh.d.ts.map +1 -1
  151. package/vendor/directive-core/dist/release-rollback/gh.js +2 -1
  152. package/vendor/directive-core/dist/release-rollback/gh.js.map +1 -1
  153. package/vendor/directive-core/dist/scope/delivery-evidence.d.ts +202 -19
  154. package/vendor/directive-core/dist/scope/delivery-evidence.d.ts.map +1 -1
  155. package/vendor/directive-core/dist/scope/delivery-evidence.js +948 -107
  156. package/vendor/directive-core/dist/scope/delivery-evidence.js.map +1 -1
  157. package/vendor/directive-core/dist/scope/transition.d.ts +4 -1
  158. package/vendor/directive-core/dist/scope/transition.d.ts.map +1 -1
  159. package/vendor/directive-core/dist/scope/transition.js +2 -2
  160. package/vendor/directive-core/dist/scope/transition.js.map +1 -1
  161. package/vendor/directive-core/dist/scope-provenance/base-fence.d.ts +11 -2
  162. package/vendor/directive-core/dist/scope-provenance/base-fence.d.ts.map +1 -1
  163. package/vendor/directive-core/dist/scope-provenance/base-fence.js +16 -1
  164. package/vendor/directive-core/dist/scope-provenance/base-fence.js.map +1 -1
  165. package/vendor/directive-core/dist/scope-provenance/evaluate.d.ts +12 -0
  166. package/vendor/directive-core/dist/scope-provenance/evaluate.d.ts.map +1 -1
  167. package/vendor/directive-core/dist/scope-provenance/evaluate.js +41 -5
  168. package/vendor/directive-core/dist/scope-provenance/evaluate.js.map +1 -1
  169. package/vendor/directive-core/dist/scope-provenance/forge-approval.d.ts +106 -0
  170. package/vendor/directive-core/dist/scope-provenance/forge-approval.d.ts.map +1 -0
  171. package/vendor/directive-core/dist/scope-provenance/forge-approval.js +382 -0
  172. package/vendor/directive-core/dist/scope-provenance/forge-approval.js.map +1 -0
  173. package/vendor/directive-core/dist/session/git.d.ts +21 -2
  174. package/vendor/directive-core/dist/session/git.d.ts.map +1 -1
  175. package/vendor/directive-core/dist/session/git.js +21 -4
  176. package/vendor/directive-core/dist/session/git.js.map +1 -1
  177. package/vendor/directive-core/dist/session/occupancy.d.ts +93 -6
  178. package/vendor/directive-core/dist/session/occupancy.d.ts.map +1 -1
  179. package/vendor/directive-core/dist/session/occupancy.js +215 -52
  180. package/vendor/directive-core/dist/session/occupancy.js.map +1 -1
  181. package/vendor/directive-core/dist/session/orientation-compression.d.ts +18 -2
  182. package/vendor/directive-core/dist/session/orientation-compression.d.ts.map +1 -1
  183. package/vendor/directive-core/dist/session/orientation-compression.js +38 -5
  184. package/vendor/directive-core/dist/session/orientation-compression.js.map +1 -1
  185. package/vendor/directive-core/dist/session/session-start.d.ts +47 -2
  186. package/vendor/directive-core/dist/session/session-start.d.ts.map +1 -1
  187. package/vendor/directive-core/dist/session/session-start.js +154 -3
  188. package/vendor/directive-core/dist/session/session-start.js.map +1 -1
  189. package/vendor/directive-core/dist/swarm/approach1-babysitter.d.ts +18 -4
  190. package/vendor/directive-core/dist/swarm/approach1-babysitter.d.ts.map +1 -1
  191. package/vendor/directive-core/dist/swarm/approach1-babysitter.js +28 -4
  192. package/vendor/directive-core/dist/swarm/approach1-babysitter.js.map +1 -1
  193. package/vendor/directive-core/dist/swarm/dest-place.d.ts +1 -1
  194. package/vendor/directive-core/dist/swarm/dest-place.d.ts.map +1 -1
  195. package/vendor/directive-core/dist/swarm/dest-place.js +36 -41
  196. package/vendor/directive-core/dist/swarm/dest-place.js.map +1 -1
  197. package/vendor/directive-core/dist/swarm/finalize-cohort.d.ts +29 -0
  198. package/vendor/directive-core/dist/swarm/finalize-cohort.d.ts.map +1 -1
  199. package/vendor/directive-core/dist/swarm/finalize-cohort.js +122 -11
  200. package/vendor/directive-core/dist/swarm/finalize-cohort.js.map +1 -1
  201. package/vendor/directive-core/dist/swarm/finalize-owed.d.ts +14 -0
  202. package/vendor/directive-core/dist/swarm/finalize-owed.d.ts.map +1 -1
  203. package/vendor/directive-core/dist/swarm/finalize-owed.js +214 -48
  204. package/vendor/directive-core/dist/swarm/finalize-owed.js.map +1 -1
  205. package/vendor/directive-core/dist/swarm/launch.d.ts.map +1 -1
  206. package/vendor/directive-core/dist/swarm/launch.js +15 -4
  207. package/vendor/directive-core/dist/swarm/launch.js.map +1 -1
  208. package/vendor/directive-core/dist/swarm/worktree-pm-install.d.ts +49 -2
  209. package/vendor/directive-core/dist/swarm/worktree-pm-install.d.ts.map +1 -1
  210. package/vendor/directive-core/dist/swarm/worktree-pm-install.js +207 -12
  211. package/vendor/directive-core/dist/swarm/worktree-pm-install.js.map +1 -1
  212. package/vendor/directive-core/dist/swarm/worktrees-cli.d.ts +6 -0
  213. package/vendor/directive-core/dist/swarm/worktrees-cli.d.ts.map +1 -1
  214. package/vendor/directive-core/dist/swarm/worktrees-cli.js +79 -2
  215. package/vendor/directive-core/dist/swarm/worktrees-cli.js.map +1 -1
  216. package/vendor/directive-core/dist/swarm/worktrees.d.ts +12 -1
  217. package/vendor/directive-core/dist/swarm/worktrees.d.ts.map +1 -1
  218. package/vendor/directive-core/dist/swarm/worktrees.js +34 -26
  219. package/vendor/directive-core/dist/swarm/worktrees.js.map +1 -1
  220. package/vendor/directive-core/dist/triage/evaluate/worktrees.d.ts.map +1 -1
  221. package/vendor/directive-core/dist/triage/evaluate/worktrees.js +219 -60
  222. package/vendor/directive-core/dist/triage/evaluate/worktrees.js.map +1 -1
@@ -1,7 +1,7 @@
1
1
  import { execFileSync } from "node:child_process";
2
- import { existsSync, readdirSync, realpathSync } from "node:fs";
3
- import { basename, isAbsolute, join, relative, resolve, sep } from "node:path";
4
- import { appendAuthzAudit, classifyHookAuthzOps, evaluateAuthzMutation, evidenceSatisfiesImplementationApproval, listActiveHumanGrants, loadAuthzStateResult, markGrantUsed, shouldConsumeSingleUseGrant, utcIso, } from "../authz/index.js";
2
+ import { existsSync, lstatSync, readdirSync, readlinkSync, realpathSync } from "node:fs";
3
+ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
4
+ import { appendAuthzAudit, classifyHookAuthzOps, evaluateAuthzMutation, evidenceSatisfiesImplementationApproval, hasKillSwitchShellWrite, isKillSwitchPlantPath, listActiveHumanGrants, loadAuthzStateResult, markGrantUsed, shouldConsumeSingleUseGrant, utcIso, } from "../authz/index.js";
5
5
  import { shellCommandHasPayloadRootProtectedDestAfterRealpath } from "../authz/protected-dest-realpath.js";
6
6
  import { prepareGithubOnlyDest } from "../design-critique/run-posture.js";
7
7
  import { runningInsideDeftRepo } from "../doctor/paths.js";
@@ -29,6 +29,7 @@ import { inspectSessionRitual, verifySessionRitual, WRITE_GATED_REQUIRED_STEPS,
29
29
  import { countModelFlagsInLauncherArgv, evaluateSpawnRoutingHonor, extractModelFromLauncherArgv, extractRequestedModelFromPayload, extractStructuralWorkerRole, } from "../swarm/routing-honor.js";
30
30
  import { formatLauncherCorrectLifecycleRecovery, UNRESOLVED_HOST_OWNER, uninspectableLifecycleDenyMessage, } from "./classify/host-session-identity.js";
31
31
  import { applyPatchHarvestedInputUnclassified, fieldString, firstString, hintUninspectableLifecycleCommand, hookApplyPatchBodyPaths, hookApplyPatchBodyText, hookMcpArgsText, hookMutationTargetPaths, hookShellCommand, hookToolName, hookWriteTargetPath, hostIdentityFallsBackToExplicitOwner, inspectExactLifecycleCommand, inspectHintedLifecycleSessionId, landProcessOnlyFlagOnToolInput, missingToolNameMessage, normalizeMutationTargetPaths, record, resolveHookHostIdentity, rewriteExactLifecycleCommand, toolInputRecord, } from "./classify/index.js";
32
+ import { GROK_SPAWN_WRITING_SKIP_CLASS_FIELD, PROCESS_ONLY_FLAG_KEYS } from "./classify/payload.js";
32
33
  import { defaultCursorPlanChoiceDeps, isCursorPlanChoiceManagedPath, storeDenyMessage, } from "./cursor-plan-choice/index.js";
33
34
  import { classifyGitDestructive, classifyProductDestForms, payloadWithInjectedWriteTarget, } from "./dest-form.js";
34
35
  import { decidePlanChoiceWithHatch, decideQuestionHatchGate, decideQuestionHatchPauseGate, decideSpendRecommendGate, } from "./dispatcher-plan-choice.js";
@@ -38,7 +39,7 @@ import { isLexicalOutsideProjectRoot, isOutsideProjectRootWrite } from "./outsid
38
39
  import { restampOwnerLivenessOnHookEvent, } from "./owner-liveness.js";
39
40
  import { appliesGrokSpawnDestContract, isAssistPosture, isEphemeralSpawn, isExploreSpawn, isProcessOnlyCriticSpawn, isReadOnlyHookContext, processOnlyCriticRequiresDest, SPAWN_CLASS_RECOVERY, SPAWN_READ_ONLY_RECOVERY, } from "./readonly.js";
40
41
  import { inspectActiveScope, POSITIVE_GOVERNING_ALLOW_REQUIRED, } from "./scope.js";
41
- import { classifyShellWriteTargets, isInRepoShellWritePath } from "./shell-write-targets.js";
42
+ import { classifyShellWriteTargets, isInRepoShellWritePath, isKillSwitchShellWriteBasename, } from "./shell-write-targets.js";
42
43
  import { effectiveHookArgumentView, effectiveHookToolName, expectsLocalMutationDest, isApplyPatchTool, isDirectWriteTool, isKillTool, isMcpProxyWrapper, isMcpTool, isMcpWriteShaped, isShellTool, isSpawnTool, } from "./tools.js";
43
44
  // Pure parse/classify helpers are defined in ./classify/ and re-exported from
44
45
  // ./index.ts (#2950). Dispatcher is orchestration: classify → policy → decision.
@@ -100,7 +101,117 @@ function isLauncherFamilySpawnNotReady(input, toolName) {
100
101
  });
101
102
  return launcher.kind === "launcher" || launcher.kind === "compound";
102
103
  }
104
+ function recordPayload4781(value) {
105
+ return value !== null && typeof value === "object" && !Array.isArray(value)
106
+ ? value
107
+ : null;
108
+ }
109
+ function fieldString4781(input, key) {
110
+ const value = input[key];
111
+ if (typeof value === "string" && value.trim().length > 0)
112
+ return value.trim();
113
+ return null;
114
+ }
115
+ function toolInput4781(payload) {
116
+ return (recordPayload4781(payload.tool_input) ??
117
+ recordPayload4781(payload.toolInput) ??
118
+ recordPayload4781(payload.input) ??
119
+ recordPayload4781(payload.arguments) ??
120
+ payload);
121
+ }
122
+ function fieldTruthy4781(input, key) {
123
+ const value = input[key];
124
+ if (value === true)
125
+ return true;
126
+ if (typeof value === "number")
127
+ return value === 1;
128
+ if (typeof value === "string") {
129
+ const t = value.trim().toLowerCase();
130
+ return t === "1" || t === "true" || t === "yes" || t === "on";
131
+ }
132
+ return false;
133
+ }
134
+ /** Prefer-A #4781: process_only/plan marker present before implement-conflict gate. */
135
+ function hasProcessOnlySkipMarker4781(payload) {
136
+ const input = recordPayload4781(payload);
137
+ if (input === null)
138
+ return false;
139
+ const toolInput = toolInput4781(input);
140
+ const subagentType = fieldString4781(toolInput, "subagent_type") ??
141
+ fieldString4781(toolInput, "subagentType") ??
142
+ fieldString4781(input, "subagent_type") ??
143
+ fieldString4781(input, "subagentType");
144
+ if (subagentType?.toLowerCase() === "plan")
145
+ return true;
146
+ if (GROK_SPAWN_WRITING_SKIP_CLASS_FIELD !== "process_only")
147
+ return false;
148
+ return PROCESS_ONLY_FLAG_KEYS.some((key) => fieldTruthy4781(toolInput, key) || fieldTruthy4781(input, key));
149
+ }
150
+ /** Prefer-A #4781: name suppressing implement field when present. */
151
+ function namedImplementConflictSuppressor4781(payload) {
152
+ const input = recordPayload4781(payload);
153
+ if (input === null)
154
+ return null;
155
+ const toolInput = toolInput4781(input);
156
+ const driveTo = fieldString4781(toolInput, "drive_to") ??
157
+ fieldString4781(toolInput, "driveTo") ??
158
+ fieldString4781(toolInput, "drive-to") ??
159
+ fieldString4781(input, "drive_to") ??
160
+ fieldString4781(input, "driveTo") ??
161
+ fieldString4781(input, "drive-to");
162
+ if (driveTo !== null) {
163
+ const normalized = driveTo.toLowerCase().replace(/[_\s]/g, "-");
164
+ if (normalized === "merge-ready" ||
165
+ normalized === "merge" ||
166
+ normalized.startsWith("merge-") ||
167
+ normalized.includes("implement")) {
168
+ return "drive_to";
169
+ }
170
+ }
171
+ const workerRole = fieldString4781(toolInput, "worker_role") ??
172
+ fieldString4781(toolInput, "workerRole") ??
173
+ fieldString4781(input, "worker_role") ??
174
+ fieldString4781(input, "workerRole");
175
+ if (workerRole !== null) {
176
+ const role = workerRole.toLowerCase().replace(/[_\s]/g, "-");
177
+ if (role === "leaf-implementation" ||
178
+ role === "implementation" ||
179
+ role === "implement" ||
180
+ role.includes("implement")) {
181
+ return "worker_role";
182
+ }
183
+ }
184
+ const dispatchKind = fieldString4781(toolInput, "dispatch_kind") ??
185
+ fieldString4781(toolInput, "dispatchKind") ??
186
+ fieldString4781(input, "dispatch_kind") ??
187
+ fieldString4781(input, "dispatchKind");
188
+ if (dispatchKind !== null) {
189
+ const kind = dispatchKind.toLowerCase().replace(/[_\s]/g, "-");
190
+ if (kind === "swarm-cohort" || kind === "swarm-leaf" || kind.includes("implement")) {
191
+ return "dispatch_kind";
192
+ }
193
+ }
194
+ return null;
195
+ }
196
+ function processOnlyImplementConflictSuppressor4781(payload) {
197
+ if (!hasProcessOnlySkipMarker4781(payload))
198
+ return null;
199
+ return namedImplementConflictSuppressor4781(payload);
200
+ }
201
+ /** Prefer-A #4781: name implement-conflict suppressor when process_only is present but blocked. */
202
+ function overlayProcessOnlyImplementConflictSuppressor(input, decision) {
203
+ if (decision.verdict !== "deny")
204
+ return decision;
205
+ const field = processOnlyImplementConflictSuppressor4781(input.payload);
206
+ if (field === null)
207
+ return decision;
208
+ const note = `process_only was suppressed by ${field} (implement conflict wins; not bare #2885).`;
209
+ if (decision.message.includes(note))
210
+ return decision;
211
+ return { ...decision, message: `${note} ${decision.message}` };
212
+ }
103
213
  function overlayGrokCriticSpawnNotReadyRecovery(input, toolName, decision) {
214
+ decision = overlayProcessOnlyImplementConflictSuppressor(input, decision);
104
215
  if (decision.verdict !== "deny" || decision.code !== "spawn-not-ready")
105
216
  return decision;
106
217
  if (!appliesGrokSpawnDestContract({
@@ -827,6 +938,65 @@ function recordAuthzAudit(projectRoot, decision, state, seams) {
827
938
  // Audit write must not crash the host tool gate.
828
939
  }
829
940
  }
941
+ /**
942
+ * Resolve as far as the filesystem allows: realpath existing prefixes even when
943
+ * the leaf is missing (dangling multi-hop symlink parents).
944
+ */
945
+ function realpathExistingParents(absPath) {
946
+ try {
947
+ return realpathSync(absPath);
948
+ }
949
+ catch {
950
+ const parent = dirname(absPath);
951
+ if (parent === absPath)
952
+ return absPath;
953
+ return join(realpathExistingParents(parent), basename(absPath));
954
+ }
955
+ }
956
+ /**
957
+ * True when a kill-switch plant path realpath-resolves under `.deft/authz/` or
958
+ * `.deft/approved-scope/` (symlink alias). Does not treat the flag basename
959
+ * itself as an inventoried-store hit (#6136 Greptile).
960
+ * Dangling symlinks: resolve link text, then realpath existing parent dirs so a
961
+ * directory alias into the store is not missed (#6158 Greptile P1).
962
+ */
963
+ function killSwitchPlantResolvesToInventoriedAuthzStore(projectRoot, relOrAbsPath) {
964
+ const root = resolve(projectRoot);
965
+ const target = isAbsolute(relOrAbsPath)
966
+ ? resolve(relOrAbsPath)
967
+ : resolve(root, relOrAbsPath.replace(/\\/g, "/"));
968
+ let resolved;
969
+ try {
970
+ resolved = realpathSync(target);
971
+ }
972
+ catch {
973
+ try {
974
+ const st = lstatSync(target);
975
+ if (!st.isSymbolicLink())
976
+ return false;
977
+ const link = readlinkSync(target);
978
+ const candidate = isAbsolute(link) ? resolve(link) : resolve(dirname(target), link);
979
+ resolved = realpathExistingParents(candidate);
980
+ }
981
+ catch {
982
+ return false;
983
+ }
984
+ }
985
+ let rootReal;
986
+ try {
987
+ rootReal = realpathSync(root);
988
+ }
989
+ catch {
990
+ return false;
991
+ }
992
+ const rel = relative(rootReal, resolved).split(sep).join("/").replace(/\\/g, "/").toLowerCase();
993
+ if (rel.length === 0 || rel.startsWith(".."))
994
+ return false;
995
+ return (rel === ".deft/authz" ||
996
+ rel.startsWith(".deft/authz/") ||
997
+ rel === ".deft/approved-scope" ||
998
+ rel.startsWith(".deft/approved-scope/"));
999
+ }
830
1000
  /**
831
1001
  * UAT lease + human-origin grant gate (#2944). Returns deny decision or null when allowed.
832
1002
  * Composes before runtimeAuthority path/scope checks for direct writes and shell/MCP.
@@ -853,6 +1023,7 @@ function authzForMutation(input, toolName, seams, options) {
853
1023
  shellCommand,
854
1024
  isDirectWrite: options.isDirectWrite,
855
1025
  mcpArgsText: options.isDirectWrite ? null : hookMcpArgsText(input.payload),
1026
+ writePath: options.isDirectWrite ? options.relPath : null,
856
1027
  });
857
1028
  // #4188: realpath recovered dest-of-write against payload root. Lexical
858
1029
  // classify stays I/O-free; a non-shell symlink dest is grant-immune unknown.
@@ -881,9 +1052,24 @@ function authzForMutation(input, toolName, seams, options) {
881
1052
  branch = null;
882
1053
  }
883
1054
  const repo = (process.env.DEFT_AUTHZ_REPO ?? process.env.GITHUB_REPOSITORY ?? "").trim() || null;
1055
+ // #6136: kill-switch / permanent opt-out plant is always-on grant-gated (not UAT-only).
1056
+ const killSwitchPlant = (shellCommand !== null && hasKillSwitchShellWrite(shellCommand)) ||
1057
+ (options.isDirectWrite && options.relPath !== null && isKillSwitchPlantPath(options.relPath));
1058
+ // Symlink plant of a kill-switch basename into `.deft/authz/` / approved-scope
1059
+ // must not ride a settings grant (settings op skips isProtectedStoreEditDest).
1060
+ // Plain flag basenames are themselves "protected" in relIsProtectedDirectiveDest;
1061
+ // only deny when realpath lands under the inventoried store dirs (#6136 Greptile).
1062
+ if (killSwitchPlant &&
1063
+ options.isDirectWrite &&
1064
+ options.relPath !== null &&
1065
+ killSwitchPlantResolvesToInventoriedAuthzStore(projectRoot, options.relPath)) {
1066
+ return deny(input, "authz-uat-deny", toolName, "Directive denied kill-switch plant: path resolves into the inventoried authz " +
1067
+ "store (`.deft/authz/` or `.deft/approved-scope/`). A settings grant does not " +
1068
+ "authorize rewriting approval state through a flag symlink (#6136).", options.scopePath);
1069
+ }
884
1070
  // Evaluate each op; first deny wins (compound shell must not short-circuit).
885
1071
  for (const op of ops) {
886
- const decision = evaluateAuthzMutation({
1072
+ let decision = evaluateAuthzMutation({
887
1073
  state,
888
1074
  grants,
889
1075
  op,
@@ -892,6 +1078,48 @@ function authzForMutation(input, toolName, seams, options) {
892
1078
  repo,
893
1079
  worktree: projectRoot,
894
1080
  });
1081
+ // Outside UAT, settings (and kill-switch Write classified as settings) would
1082
+ // authz-inactive allow. Re-evaluate under a synthetic human-origin UAT so the
1083
+ // existing grant gate applies without widening evaluate.ts (#6136).
1084
+ if (killSwitchPlant &&
1085
+ decision.allowed &&
1086
+ decision.code === "authz-inactive" &&
1087
+ (op === "settings" || op === "edit")) {
1088
+ decision = evaluateAuthzMutation({
1089
+ state: {
1090
+ ...state,
1091
+ uat: {
1092
+ active: true,
1093
+ campaignId: "always-on-kill-switch-plant",
1094
+ startedAt: "1970-01-01T00:00:00.000Z",
1095
+ startedBy: {
1096
+ kind: "operator-cli",
1097
+ actor: "directive-always-on-kill-switch",
1098
+ mintedAt: "1970-01-01T00:00:00.000Z",
1099
+ mintedVia: "cli",
1100
+ eventRef: null,
1101
+ },
1102
+ suspendedAt: null,
1103
+ note: "synthetic lease for always-on kill-switch plant grant gate (#6136)",
1104
+ },
1105
+ },
1106
+ grants,
1107
+ op: "settings",
1108
+ path: options.relPath,
1109
+ branch,
1110
+ repo,
1111
+ worktree: projectRoot,
1112
+ });
1113
+ if (!decision.allowed) {
1114
+ decision = {
1115
+ ...decision,
1116
+ reason: "Directive denied kill-switch / permanent opt-out plant without a human-origin " +
1117
+ "settings grant (#6136). Agents must not self-serve `.deft-directive-disable` or " +
1118
+ "`.no-deft-directive`. Human action required: plant outside an agent session, or " +
1119
+ "run `deft authz:grant` covering settings for this cohort.",
1120
+ };
1121
+ }
1122
+ }
895
1123
  recordAuthzAudit(projectRoot, decision, state, seams);
896
1124
  if (!decision.allowed) {
897
1125
  return deny(input, authzCodeToHook(decision.code), toolName, decision.reason, options.scopePath);
@@ -1083,6 +1311,8 @@ function inspectMutationGates(input, toolName, seams, options) {
1083
1311
  scopePath: null,
1084
1312
  runGit: dispatchGit,
1085
1313
  projectRoot,
1314
+ deferGrantConsume: options.deferGrantConsume === true,
1315
+ pendingConsumeOut: options.pendingConsumeOut,
1086
1316
  });
1087
1317
  if (authzDeny !== null)
1088
1318
  return authzDeny;
@@ -1194,6 +1424,8 @@ function inspectMutationGates(input, toolName, seams, options) {
1194
1424
  scopePath: null,
1195
1425
  runGit: dispatchGit,
1196
1426
  projectRoot,
1427
+ deferGrantConsume: options.deferGrantConsume === true,
1428
+ pendingConsumeOut: options.pendingConsumeOut,
1197
1429
  });
1198
1430
  if (authzDeny !== null)
1199
1431
  return authzDeny;
@@ -1453,10 +1685,11 @@ function inspectMutationGates(input, toolName, seams, options) {
1453
1685
  "`worker_role`/`subagent_type` ∈ {ephemeral, docs, assist} (hosts that support them), " +
1454
1686
  "or set session assist (`DEFT_SESSION_POSTURE=assist` or `DEFT_HOOK_ASSIST=1`), " +
1455
1687
  "or run local-dev Shell (`docker compose` / `pnpm dev`) in the parent without a " +
1456
- "lifecycle story. (4) Process-only critic — spawn with structural `subagent_type` " +
1457
- "plan or `process_only` (Grok PreToolUse stdin). Dest-path is not that class. " +
1458
- "Free-text markers such as `[worker_role: ephemeral]` or naming critic in the prompt " +
1459
- "are NOT sufficient. Do not invent a fake scope only to satisfy this gate.";
1688
+ "lifecycle story. (4) Process-only critic / review-monitor / validation seat — spawn with " +
1689
+ "structural `subagent_type` plan or `process_only` (Grok PreToolUse stdin) plus dest cwd " +
1690
+ "for watch/report seats. Dest-path is not that class. Free-text markers such as " +
1691
+ "`[worker_role: ephemeral]` or naming critic in the prompt are NOT sufficient. Do not " +
1692
+ "invent a fake scope only to satisfy this gate.";
1460
1693
  }
1461
1694
  else if (options.proposedLifecycleExempt &&
1462
1695
  relTarget !== null &&
@@ -1539,7 +1772,7 @@ function inspectMutationGates(input, toolName, seams, options) {
1539
1772
  };
1540
1773
  if (!isSpawnTool(toolName)) {
1541
1774
  // Wave 1 authz (UAT lease + human-origin grant) before runtimeAuthority (#2944 / #2948 L1–L2).
1542
- const pendingGrantConsume = [];
1775
+ const pendingGrantConsume = options.pendingConsumeOut ?? [];
1543
1776
  const authzDeny = authzForMutationTargets(input, toolName, seams, {
1544
1777
  isDirectWrite: true,
1545
1778
  scopePath: scope.path,
@@ -1556,7 +1789,12 @@ function inspectMutationGates(input, toolName, seams, options) {
1556
1789
  const runtimeDeny = runtimeAuthorityForDirectWrite(input, toolName, seams, scope.path, effectiveRoot);
1557
1790
  if (runtimeDeny !== null)
1558
1791
  return runtimeDeny;
1559
- consumePendingSingleUseGrants(projectRoot, pendingGrantConsume);
1792
+ // Shell write-reissue may defer spend so decideShellOrMcpRuntimeAuthority can
1793
+ // reuse the same single-use grant (#6136 Greptile P1). When pendingConsumeOut
1794
+ // is the same bag, authz already recorded refs — do not push twice.
1795
+ if (options.deferGrantConsume !== true) {
1796
+ consumePendingSingleUseGrants(projectRoot, pendingGrantConsume);
1797
+ }
1560
1798
  // Intentional product-write allow: Prefer-A durable marker (#5176 / #4544).
1561
1799
  const occupancyDeny = recheckOccupancyBeforeWriteAllow(true);
1562
1800
  if (occupancyDeny !== null)
@@ -1812,29 +2050,37 @@ function decideGitDestructive(input, toolName) {
1812
2050
  /**
1813
2051
  * Authorize recognized in-repo Shell file-write dests through inspectMutationGates (#3983 / #3987).
1814
2052
  * Deny is returned; allow falls through so dest-forms and push/merge still run.
2053
+ * Kill-switch basenames are checked before the in-repo skip so out-of-tree plants
2054
+ * cannot fail-open (#6136 Prefer-A Bound limb 2).
1815
2055
  */
1816
- function decideShellWriteReissue(input, toolName, seams, observation) {
2056
+ function decideShellWriteReissue(input, toolName, seams, observation, pendingConsumeOut) {
1817
2057
  const command = hookShellCommand(input.payload);
1818
2058
  if (command === null)
1819
2059
  return null;
1820
2060
  const projectRoot = resolve(input.projectRoot);
1821
2061
  for (const dest of classifyShellWriteTargets(command)) {
2062
+ const killSwitchDest = isKillSwitchShellWriteBasename(dest.path);
1822
2063
  if (dest.unprovable === true) {
1823
- if (!isInRepoShellWritePath(projectRoot, dest.path))
2064
+ if (!killSwitchDest && !isInRepoShellWritePath(projectRoot, dest.path))
1824
2065
  continue;
1825
2066
  return deny(input, "scope-not-ready", toolName, "Directive denied " +
1826
2067
  toolName +
1827
2068
  ": Shell write dest is not reconstructable (compound command). Use one simple command or Edit/Write.");
1828
2069
  }
1829
- if (!isInRepoShellWritePath(projectRoot, dest.path))
2070
+ // #6136: protected basename before isInRepoShellWritePath skip.
2071
+ if (!killSwitchDest && !isInRepoShellWritePath(projectRoot, dest.path))
1830
2072
  continue;
1831
2073
  const destInput = {
1832
2074
  ...input,
1833
2075
  payload: payloadWithInjectedWriteTarget(input.payload, dest.path),
1834
2076
  };
2077
+ // Defer single-use spend into pendingConsumeOut; caller spends after the whole
2078
+ // shell call allows so ordinary edit grants are not reusable (#6136 Greptile).
1835
2079
  const destDecision = inspectMutationGates(destInput, toolName, seams, {
1836
2080
  proposedLifecycleExempt: true,
1837
2081
  observation,
2082
+ deferGrantConsume: true,
2083
+ pendingConsumeOut,
1838
2084
  });
1839
2085
  if (destDecision.verdict === "deny")
1840
2086
  return destDecision;
@@ -2287,12 +2533,15 @@ function tryPublishApplyingHostFromSessionStart(input, projectRoot) {
2287
2533
  const transport = identity.provider === "grok" && environ.GROK_HOOK_EVENT?.trim()
2288
2534
  ? "grok-hook-event"
2289
2535
  : "native";
2536
+ // SessionStart soft claim may take over a no-lease different-provider record
2537
+ // (#6143 P1/P4); RO CLI path must omit allowForeignTakeover.
2290
2538
  // Native Cursor SessionStart must stay cursor even when GROK_SESSION_ID lingers.
2291
2539
  if (input.host === "cursor" && transport === "native") {
2292
2540
  publishApplyingHost(projectRoot, {
2293
2541
  provider: "cursor",
2294
2542
  rawSessionId: identity.rawSessionId,
2295
2543
  transport: "native",
2544
+ allowForeignTakeover: true,
2296
2545
  });
2297
2546
  return;
2298
2547
  }
@@ -2300,6 +2549,7 @@ function tryPublishApplyingHostFromSessionStart(input, projectRoot) {
2300
2549
  provider: identity.provider,
2301
2550
  rawSessionId: identity.rawSessionId,
2302
2551
  transport,
2552
+ allowForeignTakeover: true,
2303
2553
  });
2304
2554
  }
2305
2555
  catch {
@@ -2386,6 +2636,8 @@ function attachLifecycleIdentityRewrite(input, toolName, decision, seams) {
2386
2636
  : "native";
2387
2637
  // Prefer deposit identity when it matches the named canonical owner.
2388
2638
  const identity = resolveHookHostIdentity(input.host, input.payload, environ);
2639
+ // #6143 P4: RO SessionStart must not displace a different-provider fresh
2640
+ // record (omit allowForeignTakeover; publish defers foreign-fresh-claim).
2389
2641
  if (identity.status === "ok" &&
2390
2642
  identity.sessionId === lifecycle.sessionId &&
2391
2643
  // Leftover GROK_SESSION_ID alone must not publish Cursor as Claude/grok.
@@ -2447,7 +2699,17 @@ function attachLifecycleIdentityRewrite(input, toolName, decision, seams) {
2447
2699
  return denyIdentity("occupancy-identity-conflict", applyingAdmission.message);
2448
2700
  }
2449
2701
  let liveOwnerBypass = false;
2450
- if (applyingAdmission.kind === "foreign-owner") {
2702
+ if (applyingAdmission.kind === "live-owner-cleanup") {
2703
+ // Deposit equals live lease holder (#6101 Prefer-A): effectiveOwner is the
2704
+ // live deposit identity; bare stays on the rewrite path (not soft-pass).
2705
+ liveOwnerBypass = true;
2706
+ }
2707
+ else if (applyingAdmission.kind === "advisory-takeover") {
2708
+ // #6143 P1: no-lease fresh applying-host is advisory; caller keeps identity
2709
+ // and may republish after lifecycle succeeds.
2710
+ liveOwnerBypass = true;
2711
+ }
2712
+ else if (applyingAdmission.kind === "foreign-owner") {
2451
2713
  const live = liveOccupant(resolve(input.projectRoot));
2452
2714
  if (live !== null && live.sessionId === identity.sessionId) {
2453
2715
  // Applying-host was replaced by another SessionStart; keep live lease owner
@@ -2568,6 +2830,14 @@ function prepareProcessOnlyDestPath(destPath, projectRoot, seams, payload) {
2568
2830
  destPath,
2569
2831
  againstImplementationSha: against,
2570
2832
  });
2833
+ // Strict false only: legacy success mocks may omit `ok` and still carry `record` (#6100).
2834
+ if (prepared.ok === false) {
2835
+ return {
2836
+ ok: false,
2837
+ message: `Directive denied process-only critic spawn: dest prepare failed: ${prepared.code}: ${prepared.message}. ` +
2838
+ "Parent must fetch origin and create or verify the dest at origin/<default> before spawn.",
2839
+ };
2840
+ }
2571
2841
  return { ok: true, record: prepared.record };
2572
2842
  }
2573
2843
  catch (cause) {
@@ -3008,11 +3278,15 @@ function routeHookDecision(input, seams, observation) {
3008
3278
  if (prospective !== null) {
3009
3279
  return remapProxyShellUpdatedInput(input.payload, toolName, shellProxyUnwrap, attachLifecycleIdentityRewrite(shellInput, shellToolName, prospective, seams));
3010
3280
  }
3011
- const writeReissue = decideShellWriteReissue(shellInput, shellToolName, seams, observation);
3281
+ const pendingShellGrantConsume = [];
3282
+ const writeReissue = decideShellWriteReissue(shellInput, shellToolName, seams, observation, pendingShellGrantConsume);
3012
3283
  if (writeReissue !== null) {
3013
3284
  return remapProxyShellUpdatedInput(input.payload, toolName, shellProxyUnwrap, attachLifecycleIdentityRewrite(shellInput, shellToolName, writeReissue, seams));
3014
3285
  }
3015
3286
  const decision = decideShellDestFormsThenRuntimeAuthority(shellInput, shellToolName, seams, observation);
3287
+ if (decision.verdict === "allow") {
3288
+ consumePendingSingleUseGrants(resolve(shellInput.projectRoot), pendingShellGrantConsume);
3289
+ }
3016
3290
  return remapProxyShellUpdatedInput(input.payload, toolName, shellProxyUnwrap, attachLifecycleIdentityRewrite(shellInput, shellToolName, decision, seams));
3017
3291
  }
3018
3292
  // Host kill deny-class / attestation gate (#5281 Prefer-A Bound).