@gajae-code/coding-agent 0.15.6 → 0.16.1

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 (270) hide show
  1. package/CHANGELOG.md +99 -0
  2. package/dist/types/async/job-manager.d.ts +32 -1
  3. package/dist/types/browser-backend.d.ts +12 -0
  4. package/dist/types/cli/args.d.ts +2 -0
  5. package/dist/types/cli/root-flags.d.ts +14 -0
  6. package/dist/types/cli/update-cli.d.ts +14 -0
  7. package/dist/types/cli.d.ts +7 -0
  8. package/dist/types/commands/launch.d.ts +10 -0
  9. package/dist/types/commands/sdk.d.ts +2 -0
  10. package/dist/types/config/autorouting-tier-map.d.ts +24 -0
  11. package/dist/types/config/billing-path.d.ts +25 -0
  12. package/dist/types/config/config-schema-version.d.ts +13 -1
  13. package/dist/types/config/file-lock.d.ts +5 -0
  14. package/dist/types/config/model-registry.d.ts +22 -0
  15. package/dist/types/config/settings-schema.d.ts +27 -8
  16. package/dist/types/config/settings.d.ts +2 -0
  17. package/dist/types/coordinator-mcp/projection-scan.d.ts +8 -0
  18. package/dist/types/crash/record-loader.d.ts +15 -0
  19. package/dist/types/extensibility/extensions/types.d.ts +8 -3
  20. package/dist/types/gjc-runtime/launch-worktree-reservation.d.ts +21 -0
  21. package/dist/types/gjc-runtime/launch-worktree.d.ts +25 -1
  22. package/dist/types/gjc-runtime/managed-owner-supervisor.d.ts +2 -0
  23. package/dist/types/gjc-runtime/session-state-lock.d.ts +22 -0
  24. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +66 -1
  25. package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +1 -0
  26. package/dist/types/gjc-runtime/tmux-sessions.d.ts +27 -0
  27. package/dist/types/main.d.ts +1 -0
  28. package/dist/types/master-mode/context.d.ts +21 -0
  29. package/dist/types/master-mode/first-request.d.ts +34 -0
  30. package/dist/types/master-mode/snapshot.d.ts +32 -0
  31. package/dist/types/modes/acp/acp-agent.d.ts +21 -21
  32. package/dist/types/modes/components/frictionless-onboarding-selector.d.ts +10 -0
  33. package/dist/types/modes/components/model-selector.d.ts +4 -0
  34. package/dist/types/modes/components/oauth-selector.d.ts +1 -0
  35. package/dist/types/modes/components/session-selector.d.ts +1 -1
  36. package/dist/types/modes/components/sessions-dashboard.d.ts +2 -1
  37. package/dist/types/modes/components/status-line/model-name.d.ts +18 -0
  38. package/dist/types/modes/components/status-line/priority-row.d.ts +34 -0
  39. package/dist/types/modes/components/status-line/segments.d.ts +10 -0
  40. package/dist/types/modes/interactive-mode.d.ts +16 -2
  41. package/dist/types/modes/print-mode.d.ts +17 -0
  42. package/dist/types/modes/theme/theme.d.ts +2 -1
  43. package/dist/types/modes/types.d.ts +2 -0
  44. package/dist/types/modes/ui-language.d.ts +7 -1
  45. package/dist/types/sdk/broker/broker.d.ts +79 -2
  46. package/dist/types/sdk/broker/endpoint-authority.d.ts +24 -0
  47. package/dist/types/sdk/broker/ensure.d.ts +3 -0
  48. package/dist/types/sdk/broker/index.d.ts +3 -0
  49. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +6 -0
  50. package/dist/types/sdk/broker/lifecycle.d.ts +40 -0
  51. package/dist/types/sdk/broker/master-capability.d.ts +10 -0
  52. package/dist/types/sdk/broker/session-index.d.ts +40 -11
  53. package/dist/types/sdk/broker/session-scope.d.ts +72 -0
  54. package/dist/types/sdk/broker/spawn-authority.d.ts +201 -0
  55. package/dist/types/sdk/broker/spawn-substrate.d.ts +30 -0
  56. package/dist/types/sdk/broker/startup-budget.d.ts +52 -0
  57. package/dist/types/sdk/broker/state-version.d.ts +21 -1
  58. package/dist/types/sdk/broker/worktree-occupancy.d.ts +28 -0
  59. package/dist/types/sdk/bus/chat-daemon-control.d.ts +3 -0
  60. package/dist/types/sdk/bus/discord-daemon.d.ts +1 -1
  61. package/dist/types/sdk/bus/index.d.ts +9 -1
  62. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +1 -1
  63. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +1 -1
  64. package/dist/types/sdk/bus/slack-conversation.d.ts +1 -1
  65. package/dist/types/sdk/bus/slack-daemon.d.ts +1 -1
  66. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
  67. package/dist/types/sdk/cli/index.d.ts +1 -0
  68. package/dist/types/sdk/cli/master-cli.d.ts +63 -0
  69. package/dist/types/sdk/cli/rows.d.ts +12 -5
  70. package/dist/types/sdk/cli/session-cli.d.ts +20 -3
  71. package/dist/types/sdk/client/client.d.ts +3 -2
  72. package/dist/types/sdk/host/control/dispatch.d.ts +10 -0
  73. package/dist/types/sdk/host/control/index.d.ts +1 -1
  74. package/dist/types/sdk/host/control/operations.d.ts +2 -0
  75. package/dist/types/sdk/host/control/runtime-gate.d.ts +21 -7
  76. package/dist/types/sdk/host/events.d.ts +1 -0
  77. package/dist/types/sdk/host/host.d.ts +10 -0
  78. package/dist/types/sdk/host/query/cursor.d.ts +4 -2
  79. package/dist/types/sdk/host/query/handlers.d.ts +1 -0
  80. package/dist/types/sdk/host/query/revision-store.d.ts +1 -0
  81. package/dist/types/sdk/host/session-runtime.d.ts +70 -17
  82. package/dist/types/sdk/lifecycle/broker-client.d.ts +6 -0
  83. package/dist/types/sdk/lifecycle/service.d.ts +15 -3
  84. package/dist/types/sdk/lifecycle-session.d.ts +3 -1
  85. package/dist/types/sdk/prompt-deadline-manager.d.ts +2 -5
  86. package/dist/types/sdk/receipt-state.d.ts +2 -0
  87. package/dist/types/sdk/router/session-router.d.ts +6 -0
  88. package/dist/types/sdk/session.d.ts +16 -0
  89. package/dist/types/sdk/startup-capability.d.ts +2 -1
  90. package/dist/types/sdk/turn-result.d.ts +6 -0
  91. package/dist/types/session/agent-session.d.ts +52 -7
  92. package/dist/types/session/credential-store-errors.d.ts +1 -0
  93. package/dist/types/session/fold-coordinator.d.ts +29 -2
  94. package/dist/types/session/session-manager.d.ts +79 -2
  95. package/dist/types/session/yield-queue.d.ts +5 -4
  96. package/dist/types/setup/frictionless-onboarding.d.ts +1 -0
  97. package/dist/types/tools/ask.d.ts +1 -0
  98. package/dist/types/tools/bash.d.ts +16 -0
  99. package/dist/types/tools/browser/launch.d.ts +10 -0
  100. package/dist/types/tools/browser/registry.d.ts +8 -0
  101. package/dist/types/tools/gh.d.ts +8 -0
  102. package/dist/types/tools/index.d.ts +10 -10
  103. package/dist/types/tools/job.d.ts +3 -1
  104. package/dist/types/utils/external-editor.d.ts +7 -0
  105. package/examples/extensions/README.md +1 -1
  106. package/examples/extensions/pirate.ts +7 -4
  107. package/package.json +7 -7
  108. package/scripts/generate-sdk-operation-inventory.ts +13 -1
  109. package/scripts/verify-gjc-sdk-canonicalization.ts +35 -1
  110. package/src/async/job-manager.ts +107 -9
  111. package/src/browser-backend.ts +29 -0
  112. package/src/cli/accounts-cli.ts +9 -5
  113. package/src/cli/args.ts +17 -0
  114. package/src/cli/fast-help.ts +1 -0
  115. package/src/cli/plugin-cli.ts +29 -0
  116. package/src/cli/root-flags.ts +5 -0
  117. package/src/cli/update-cli.ts +140 -23
  118. package/src/commands/launch.ts +86 -18
  119. package/src/commands/sdk.ts +135 -28
  120. package/src/config/autorouting-tier-map.ts +12 -0
  121. package/src/config/billing-path.ts +42 -0
  122. package/src/config/config-schema-version.ts +18 -1
  123. package/src/config/file-lock.ts +158 -83
  124. package/src/config/model-preset-registry.ts +178 -23
  125. package/src/config/model-profiles.ts +5 -5
  126. package/src/config/model-registry.ts +291 -42
  127. package/src/config/model-resolver.ts +5 -0
  128. package/src/config/settings-schema.ts +27 -8
  129. package/src/config/settings.ts +51 -15
  130. package/src/coordinator-mcp/projection-scan.ts +27 -6
  131. package/src/coordinator-mcp/question-state.ts +9 -11
  132. package/src/coordinator-mcp/server.ts +115 -21
  133. package/src/crash/index-store.ts +2 -0
  134. package/src/crash/record-loader.ts +10 -0
  135. package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
  136. package/src/extensibility/extensions/runner.ts +27 -0
  137. package/src/extensibility/extensions/types.ts +8 -3
  138. package/src/extensibility/gjc-plugins/installer.ts +51 -11
  139. package/src/extensibility/runtime-skill-discovery.ts +110 -3
  140. package/src/extensibility/skills.ts +22 -12
  141. package/src/gjc-runtime/launch-worktree-reservation.ts +242 -0
  142. package/src/gjc-runtime/launch-worktree.ts +285 -4
  143. package/src/gjc-runtime/managed-owner-supervisor.ts +63 -51
  144. package/src/gjc-runtime/session-state-lock.ts +213 -14
  145. package/src/gjc-runtime/session-state-sidecar.ts +938 -39
  146. package/src/gjc-runtime/tmux-owner-isolation-cli.ts +4 -7
  147. package/src/gjc-runtime/tmux-owner-isolation.ts +18 -3
  148. package/src/gjc-runtime/tmux-sessions.ts +252 -13
  149. package/src/hooks/skill-state.ts +6 -0
  150. package/src/internal-urls/docs-index.generated.ts +15 -15
  151. package/src/internal-urls/issue-pr-protocol.ts +4 -2
  152. package/src/main.ts +61 -3
  153. package/src/master-mode/context.ts +50 -0
  154. package/src/master-mode/first-request.ts +65 -0
  155. package/src/master-mode/snapshot.ts +205 -0
  156. package/src/modes/acp/acp-agent.ts +610 -161
  157. package/src/modes/components/footer.ts +4 -2
  158. package/src/modes/components/frictionless-onboarding-selector.ts +48 -2
  159. package/src/modes/components/model-selector.ts +76 -8
  160. package/src/modes/components/oauth-selector.ts +6 -1
  161. package/src/modes/components/session-selector.ts +23 -15
  162. package/src/modes/components/sessions-dashboard.ts +8 -5
  163. package/src/modes/components/settings-selector.ts +1 -0
  164. package/src/modes/components/status-line/model-name.ts +53 -0
  165. package/src/modes/components/status-line/priority-row.ts +107 -0
  166. package/src/modes/components/status-line/segments.ts +23 -9
  167. package/src/modes/components/tool-status-header.ts +151 -15
  168. package/src/modes/controllers/command-controller.ts +1 -1
  169. package/src/modes/controllers/event-controller.ts +30 -4
  170. package/src/modes/controllers/extension-ui-controller.ts +13 -13
  171. package/src/modes/controllers/input-controller.ts +30 -2
  172. package/src/modes/controllers/selector-controller.ts +200 -98
  173. package/src/modes/interactive-mode.ts +36 -12
  174. package/src/modes/print-mode.ts +64 -0
  175. package/src/modes/prompt-action-autocomplete.ts +30 -4
  176. package/src/modes/runtime-init.ts +12 -9
  177. package/src/modes/theme/theme.ts +5 -0
  178. package/src/modes/types.ts +2 -0
  179. package/src/modes/ui-language.ts +49 -2
  180. package/src/modes/utils/ui-helpers.ts +22 -3
  181. package/src/prompts/agent-fragments/browser-aside.md +22 -0
  182. package/src/prompts/system/master-mode.md +28 -0
  183. package/src/prompts/tools/ask.md +1 -1
  184. package/src/prompts/tools/bash.md +1 -0
  185. package/src/prompts/tools/job.md +1 -1
  186. package/src/sdk/acp/adapter.ts +5 -0
  187. package/src/sdk/broker/broker.ts +1646 -27
  188. package/src/sdk/broker/endpoint-authority.ts +86 -0
  189. package/src/sdk/broker/ensure.ts +81 -3
  190. package/src/sdk/broker/index.ts +3 -0
  191. package/src/sdk/broker/lifecycle-ledger.ts +6 -0
  192. package/src/sdk/broker/lifecycle.ts +440 -75
  193. package/src/sdk/broker/master-capability.ts +232 -0
  194. package/src/sdk/broker/session-index.ts +121 -17
  195. package/src/sdk/broker/session-scope.ts +272 -0
  196. package/src/sdk/broker/spawn-authority.ts +1031 -0
  197. package/src/sdk/broker/spawn-substrate.ts +591 -0
  198. package/src/sdk/broker/startup-budget.ts +144 -2
  199. package/src/sdk/broker/state-version.ts +43 -14
  200. package/src/sdk/broker/transport.ts +1 -0
  201. package/src/sdk/broker/worktree-occupancy.ts +90 -0
  202. package/src/sdk/bus/chat-daemon-control.ts +5 -2
  203. package/src/sdk/bus/chat-daemon-runtime.ts +136 -18
  204. package/src/sdk/bus/discord-daemon.ts +50 -10
  205. package/src/sdk/bus/index.ts +84 -7
  206. package/src/sdk/bus/kind-aware-reconciliation.ts +296 -48
  207. package/src/sdk/bus/lifecycle-commands.ts +4 -0
  208. package/src/sdk/bus/notification-service.ts +22 -5
  209. package/src/sdk/bus/prompt-reconciliation.ts +7 -2
  210. package/src/sdk/bus/reconciliation-store.ts +55 -31
  211. package/src/sdk/bus/slack-conversation.ts +1 -1
  212. package/src/sdk/bus/slack-daemon.ts +72 -38
  213. package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
  214. package/src/sdk/cli/index.ts +1 -0
  215. package/src/sdk/cli/master-cli.ts +259 -0
  216. package/src/sdk/cli/rows.ts +41 -15
  217. package/src/sdk/cli/session-cli.ts +297 -26
  218. package/src/sdk/client/client.ts +14 -8
  219. package/src/sdk/host/control/dispatch.ts +101 -40
  220. package/src/sdk/host/control/index.ts +2 -0
  221. package/src/sdk/host/control/operations.ts +2 -0
  222. package/src/sdk/host/control/runtime-gate.ts +203 -11
  223. package/src/sdk/host/events.ts +1 -0
  224. package/src/sdk/host/host.ts +29 -2
  225. package/src/sdk/host/query/cursor.ts +52 -7
  226. package/src/sdk/host/query/handlers.ts +33 -12
  227. package/src/sdk/host/query/revision-store.ts +12 -0
  228. package/src/sdk/host/session-runtime.test.ts +673 -14
  229. package/src/sdk/host/session-runtime.ts +674 -103
  230. package/src/sdk/host/surface-policy.ts +3 -3
  231. package/src/sdk/lifecycle/broker-client.ts +28 -0
  232. package/src/sdk/lifecycle/service.ts +279 -20
  233. package/src/sdk/lifecycle-session.ts +17 -4
  234. package/src/sdk/prompt-deadline-manager.ts +2 -1
  235. package/src/sdk/protocol/operation-inventory.generated.json +105 -3
  236. package/src/sdk/protocol/operation-registry.ts +14 -4
  237. package/src/sdk/receipt-state.ts +10 -0
  238. package/src/sdk/router/session-router.ts +219 -118
  239. package/src/sdk/session.ts +416 -195
  240. package/src/sdk/startup-capability.ts +1 -0
  241. package/src/sdk/turn-result.ts +22 -0
  242. package/src/session/agent-session.ts +1628 -318
  243. package/src/session/blob-store.ts +15 -5
  244. package/src/session/credential-store-errors.ts +2 -0
  245. package/src/session/fold-coordinator.ts +40 -3
  246. package/src/session/internal/managed-session-storage.ts +153 -78
  247. package/src/session/session-manager.ts +850 -97
  248. package/src/session/yield-queue.ts +24 -10
  249. package/src/setup/frictionless-onboarding.ts +2 -0
  250. package/src/slash-commands/builtin-registry.ts +41 -0
  251. package/src/task/executor.ts +9 -4
  252. package/src/telemetry/events.ts +1138 -12
  253. package/src/tools/ask-contract.test.ts +64 -0
  254. package/src/tools/ask-contract.ts +36 -1
  255. package/src/tools/ask.ts +10 -8
  256. package/src/tools/bash-interactive.ts +11 -2
  257. package/src/tools/bash.ts +412 -75
  258. package/src/tools/browser/launch.ts +37 -0
  259. package/src/tools/browser/registry.ts +99 -9
  260. package/src/tools/cron.ts +6 -4
  261. package/src/tools/descriptors.test.ts +15 -0
  262. package/src/tools/descriptors.ts +5 -1
  263. package/src/tools/gh.ts +104 -48
  264. package/src/tools/github-cache.ts +2 -2
  265. package/src/tools/index.ts +10 -6
  266. package/src/tools/job.ts +4 -1
  267. package/src/tools/monitor.ts +12 -9
  268. package/src/tools/resolve.ts +30 -10
  269. package/src/tools/tool-catalog.generated.ts +2 -2
  270. package/src/utils/external-editor.ts +72 -1
@@ -6,8 +6,13 @@ import { exactUnlink } from "@gajae-code/natives";
6
6
  import { isEnoent, logger, postmortem } from "@gajae-code/utils";
7
7
 
8
8
  const BLOB_PREFIX = "blob:sha256:";
9
+ const CANONICAL_BLOB_NAME = /^[0-9a-f]{64}$/;
9
10
  const TAKE_BLOB_BUFFER_OWNERSHIP = Symbol("takeBlobBufferOwnership");
10
11
 
12
+ function isCanonicalBlobHash(hash: string): boolean {
13
+ return hash.length === 64 && CANONICAL_BLOB_NAME.test(hash);
14
+ }
15
+
11
16
  /**
12
17
  * Owner-only permissions for on-disk blob directories and files.
13
18
  *
@@ -1126,6 +1131,7 @@ export class BlobStore {
1126
1131
 
1127
1132
  /** Read blob by hash, returns Buffer or null if not found. */
1128
1133
  async get(hash: string): Promise<Buffer | null> {
1134
+ if (!isCanonicalBlobHash(hash)) return null;
1129
1135
  const blobPath = path.join(this.dir, hash);
1130
1136
  try {
1131
1137
  const file = Bun.file(blobPath);
@@ -1139,6 +1145,7 @@ export class BlobStore {
1139
1145
 
1140
1146
  /** Synchronously read blob by hash, returns Buffer or null if not found. */
1141
1147
  getSync(hash: string): Buffer | null {
1148
+ if (!isCanonicalBlobHash(hash)) return null;
1142
1149
  const blobPath = path.join(this.dir, hash);
1143
1150
  try {
1144
1151
  return fs.readFileSync(blobPath);
@@ -1155,6 +1162,7 @@ export class BlobStore {
1155
1162
 
1156
1163
  /** Synchronously read blob by hash and verify its content hash; returns null if not found. */
1157
1164
  getCheckedSync(hash: string): Buffer | null {
1165
+ if (!isCanonicalBlobHash(hash)) return null;
1158
1166
  const blobPath = path.join(this.dir, hash);
1159
1167
  try {
1160
1168
  return verifyBlobFileSync(hash, blobPath);
@@ -1166,6 +1174,7 @@ export class BlobStore {
1166
1174
 
1167
1175
  /** Check if a blob exists. */
1168
1176
  async has(hash: string): Promise<boolean> {
1177
+ if (!isCanonicalBlobHash(hash)) return false;
1169
1178
  try {
1170
1179
  await fsp.access(path.join(this.dir, hash));
1171
1180
  return true;
@@ -1321,6 +1330,7 @@ export class EphemeralBlobStore extends BlobStore {
1321
1330
  }
1322
1331
 
1323
1332
  getSync(hash: string): Buffer | null {
1333
+ if (!isCanonicalBlobHash(hash)) return null;
1324
1334
  const cached = this.#bufferCache.get(hash);
1325
1335
  if (cached) {
1326
1336
  const blobPath = path.join(this.dir, hash);
@@ -1374,7 +1384,7 @@ export class EphemeralBlobStore extends BlobStore {
1374
1384
  const blobPath = path.join(this.dir, entry);
1375
1385
  const stat = fs.lstatSync(blobPath);
1376
1386
  if (
1377
- !/^[a-f0-9]{64}$/.test(entry) ||
1387
+ !isCanonicalBlobHash(entry) ||
1378
1388
  !stat.isFile() ||
1379
1389
  stat.isSymbolicLink() ||
1380
1390
  stat.uid !== uid ||
@@ -1534,13 +1544,14 @@ export class ResidentBlobMissingError extends Error {
1534
1544
 
1535
1545
  /** Check if a data string is a blob reference. */
1536
1546
  export function isBlobRef(data: string): boolean {
1537
- return data.startsWith(BLOB_PREFIX);
1547
+ return parseBlobRef(data) !== null;
1538
1548
  }
1539
1549
 
1540
1550
  /** Extract the SHA-256 hash from a blob reference string. */
1541
1551
  export function parseBlobRef(data: string): string | null {
1542
1552
  if (!data.startsWith(BLOB_PREFIX)) return null;
1543
- return data.slice(BLOB_PREFIX.length);
1553
+ const hash = data.slice(BLOB_PREFIX.length);
1554
+ return isCanonicalBlobHash(hash) ? hash : null;
1544
1555
  }
1545
1556
 
1546
1557
  /** Identify provider transport image data URLs so persistence can externalize and restore them losslessly. */
@@ -1731,7 +1742,6 @@ export interface CanonicalBlobEntry {
1731
1742
  readonly nlink: bigint;
1732
1743
  }
1733
1744
 
1734
- const CANONICAL_BLOB_NAME = /^[0-9a-f]{64}$/;
1735
1745
  const BLOB_REFERENCE = /blob:sha256:([0-9a-f]{64})/g;
1736
1746
 
1737
1747
  /** Longest possible `blob:sha256:<hash>` reference, used to bound chunked scans. */
@@ -1758,7 +1768,7 @@ export async function listCanonicalBlobs(dir: string): Promise<CanonicalBlobEntr
1758
1768
 
1759
1769
  const entries: CanonicalBlobEntry[] = [];
1760
1770
  for (const name of names) {
1761
- if (!CANONICAL_BLOB_NAME.test(name)) continue;
1771
+ if (!isCanonicalBlobHash(name)) continue;
1762
1772
  const blobPath = path.join(dir, name);
1763
1773
  let stat: fs.BigIntStats;
1764
1774
  try {
@@ -0,0 +1,2 @@
1
+ export const CREDENTIAL_STORE_UNREADABLE_MESSAGE =
2
+ "Credential store is unreadable. Back up the database, then have an operator run PRAGMA integrity_check or REINDEX; no automatic repair was attempted.";
@@ -23,7 +23,7 @@
23
23
  * delivery therefore still carries its receipt and can never silently
24
24
  * degrade into an ordinary receipt-less completion.
25
25
  */
26
- import type { AsyncJob } from "../async/job-manager";
26
+ import type { AsyncJob, FoldReason } from "../async/job-manager";
27
27
  import foldReceiptPrompt from "../prompts/tools/fold-receipt.md" with { type: "text" };
28
28
 
29
29
  /**
@@ -68,6 +68,8 @@ export interface FoldReceipt {
68
68
  foldedAt: number;
69
69
  /** Only command kinds can change directory; task-style waits never do. */
70
70
  cwdSensitive: boolean;
71
+ /** What triggered the fold; recorded on the job as `metadata.foldReason`. */
72
+ reason: FoldReason;
71
73
  }
72
74
 
73
75
  /** A terminal completion observed for a folded job. */
@@ -106,6 +108,34 @@ export type FoldRequestResult =
106
108
  | { status: "already-terminal"; reason: string }
107
109
  | { status: "capture-failed"; reason: string };
108
110
 
111
+ /**
112
+ * Session-level answer to "fold the foreground bash now". Consumed by the SDK
113
+ * `bash.background` control, whose declared error codes are exactly these
114
+ * non-folded statuses.
115
+ */
116
+ export type ForegroundFoldOutcome =
117
+ | { status: "folded"; jobId: string }
118
+ | { status: "already_backgrounded" }
119
+ | { status: "no_active_bash" }
120
+ | { status: "not_foldable"; reason: string };
121
+
122
+ /** Map a non-folded outcome onto the C52 `bash.background` error contract (`not_foldable` | `already_backgrounded` | `no_active_bash`). */
123
+ export function bashBackgroundControlError(outcome: Exclude<ForegroundFoldOutcome, { status: "folded" }>): Error {
124
+ switch (outcome.status) {
125
+ case "already_backgrounded":
126
+ return Object.assign(new Error("The active bash command has already been moved to a background job."), {
127
+ code: "already_backgrounded",
128
+ });
129
+ case "no_active_bash":
130
+ return Object.assign(new Error("No foreground bash command is running."), { code: "no_active_bash" });
131
+ case "not_foldable":
132
+ return Object.assign(
133
+ new Error(`The active bash command cannot be moved to a managed background job: ${outcome.reason}`),
134
+ { code: "not_foldable" },
135
+ );
136
+ }
137
+ }
138
+
109
139
  /** What a delivery should carry, decided by the durable slot state (T2). */
110
140
  export type FoldDeliveryDisposition =
111
141
  | { kind: "ordinary" }
@@ -225,8 +255,13 @@ export class FoldCoordinator {
225
255
  * Nothing awaits before the slot is reserved and the fence is armed, so a
226
256
  * completion or a steering submission that races the capture cannot slip
227
257
  * past into the old turn.
258
+ *
259
+ * A `steer` fold is the one trigger that does NOT end the turn: the steer
260
+ * that caused it must be consumed by the same run at the tool boundary
261
+ * right after the fold result (subagent-await parity), so no fence is
262
+ * armed, no stop is requested, and no remaining intent is captured.
228
263
  */
229
- async requestFold(explicit?: FoldAdapter): Promise<FoldRequestResult> {
264
+ async requestFold(explicit?: FoldAdapter, reason: FoldReason = "chord"): Promise<FoldRequestResult> {
230
265
  // S1 resolve target.
231
266
  const adapter = explicit ?? this.resolveTarget();
232
267
  if (!adapter) return { status: "unavailable", reason: "no foldable wait is registered" };
@@ -244,7 +279,8 @@ export class FoldCoordinator {
244
279
  // S3 claim + reserve, S4 hand-off is the reservation itself, S5 arm the fence.
245
280
  this.#folding.add(job);
246
281
  this.#slots.set(job, { state: "reserved", adapter, parked: undefined, parkedAt: undefined });
247
- const fencesOriginatingTurn = adapter.originatingTurn ?? this.#deps.hasActiveTurn?.() ?? true;
282
+ const fencesOriginatingTurn =
283
+ reason !== "steer" && (adapter.originatingTurn ?? this.#deps.hasActiveTurn?.() ?? true);
248
284
  const releaseFence = fencesOriginatingTurn ? this.#deps.armSteeringFence() : () => {};
249
285
 
250
286
  let remainingIntent: string | undefined;
@@ -293,6 +329,7 @@ export class FoldCoordinator {
293
329
  remainingIntent,
294
330
  foldedAt: Date.now(),
295
331
  cwdSensitive: adapter.cwdSensitive,
332
+ reason,
296
333
  };
297
334
 
298
335
  // A2 promote to present, preserving any payload parked during capture.