@loucompanion/forge-bridge 0.1.3-dev.f66395c3ac21 → 0.1.4-dev.04a1e5b9e484

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 (223) hide show
  1. package/README.md +165 -1
  2. package/dist/bridge/bridge-chat.types.d.ts +111 -0
  3. package/dist/bridge/bridge-chat.types.js +401 -0
  4. package/dist/bridge/bridge.base.d.ts +9 -1
  5. package/dist/bridge/bridge.service.d.ts +129 -3
  6. package/dist/bridge/bridge.service.js +2427 -70
  7. package/dist/bridge/bridge.types.d.ts +218 -2
  8. package/dist/bridge/dispatch-result-outbox.d.ts +25 -0
  9. package/dist/bridge/dispatch-result-outbox.js +62 -0
  10. package/dist/bridge/dispatch-result-worker.d.ts +2 -0
  11. package/dist/bridge/dispatch-result-worker.js +122 -0
  12. package/dist/bridge/internals.d.ts +2 -0
  13. package/dist/bridge/internals.js +1 -0
  14. package/dist/bridge/readiness-result-outbox.d.ts +21 -0
  15. package/dist/bridge/readiness-result-outbox.js +54 -0
  16. package/dist/bridge/readiness-result-worker.d.ts +2 -0
  17. package/dist/bridge/readiness-result-worker.js +121 -0
  18. package/dist/bridge/runner-host-capabilities.d.ts +15 -0
  19. package/dist/bridge/runner-host-capabilities.js +93 -0
  20. package/dist/cleanup/cleanup.service.d.ts +14 -2
  21. package/dist/cleanup/cleanup.service.js +496 -3
  22. package/dist/cleanup/cleanup.types.d.ts +10 -0
  23. package/dist/cleanup/index.d.ts +1 -1
  24. package/dist/cleanup/index.js +1 -1
  25. package/dist/cleanup/internals.d.ts +2 -2
  26. package/dist/cleanup/internals.js +1 -1
  27. package/dist/cli/cli.help.d.ts +2 -0
  28. package/dist/cli/cli.help.js +217 -0
  29. package/dist/cli/cli.service.d.ts +55 -7
  30. package/dist/cli/cli.service.js +429 -219
  31. package/dist/cli/local-config.d.ts +7 -0
  32. package/dist/cli/local-config.js +51 -3
  33. package/dist/runtime/aspnet-runtime-prebuild.d.ts +36 -0
  34. package/dist/runtime/aspnet-runtime-prebuild.js +341 -0
  35. package/dist/runtime/attempt-database-broker.d.ts +89 -0
  36. package/dist/runtime/attempt-database-broker.js +390 -0
  37. package/dist/runtime/attempt-node-runtime-launcher.d.ts +18 -0
  38. package/dist/runtime/attempt-node-runtime-launcher.js +140 -0
  39. package/dist/runtime/attempt-path-operation.d.ts +21 -0
  40. package/dist/runtime/attempt-path-operation.js +94 -0
  41. package/dist/runtime/attempt-private-directory.d.ts +6 -0
  42. package/dist/runtime/attempt-private-directory.js +54 -0
  43. package/dist/runtime/attempt-process-supervisor-registry.d.ts +20 -0
  44. package/dist/runtime/attempt-process-supervisor-registry.js +64 -0
  45. package/dist/runtime/attempt-process-supervisor.d.ts +102 -0
  46. package/dist/runtime/attempt-process-supervisor.js +421 -0
  47. package/dist/runtime/canonical-source-file.d.ts +3 -0
  48. package/dist/runtime/canonical-source-file.js +54 -0
  49. package/dist/runtime/docker-engine-probe.d.ts +90 -0
  50. package/dist/runtime/docker-engine-probe.js +333 -0
  51. package/dist/runtime/generated-output-reset.d.ts +20 -0
  52. package/dist/runtime/generated-output-reset.js +157 -0
  53. package/dist/runtime/host-database-capability-boundary.d.ts +16 -0
  54. package/dist/runtime/host-database-capability-boundary.js +62 -0
  55. package/dist/runtime/host-diagnostics.d.ts +11 -0
  56. package/dist/runtime/host-diagnostics.js +192 -0
  57. package/dist/runtime/host-execution-root.d.ts +4 -0
  58. package/dist/runtime/host-execution-root.js +39 -0
  59. package/dist/runtime/host-listener-inspector.d.ts +51 -0
  60. package/dist/runtime/host-listener-inspector.js +385 -0
  61. package/dist/runtime/host-port-broker.d.ts +76 -0
  62. package/dist/runtime/host-port-broker.js +333 -0
  63. package/dist/runtime/host-runtime-contract.d.ts +58 -0
  64. package/dist/runtime/host-runtime-contract.js +813 -0
  65. package/dist/runtime/host-runtime-lease.d.ts +217 -0
  66. package/dist/runtime/host-runtime-lease.js +2487 -0
  67. package/dist/runtime/host-runtime-promotion.d.ts +32 -0
  68. package/dist/runtime/host-runtime-promotion.js +206 -0
  69. package/dist/runtime/memory-capacity.d.ts +70 -0
  70. package/dist/runtime/memory-capacity.js +123 -0
  71. package/dist/runtime/native-test-postgres-fallback.d.ts +25 -0
  72. package/dist/runtime/native-test-postgres-fallback.js +91 -0
  73. package/dist/runtime/node-host-runtime-adapter.d.ts +54 -0
  74. package/dist/runtime/node-host-runtime-adapter.js +286 -0
  75. package/dist/runtime/pinned-directory-process.d.ts +9 -0
  76. package/dist/runtime/pinned-directory-process.js +61 -0
  77. package/dist/runtime/pinned-source-directory.d.ts +17 -0
  78. package/dist/runtime/pinned-source-directory.js +94 -0
  79. package/dist/runtime/playwright-host-runtime-adapter.d.ts +21 -0
  80. package/dist/runtime/playwright-host-runtime-adapter.js +268 -0
  81. package/dist/runtime/prepared-runtime-identity.d.ts +6 -0
  82. package/dist/runtime/prepared-runtime-identity.js +218 -0
  83. package/dist/runtime/prepared-runtime-readiness.d.ts +30 -0
  84. package/dist/runtime/prepared-runtime-readiness.js +285 -0
  85. package/dist/runtime/runtime-isolation-lease.d.ts +67 -0
  86. package/dist/runtime/runtime-isolation-lease.js +161 -0
  87. package/dist/runtime/workspace-resource-estimator.d.ts +17 -0
  88. package/dist/runtime/workspace-resource-estimator.js +174 -0
  89. package/dist/sandbox/command-runner.d.ts +4 -0
  90. package/dist/sandbox/command-runner.js +47 -0
  91. package/dist/sandbox/contract.d.ts +5 -0
  92. package/dist/sandbox/contract.js +276 -0
  93. package/dist/sandbox/event-budget.d.ts +11 -0
  94. package/dist/sandbox/event-budget.js +27 -0
  95. package/dist/sandbox/image-policy.d.ts +35 -0
  96. package/dist/sandbox/image-policy.js +247 -0
  97. package/dist/sandbox/index.d.ts +5 -0
  98. package/dist/sandbox/index.js +5 -0
  99. package/dist/sandbox/lease-watchdog.d.ts +18 -0
  100. package/dist/sandbox/lease-watchdog.js +67 -0
  101. package/dist/sandbox/preflight.d.ts +84 -0
  102. package/dist/sandbox/preflight.js +521 -0
  103. package/dist/sandbox/process.d.ts +20 -0
  104. package/dist/sandbox/process.js +209 -0
  105. package/dist/sandbox/provider-auth/codex.d.ts +26 -0
  106. package/dist/sandbox/provider-auth/codex.js +212 -0
  107. package/dist/sandbox/repository-lock.d.ts +6 -0
  108. package/dist/sandbox/repository-lock.js +129 -0
  109. package/dist/sandbox/runtime.d.ts +302 -0
  110. package/dist/sandbox/runtime.js +2368 -0
  111. package/dist/sandbox/sandbox.types.d.ts +93 -0
  112. package/dist/sandbox/sandbox.types.js +1 -0
  113. package/dist/sandbox/smoke.d.ts +76 -0
  114. package/dist/sandbox/smoke.js +380 -0
  115. package/dist/sandbox/worker-supervisor.d.ts +13 -0
  116. package/dist/sandbox/worker-supervisor.js +36 -0
  117. package/dist/sandbox/worker.d.ts +1 -0
  118. package/dist/sandbox/worker.js +225 -0
  119. package/dist/sandbox/workspace.service.d.ts +13 -0
  120. package/dist/sandbox/workspace.service.js +74 -0
  121. package/dist/session/managed-attempt-tools.d.ts +28 -0
  122. package/dist/session/managed-attempt-tools.js +1016 -0
  123. package/dist/session/managed-build-coordinator.d.ts +5 -0
  124. package/dist/session/managed-build-coordinator.js +106 -0
  125. package/dist/session/managed-build-receipt.d.ts +21 -0
  126. package/dist/session/managed-build-receipt.js +337 -0
  127. package/dist/session/managed-verification-timeouts.d.ts +8 -0
  128. package/dist/session/managed-verification-timeouts.js +17 -0
  129. package/dist/session/phase-completion.artifacts.d.ts +27 -0
  130. package/dist/session/phase-completion.artifacts.js +829 -0
  131. package/dist/session/phase-completion.d.ts +53 -42
  132. package/dist/session/phase-completion.helpers.d.ts +117 -0
  133. package/dist/session/phase-completion.helpers.js +707 -0
  134. package/dist/session/phase-completion.js +125 -3007
  135. package/dist/session/phase-completion.prompts.d.ts +14 -0
  136. package/dist/session/phase-completion.prompts.js +233 -0
  137. package/dist/session/phase-completion.runtime.d.ts +49 -0
  138. package/dist/session/phase-completion.runtime.js +840 -0
  139. package/dist/session/phase-completion.schemas.d.ts +3 -0
  140. package/dist/session/phase-completion.schemas.js +859 -0
  141. package/dist/session/phase-completion.validation.d.ts +38 -0
  142. package/dist/session/phase-completion.validation.js +918 -0
  143. package/dist/session/pre-publication-validation.d.ts +75 -0
  144. package/dist/session/pre-publication-validation.js +661 -0
  145. package/dist/session/provider-cli/bridge-cli.conformance-fixtures.d.ts +72 -0
  146. package/dist/session/provider-cli/bridge-cli.conformance-fixtures.js +462 -0
  147. package/dist/session/provider-cli/ci-repair-readiness.d.ts +16 -0
  148. package/dist/session/provider-cli/ci-repair-readiness.js +110 -0
  149. package/dist/session/provider-cli/provider-cli.artifacts.d.ts +95 -0
  150. package/dist/session/provider-cli/provider-cli.artifacts.js +812 -0
  151. package/dist/session/provider-cli/provider-cli.base.d.ts +1 -0
  152. package/dist/session/provider-cli/provider-cli.deterministic-payloads.d.ts +12 -0
  153. package/dist/session/provider-cli/provider-cli.deterministic-payloads.js +279 -0
  154. package/dist/session/provider-cli/provider-cli.deterministic.d.ts +14 -0
  155. package/dist/session/provider-cli/provider-cli.deterministic.js +407 -0
  156. package/dist/session/provider-cli/provider-cli.process.d.ts +99 -0
  157. package/dist/session/provider-cli/provider-cli.process.js +874 -0
  158. package/dist/session/provider-cli/provider-cli.prompts.d.ts +52 -0
  159. package/dist/session/provider-cli/provider-cli.prompts.js +715 -0
  160. package/dist/session/provider-cli/provider-cli.qa-sidecars.d.ts +11 -0
  161. package/dist/session/provider-cli/provider-cli.qa-sidecars.js +66 -0
  162. package/dist/session/provider-cli/provider-cli.repair-epoch.d.ts +6 -0
  163. package/dist/session/provider-cli/provider-cli.repair-epoch.js +11 -0
  164. package/dist/session/provider-cli/provider-cli.runtime.d.ts +22 -0
  165. package/dist/session/provider-cli/provider-cli.runtime.js +92 -0
  166. package/dist/session/provider-cli/provider-cli.service.d.ts +47 -53
  167. package/dist/session/provider-cli/provider-cli.service.js +1258 -2497
  168. package/dist/session/provider-cli/provider-cli.types.d.ts +8 -0
  169. package/dist/session/provider-cli/provider-output-state.d.ts +32 -0
  170. package/dist/session/provider-cli/provider-output-state.js +817 -0
  171. package/dist/session/provider-cli/provider-usage.d.ts +7 -0
  172. package/dist/session/provider-cli/provider-usage.js +28 -5
  173. package/dist/session/session-redaction.d.ts +3 -0
  174. package/dist/session/session-redaction.js +448 -0
  175. package/dist/session/session.base.d.ts +6 -1
  176. package/dist/session/session.service.d.ts +8 -2
  177. package/dist/session/session.service.js +586 -59
  178. package/dist/session/session.types.d.ts +324 -3
  179. package/dist/session/session.types.js +939 -10
  180. package/dist/session/unreferenced-exports.d.ts +12 -0
  181. package/dist/session/unreferenced-exports.js +59 -0
  182. package/dist/shared/format/format-bytes.d.ts +1 -0
  183. package/dist/shared/format/format-bytes.js +9 -0
  184. package/dist/shared/git/git.js +2 -1
  185. package/dist/shared/path/path.d.ts +1 -0
  186. package/dist/shared/path/path.js +21 -1
  187. package/dist/shared/process/dotnet-toolchain.d.ts +17 -0
  188. package/dist/shared/process/dotnet-toolchain.js +307 -0
  189. package/dist/shared/process/host-process-recovery.d.ts +12 -0
  190. package/dist/shared/process/host-process-recovery.js +79 -0
  191. package/dist/shared/process/host-process-supervisor.d.ts +59 -0
  192. package/dist/shared/process/host-process-supervisor.js +331 -0
  193. package/dist/shared/process/process.d.ts +3 -0
  194. package/dist/shared/process/process.js +13 -7
  195. package/dist/shared/process/windows-launch.d.ts +8 -0
  196. package/dist/shared/process/windows-launch.js +41 -0
  197. package/dist/shared/provider-capabilities.d.ts +4 -0
  198. package/dist/shared/provider-capabilities.js +88 -0
  199. package/dist/shared/redaction/redaction.d.ts +1 -0
  200. package/dist/shared/redaction/redaction.js +47 -4
  201. package/dist/shared/time/monotonic.d.ts +1 -0
  202. package/dist/shared/time/monotonic.js +8 -0
  203. package/dist/version.d.ts +1 -1
  204. package/dist/version.js +1 -1
  205. package/dist/worktree/artifact-injector.d.ts +3 -2
  206. package/dist/worktree/artifact-injector.js +82 -10
  207. package/dist/worktree/dependency-warmer.d.ts +53 -1
  208. package/dist/worktree/dependency-warmer.js +619 -11
  209. package/dist/worktree/index.d.ts +2 -1
  210. package/dist/worktree/index.js +1 -0
  211. package/dist/worktree/prior-phase-artifact-hydrator.d.ts +2 -0
  212. package/dist/worktree/prior-phase-artifact-hydrator.js +136 -0
  213. package/dist/worktree/story-qa-reference-hydrator.d.ts +4 -0
  214. package/dist/worktree/story-qa-reference-hydrator.js +253 -0
  215. package/dist/worktree/worktree-paths.d.ts +4 -0
  216. package/dist/worktree/worktree-paths.js +30 -0
  217. package/dist/worktree/worktree.base.d.ts +3 -0
  218. package/dist/worktree/worktree.service.d.ts +16 -3
  219. package/dist/worktree/worktree.service.js +334 -54
  220. package/dist/worktree/worktree.types.d.ts +9 -1
  221. package/package.json +12 -7
  222. package/runtime/windows-job-supervisor.ps1 +722 -0
  223. package/runtime/windows-listener-owner.ps1 +33 -0
@@ -0,0 +1,72 @@
1
+ import { type BridgeChatCapability, type BridgeChatRequestedCapability, type ChatTurnCallbackEnvelope, type ChatTurnCallbackKind, type ChatTurnDispatchPacket, type ChatTurnMessage } from "../../bridge/bridge-chat.types.js";
2
+ export declare const requiredBridgeCliScenarioKeys: readonly ["happy-path", "cancellation", "failure", "malformed-tool-call", "redaction"];
3
+ export type BridgeCliConformanceScenarioKey = typeof requiredBridgeCliScenarioKeys[number];
4
+ export type BridgeCliConformanceProviderKind = "codex" | "cursor";
5
+ export type BridgeCliConformanceRuntimeKind = "managed-host";
6
+ export interface BridgeCliConformanceCapabilityFixture {
7
+ readonly fixtureKey: string;
8
+ readonly runtimeState: string;
9
+ readonly supportedCapabilities: readonly BridgeChatRequestedCapability[];
10
+ readonly metadata: Readonly<Record<string, string>>;
11
+ readonly capability: BridgeChatCapability;
12
+ }
13
+ export interface BridgeCliConformanceInputTurn {
14
+ readonly turnKey: string;
15
+ readonly messages: readonly ChatTurnMessage[];
16
+ readonly toolCalls: readonly BridgeCliConformanceInputToolCall[];
17
+ readonly requestedCapabilities: readonly BridgeChatRequestedCapability[];
18
+ readonly providerThreadId: string | null;
19
+ readonly dispatchPacket: ChatTurnDispatchPacket;
20
+ }
21
+ export interface BridgeCliConformanceInputToolCall {
22
+ readonly toolName: string;
23
+ readonly argumentsJson: string;
24
+ readonly isMalformed?: boolean;
25
+ }
26
+ export interface BridgeCliConformanceExpectedEvent {
27
+ readonly sequence: number;
28
+ readonly adapterEventId: string | null;
29
+ readonly eventType: ChatTurnCallbackKind;
30
+ readonly payloadKey?: string | null;
31
+ }
32
+ export interface BridgeCliConformanceExpectedTerminalState {
33
+ readonly state: "completed" | "cancelled" | "failed" | "rejected";
34
+ readonly failureCode?: string | null;
35
+ readonly failureKind?: string | null;
36
+ }
37
+ export interface BridgeCliConformanceExpectedSnapshotState {
38
+ readonly runtimeState: string;
39
+ readonly providerThreadId: string | null;
40
+ readonly metadata: Readonly<Record<string, string>>;
41
+ }
42
+ export interface BridgeCliConformanceProviderStreamFixture {
43
+ readonly stdoutLines: readonly string[];
44
+ readonly expectedEventTypes: readonly string[];
45
+ readonly expectedFinalMessage: string | null;
46
+ }
47
+ export interface BridgeCliChatAdapterConformanceCase {
48
+ readonly adapterKind: "bridge-cli";
49
+ readonly runtimeKind: BridgeCliConformanceRuntimeKind;
50
+ readonly providerKind: BridgeCliConformanceProviderKind;
51
+ readonly capabilityFixture: BridgeCliConformanceCapabilityFixture;
52
+ readonly scenarioKey: BridgeCliConformanceScenarioKey;
53
+ readonly inputTurn: BridgeCliConformanceInputTurn;
54
+ readonly expectedEvents: readonly BridgeCliConformanceExpectedEvent[];
55
+ readonly expectedTerminalState: BridgeCliConformanceExpectedTerminalState;
56
+ readonly expectedSnapshotState: BridgeCliConformanceExpectedSnapshotState;
57
+ readonly prohibitedLogPatterns: readonly string[];
58
+ readonly skipReason: string | null;
59
+ readonly callbackEnvelope: ChatTurnCallbackEnvelope;
60
+ readonly providerStream: BridgeCliConformanceProviderStreamFixture;
61
+ readonly redactionSecrets: readonly string[];
62
+ }
63
+ export interface BridgeCliEnvelopeRejectionCase {
64
+ readonly caseKey: string;
65
+ readonly sourceScenarioKey: BridgeCliConformanceScenarioKey;
66
+ readonly dispatchPacket: Readonly<Record<string, unknown>>;
67
+ readonly capability: BridgeChatCapability;
68
+ readonly expectedMessage: string;
69
+ }
70
+ export declare const bridgeCliConformanceCases: readonly BridgeCliChatAdapterConformanceCase[];
71
+ export declare const bridgeCliEnvelopeRejectionCases: readonly BridgeCliEnvelopeRejectionCase[];
72
+ export declare const malformedProviderStreamFixtures: Readonly<Record<BridgeCliConformanceProviderKind, readonly string[]>>;
@@ -0,0 +1,462 @@
1
+ import { bridgeChatProtocolVersion, unavailableBridgeChatCapability, } from "../../bridge/bridge-chat.types.js";
2
+ export const requiredBridgeCliScenarioKeys = [
3
+ "happy-path",
4
+ "cancellation",
5
+ "failure",
6
+ "malformed-tool-call",
7
+ "redaction",
8
+ ];
9
+ const ids = {
10
+ callbackId: "77777777-7777-4777-8777-777777777777",
11
+ chatRunId: "11111111-1111-4111-8111-111111111111",
12
+ conversationId: "22222222-2222-4222-8222-222222222222",
13
+ turnId: "33333333-3333-4333-8333-333333333333",
14
+ leaseId: "44444444-4444-4444-8444-444444444444",
15
+ fencingToken: "55555555-5555-4555-8555-555555555555",
16
+ runnerInstanceId: "66666666-6666-4666-8666-666666666666",
17
+ runnerId: "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
18
+ attachmentId: "88888888-8888-4888-8888-888888888888",
19
+ grantId: "99999999-9999-4999-8999-999999999999",
20
+ };
21
+ const deterministicExpiresAt = "2099-01-01T00:00:00.000Z";
22
+ const redactionSecrets = [
23
+ "raw-provider-secret",
24
+ "raw-tool-token",
25
+ "opaque-temp-file-token",
26
+ "opaque-grant-nonce",
27
+ ];
28
+ const prohibitedLogPatterns = [
29
+ "raw-provider-secret",
30
+ "raw-tool-token",
31
+ "opaque-temp-file-token",
32
+ "opaque-grant-nonce",
33
+ "sk-[A-Za-z0-9_-]+",
34
+ "Authorization:\\s*Bearer\\s+(?!\\[REDACTED\\])\\S+",
35
+ ];
36
+ const providerDefinitions = [
37
+ {
38
+ providerKind: "codex",
39
+ model: "gpt-5-codex",
40
+ runtimeState: "codex-cli-authenticated",
41
+ providerThreadPrefix: "codex-thread",
42
+ },
43
+ {
44
+ providerKind: "cursor",
45
+ model: "cursor-fast",
46
+ runtimeState: "cursor-agent-authenticated",
47
+ providerThreadPrefix: "cursor-session",
48
+ },
49
+ ];
50
+ const scenarioDefinitions = [
51
+ {
52
+ scenarioKey: "happy-path",
53
+ requestedCapabilities: [
54
+ "text",
55
+ "cancel",
56
+ "resume",
57
+ "thread_continuity",
58
+ "attachment_handoffs",
59
+ "action_broker_grants",
60
+ ],
61
+ terminalEventType: "output_completed",
62
+ terminalState: { state: "completed" },
63
+ finalMessage: "Deterministic Bridge CLI turn completed.",
64
+ includeBoundedEnvelopes: true,
65
+ },
66
+ {
67
+ scenarioKey: "cancellation",
68
+ requestedCapabilities: ["text", "cancel", "thread_continuity"],
69
+ terminalEventType: "cancelled",
70
+ terminalState: {
71
+ state: "cancelled",
72
+ failureCode: "chat_turn_cancelled",
73
+ failureKind: "cancelled",
74
+ },
75
+ finalMessage: null,
76
+ },
77
+ {
78
+ scenarioKey: "failure",
79
+ requestedCapabilities: ["text", "thread_continuity"],
80
+ terminalEventType: "failed",
81
+ terminalState: {
82
+ state: "failed",
83
+ failureCode: "provider_failed",
84
+ failureKind: "provider",
85
+ },
86
+ finalMessage: null,
87
+ },
88
+ {
89
+ scenarioKey: "malformed-tool-call",
90
+ requestedCapabilities: ["text", "thread_continuity"],
91
+ terminalEventType: "failed",
92
+ terminalState: {
93
+ state: "rejected",
94
+ failureCode: "bridge_cli.malformed_tool_call",
95
+ failureKind: "malformed_tool_call",
96
+ },
97
+ finalMessage: null,
98
+ toolCalls: [{
99
+ toolName: "write_file",
100
+ argumentsJson: "{\"path\":",
101
+ isMalformed: true,
102
+ }],
103
+ },
104
+ {
105
+ scenarioKey: "redaction",
106
+ requestedCapabilities: [
107
+ "text",
108
+ "thread_continuity",
109
+ "attachment_handoffs",
110
+ "action_broker_grants",
111
+ ],
112
+ terminalEventType: "output_completed",
113
+ terminalState: { state: "completed" },
114
+ finalMessage: "Redacted Bridge CLI turn completed.",
115
+ includeBoundedEnvelopes: true,
116
+ },
117
+ ];
118
+ export const bridgeCliConformanceCases = providerDefinitions.flatMap((provider) => scenarioDefinitions.map((scenario) => buildCase(provider, scenario)));
119
+ const sourceCase = bridgeCliConformanceCases.find((testCase) => testCase.providerKind === "codex" && testCase.scenarioKey === "happy-path");
120
+ if (!sourceCase) {
121
+ throw new Error("Bridge CLI conformance happy-path fixture was not initialized.");
122
+ }
123
+ const sourcePacket = sourceCase.inputTurn.dispatchPacket;
124
+ const sourceCapability = sourceCase.capabilityFixture.capability;
125
+ export const bridgeCliEnvelopeRejectionCases = [
126
+ {
127
+ caseKey: "attachment_handoff_unsupported_runner",
128
+ sourceScenarioKey: "happy-path",
129
+ capability: capabilityFor("codex", "gpt-5-codex", { supportsAttachments: false }),
130
+ dispatchPacket: {
131
+ ...packetRecord(sourcePacket),
132
+ requestedCapabilities: ["text", "attachment_handoffs"],
133
+ attachmentHandoffs: [attachmentHandoff()],
134
+ actionBrokerGrants: [],
135
+ },
136
+ expectedMessage: "requestedCapabilities attachment_handoffs for this runner",
137
+ },
138
+ {
139
+ caseKey: "attachment_handoff_unfenced_turn",
140
+ sourceScenarioKey: "happy-path",
141
+ capability: sourceCapability,
142
+ dispatchPacket: {
143
+ ...packetRecord(sourcePacket),
144
+ requestedCapabilities: ["text", "attachment_handoffs"],
145
+ attachmentHandoffs: [{
146
+ ...attachmentHandoff(),
147
+ turnId: "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
148
+ }],
149
+ actionBrokerGrants: [],
150
+ },
151
+ expectedMessage: "attachmentHandoffs[0].turnId must match turnId",
152
+ },
153
+ {
154
+ caseKey: "attachment_handoff_malformed_direct_path",
155
+ sourceScenarioKey: "happy-path",
156
+ capability: sourceCapability,
157
+ dispatchPacket: {
158
+ ...packetRecord(sourcePacket),
159
+ requestedCapabilities: ["text", "attachment_handoffs"],
160
+ attachmentHandoffs: [{
161
+ ...attachmentHandoff(),
162
+ rawPath: "C:\\Users\\developer\\secret.txt",
163
+ }],
164
+ actionBrokerGrants: [],
165
+ },
166
+ expectedMessage: "attachmentHandoffs[0].rawPath is not supported",
167
+ },
168
+ {
169
+ caseKey: "action_grant_widened_without_request",
170
+ sourceScenarioKey: "happy-path",
171
+ capability: sourceCapability,
172
+ dispatchPacket: {
173
+ ...packetRecord(sourcePacket),
174
+ requestedCapabilities: ["text"],
175
+ attachmentHandoffs: [],
176
+ actionBrokerGrants: [actionBrokerGrant()],
177
+ },
178
+ expectedMessage: "actionBrokerGrants require requestedCapabilities to include action_broker_grants",
179
+ },
180
+ {
181
+ caseKey: "action_grant_direct_execution_input",
182
+ sourceScenarioKey: "happy-path",
183
+ capability: sourceCapability,
184
+ dispatchPacket: {
185
+ ...packetRecord(sourcePacket),
186
+ requestedCapabilities: ["text", "action_broker_grants"],
187
+ attachmentHandoffs: [],
188
+ actionBrokerGrants: [{
189
+ ...actionBrokerGrant(),
190
+ executeCommand: "Remove-Item -Recurse C:\\repo",
191
+ }],
192
+ },
193
+ expectedMessage: "actionBrokerGrants[0].executeCommand is not supported",
194
+ },
195
+ {
196
+ caseKey: "action_grant_unfenced_lease",
197
+ sourceScenarioKey: "happy-path",
198
+ capability: sourceCapability,
199
+ dispatchPacket: {
200
+ ...packetRecord(sourcePacket),
201
+ requestedCapabilities: ["text", "action_broker_grants"],
202
+ attachmentHandoffs: [],
203
+ actionBrokerGrants: [{
204
+ ...actionBrokerGrant(),
205
+ leaseId: "cccccccc-cccc-4ccc-8ccc-cccccccccccc",
206
+ }],
207
+ },
208
+ expectedMessage: "actionBrokerGrants[0] must match the active dispatch fence",
209
+ },
210
+ ];
211
+ export const malformedProviderStreamFixtures = {
212
+ codex: [
213
+ "not-json",
214
+ JSON.stringify({ type: "item.started", item: { type: "mcp_tool_call", server: "forge", status: "in_progress" } }),
215
+ JSON.stringify({ type: "item.completed", item: { type: "mcp_tool_call", server: "forge", status: "completed" } }),
216
+ ],
217
+ cursor: [
218
+ "not-json",
219
+ JSON.stringify({ type: "tool_call", subtype: "started", tool_call: { writeToolCall: { args: { path: "" } } } }),
220
+ JSON.stringify({ type: "tool_call", subtype: "completed", tool_call: { writeToolCall: { result: { success: {} } } } }),
221
+ ],
222
+ };
223
+ function buildCase(provider, scenario) {
224
+ const providerThreadId = `${provider.providerThreadPrefix}-${scenario.scenarioKey}`;
225
+ const capability = capabilityFor(provider.providerKind, provider.model);
226
+ const attachmentHandoffs = scenario.includeBoundedEnvelopes ? [attachmentHandoff()] : [];
227
+ const actionBrokerGrants = scenario.includeBoundedEnvelopes ? [actionBrokerGrant()] : [];
228
+ const messages = messagesFor(scenario.scenarioKey);
229
+ const dispatchPacket = {
230
+ chatRunId: ids.chatRunId,
231
+ conversationId: ids.conversationId,
232
+ turnId: ids.turnId,
233
+ leaseId: ids.leaseId,
234
+ fencingToken: ids.fencingToken,
235
+ runnerInstanceId: ids.runnerInstanceId,
236
+ providerKind: provider.providerKind,
237
+ model: provider.model,
238
+ messages,
239
+ contextRefs: [{
240
+ kind: "work_item",
241
+ refId: `bridge-cli-${scenario.scenarioKey}`,
242
+ title: "Bridge CLI deterministic conformance",
243
+ summary: "Fixture mapped to ChatAdapterConformanceCase fields.",
244
+ metadata: {
245
+ adapterKind: "bridge-cli",
246
+ runtimeKind: "managed-host",
247
+ providerKind: provider.providerKind,
248
+ scenarioKey: scenario.scenarioKey,
249
+ },
250
+ }],
251
+ idempotencyKey: `bridge-cli-${provider.providerKind}-${scenario.scenarioKey}`,
252
+ providerThreadId,
253
+ protocolVersion: bridgeChatProtocolVersion,
254
+ requestedCapabilities: scenario.requestedCapabilities,
255
+ attachmentHandoffs,
256
+ actionBrokerGrants,
257
+ };
258
+ return {
259
+ adapterKind: "bridge-cli",
260
+ runtimeKind: "managed-host",
261
+ providerKind: provider.providerKind,
262
+ capabilityFixture: {
263
+ fixtureKey: `${provider.providerKind}-managed-host-${scenario.scenarioKey}`,
264
+ runtimeState: provider.runtimeState,
265
+ supportedCapabilities: [
266
+ "text",
267
+ "cancel",
268
+ "resume",
269
+ "thread_continuity",
270
+ "attachment_handoffs",
271
+ "action_broker_grants",
272
+ ],
273
+ metadata: {
274
+ model: provider.model,
275
+ protocolVersion: bridgeChatProtocolVersion,
276
+ },
277
+ capability,
278
+ },
279
+ scenarioKey: scenario.scenarioKey,
280
+ inputTurn: {
281
+ turnKey: `${provider.providerKind}-${scenario.scenarioKey}`,
282
+ messages,
283
+ toolCalls: scenario.toolCalls ?? [],
284
+ requestedCapabilities: scenario.requestedCapabilities,
285
+ providerThreadId,
286
+ dispatchPacket,
287
+ },
288
+ expectedEvents: expectedEventsFor(scenario.terminalEventType),
289
+ expectedTerminalState: scenario.terminalState,
290
+ expectedSnapshotState: {
291
+ runtimeState: scenario.terminalState.state,
292
+ providerThreadId,
293
+ metadata: {
294
+ providerKind: provider.providerKind,
295
+ scenarioKey: scenario.scenarioKey,
296
+ },
297
+ },
298
+ prohibitedLogPatterns,
299
+ skipReason: null,
300
+ callbackEnvelope: callbackEnvelopeFor(dispatchPacket, scenario.terminalEventType, scenario.finalMessage),
301
+ providerStream: providerStreamFor(provider.providerKind, providerThreadId, scenario),
302
+ redactionSecrets,
303
+ };
304
+ }
305
+ function capabilityFor(providerKind, model, overrides = {}) {
306
+ return {
307
+ ...unavailableBridgeChatCapability(),
308
+ availability: "available",
309
+ supportedProviders: [providerKind],
310
+ supportedModels: [model],
311
+ supportsTextStreaming: true,
312
+ supportsCancel: true,
313
+ supportsResume: true,
314
+ supportsProviderThreadContinuity: true,
315
+ supportsAttachments: true,
316
+ supportsActionBrokerGrants: true,
317
+ maxMessageBytes: 128 * 1024,
318
+ maxContextRefs: 8,
319
+ ...overrides,
320
+ };
321
+ }
322
+ function messagesFor(scenarioKey) {
323
+ if (scenarioKey === "redaction") {
324
+ return [{
325
+ role: "user",
326
+ content: "Check redaction boundaries without exposing raw-provider-secret.",
327
+ metadata: { scenarioKey },
328
+ }];
329
+ }
330
+ return [{
331
+ role: "user",
332
+ content: `Run deterministic ${scenarioKey} conformance.`,
333
+ metadata: { scenarioKey },
334
+ }];
335
+ }
336
+ function expectedEventsFor(terminalEventType) {
337
+ const events = [{
338
+ sequence: 1,
339
+ adapterEventId: "bridge-cli-turn-started",
340
+ eventType: "turn_started",
341
+ payloadKey: "turn_started",
342
+ }];
343
+ if (terminalEventType === "output_completed") {
344
+ events.push({
345
+ sequence: 2,
346
+ adapterEventId: "bridge-cli-output-delta",
347
+ eventType: "output_delta",
348
+ payloadKey: "provider_message",
349
+ });
350
+ }
351
+ events.push({
352
+ sequence: events.length + 1,
353
+ adapterEventId: `bridge-cli-${terminalEventType}`,
354
+ eventType: terminalEventType,
355
+ payloadKey: terminalEventType,
356
+ });
357
+ return events;
358
+ }
359
+ function callbackEnvelopeFor(packet, eventType, finalMessage) {
360
+ return {
361
+ callbackId: ids.callbackId,
362
+ chatRunId: packet.chatRunId,
363
+ conversationId: packet.conversationId,
364
+ turnId: packet.turnId,
365
+ leaseId: packet.leaseId,
366
+ fencingToken: packet.fencingToken,
367
+ runnerId: ids.runnerId,
368
+ runnerInstanceId: packet.runnerInstanceId,
369
+ sequence: eventType === "output_completed" ? 3 : 2,
370
+ eventType,
371
+ redactionStatus: "redacted",
372
+ providerThreadId: packet.providerThreadId,
373
+ payload: {
374
+ code: eventType,
375
+ text: finalMessage ?? "",
376
+ provider: packet.providerKind,
377
+ model: packet.model,
378
+ },
379
+ occurredAt: "2026-09-26T12:00:00.000Z",
380
+ protocolVersion: bridgeChatProtocolVersion,
381
+ };
382
+ }
383
+ function providerStreamFor(providerKind, providerThreadId, scenario) {
384
+ if (providerKind === "cursor") {
385
+ const stdoutLines = [
386
+ JSON.stringify({ type: "system", subtype: "init", session_id: providerThreadId }),
387
+ ...(scenario.finalMessage
388
+ ? [JSON.stringify({
389
+ type: "assistant",
390
+ message: { role: "assistant", content: [{ type: "text", text: scenario.finalMessage }] },
391
+ })]
392
+ : []),
393
+ JSON.stringify({ type: "result", subtype: "success", is_error: false, result: scenario.finalMessage ?? "" }),
394
+ ];
395
+ return {
396
+ stdoutLines,
397
+ expectedEventTypes: scenario.finalMessage
398
+ ? ["provider_thread_started", "provider_message"]
399
+ : ["provider_thread_started"],
400
+ expectedFinalMessage: scenario.finalMessage,
401
+ };
402
+ }
403
+ const stdoutLines = [
404
+ JSON.stringify({ type: "thread.started", thread_id: providerThreadId }),
405
+ ...(scenario.finalMessage
406
+ ? [JSON.stringify({ type: "item.completed", item: { type: "agent_message", text: scenario.finalMessage } })]
407
+ : []),
408
+ JSON.stringify({ type: "turn.completed" }),
409
+ ];
410
+ return {
411
+ stdoutLines,
412
+ expectedEventTypes: scenario.finalMessage
413
+ ? ["provider_thread_started", "provider_message", "provider_turn_completed"]
414
+ : ["provider_thread_started", "provider_turn_completed"],
415
+ expectedFinalMessage: scenario.finalMessage,
416
+ };
417
+ }
418
+ function attachmentHandoff() {
419
+ return {
420
+ turnId: ids.turnId,
421
+ attachmentId: ids.attachmentId,
422
+ tempFileToken: "opaque-temp-file-token",
423
+ mimeType: "text/plain",
424
+ sizeBytes: 123,
425
+ sha256: "a".repeat(64),
426
+ fileNameDisplay: "notes.txt",
427
+ expiresAt: deterministicExpiresAt,
428
+ status: "available",
429
+ };
430
+ }
431
+ function actionBrokerGrant() {
432
+ return {
433
+ grantId: ids.grantId,
434
+ turnId: ids.turnId,
435
+ leaseId: ids.leaseId,
436
+ fencingToken: ids.fencingToken,
437
+ allowedScopes: ["action_broker_grants", "text"],
438
+ nonce: "opaque-grant-nonce",
439
+ expiresAt: deterministicExpiresAt,
440
+ redactionStatus: "not_applicable",
441
+ };
442
+ }
443
+ function packetRecord(packet) {
444
+ return {
445
+ chatRunId: packet.chatRunId,
446
+ conversationId: packet.conversationId,
447
+ turnId: packet.turnId,
448
+ leaseId: packet.leaseId,
449
+ fencingToken: packet.fencingToken,
450
+ runnerInstanceId: packet.runnerInstanceId,
451
+ providerKind: packet.providerKind,
452
+ model: packet.model,
453
+ messages: packet.messages,
454
+ contextRefs: packet.contextRefs,
455
+ idempotencyKey: packet.idempotencyKey,
456
+ providerThreadId: packet.providerThreadId,
457
+ protocolVersion: packet.protocolVersion,
458
+ requestedCapabilities: packet.requestedCapabilities,
459
+ attachmentHandoffs: packet.attachmentHandoffs,
460
+ actionBrokerGrants: packet.actionBrokerGrants,
461
+ };
462
+ }
@@ -0,0 +1,16 @@
1
+ import type { RunOnceDispatchPacket } from "../session.types.js";
2
+ export declare const ciRepairProviderOnlySpecs: readonly ["**/bridge-dispatch.spec.ts", "**/develop-agent-run.spec.ts", "**/runner-availability.spec.ts"];
3
+ export declare const ciRepairLocalPreflightCommands: readonly CiRepairLocalPreflightCommand[];
4
+ export interface CiRepairLocalPreflightCommand {
5
+ readonly id: string;
6
+ readonly cwd: string;
7
+ readonly command: readonly string[];
8
+ readonly coverage: string;
9
+ }
10
+ export interface CiRepairReadinessResult {
11
+ readonly path: string;
12
+ readonly environment: Readonly<Record<string, string>>;
13
+ readonly manifest: Readonly<Record<string, unknown>>;
14
+ }
15
+ export declare function writeCiRepairReadinessManifest(dispatch: RunOnceDispatchPacket, worktreePath: string, specPath: string, runtimeEnvironment: Readonly<Record<string, string>> | undefined): Promise<CiRepairReadinessResult>;
16
+ export declare function assertCiRepairPreflightContract(providerOnlySpecs: readonly string[], localPreflightCommands: readonly CiRepairLocalPreflightCommand[]): void;
@@ -0,0 +1,110 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { createHash } from "node:crypto";
4
+ export const ciRepairProviderOnlySpecs = [
5
+ "**/bridge-dispatch.spec.ts",
6
+ "**/develop-agent-run.spec.ts",
7
+ "**/runner-availability.spec.ts",
8
+ ];
9
+ export const ciRepairLocalPreflightCommands = [];
10
+ export async function writeCiRepairReadinessManifest(dispatch, worktreePath, specPath, runtimeEnvironment) {
11
+ assertCiRepairPreflightContract(ciRepairProviderOnlySpecs, ciRepairLocalPreflightCommands);
12
+ const metadataRoot = path.dirname(specPath);
13
+ const manifestPath = path.join(metadataRoot, "ci-repair.readiness.json");
14
+ const workflowPath = path.join(worktreePath, ".github", "workflows", "ci.yml");
15
+ const browserReady = runtimeEnvironment?.FORGE_PLAYWRIGHT_BROWSER_READY === "true";
16
+ const providerOnlySpecsJson = JSON.stringify(ciRepairProviderOnlySpecs);
17
+ const apiUrl = runtimeEnvironment?.FORGE_E2E_API_URL ?? runtimeEnvironment?.FORGE_API_URL ?? null;
18
+ const webUrl = runtimeEnvironment?.FORGE_E2E_WEB_URL
19
+ ?? runtimeEnvironment?.FORGE_WEB_URL
20
+ ?? runtimeEnvironment?.FORGE_PLAYWRIGHT_BASE_URL
21
+ ?? null;
22
+ const environment = {
23
+ ...(runtimeEnvironment ?? {}),
24
+ ...(apiUrl ? { FORGE_E2E_API_URL: apiUrl } : {}),
25
+ ...(webUrl ? { FORGE_E2E_WEB_URL: webUrl } : {}),
26
+ FORGE_CI_REPAIR_READINESS_PATH: manifestPath,
27
+ FORGE_CI_REPAIR_HANDOFF_PATH: path.join(metadataRoot, "artifacts", "ci-repair.handoff.json"),
28
+ FORGE_CI_REPAIR_PROVIDER_ONLY_SPECS: providerOnlySpecsJson,
29
+ };
30
+ const manifest = {
31
+ schema_version: 1,
32
+ generated_by: "forge-bridge",
33
+ work_item_id: dispatch.workItem.id,
34
+ session_id: dispatch.session.id,
35
+ spec: {
36
+ path: relativePath(worktreePath, specPath),
37
+ ready: await isFile(specPath),
38
+ },
39
+ handoff: {
40
+ path: relativePath(worktreePath, environment.FORGE_CI_REPAIR_HANDOFF_PATH),
41
+ completion_tool: "forge.complete_ci_repair",
42
+ required_before_commit_or_push: true,
43
+ },
44
+ pull_request: {
45
+ provider: dispatch.pullRequest?.provider ?? "unknown",
46
+ number: dispatch.pullRequest?.number ?? null,
47
+ url: dispatch.pullRequest?.url ?? null,
48
+ source_branch: dispatch.pullRequest?.sourceBranch ?? dispatch.cycleRun.baseBranch,
49
+ target_branch: dispatch.pullRequest?.targetBranch ?? dispatch.cycleRun.requestedBase,
50
+ check_state: dispatch.pullRequest?.checkState ?? "unknown",
51
+ required_checks_passed: dispatch.pullRequest?.requiredChecksPassed ?? 0,
52
+ required_checks_total: dispatch.pullRequest?.requiredChecksTotal ?? 0,
53
+ failed_job_discovery: "Inspect provider check runs and record exact job/step in the completion payload.",
54
+ },
55
+ workflow: {
56
+ path: relativePath(worktreePath, workflowPath),
57
+ ready: await isFile(workflowPath),
58
+ requirement: "Record the failed step and every earlier guard/drift step in workflow_validation.",
59
+ },
60
+ runtime: {
61
+ mode: runtimeEnvironment?.FORGE_RUNTIME_MODE ?? "unknown",
62
+ application_runtime_ready: Boolean(apiUrl || webUrl),
63
+ api_url: apiUrl,
64
+ web_url: webUrl,
65
+ playwright_config: runtimeEnvironment?.FORGE_PLAYWRIGHT_CONFIG ?? null,
66
+ playwright_browser_cache: runtimeEnvironment?.PLAYWRIGHT_BROWSERS_PATH ?? null,
67
+ playwright_browser_ready: browserReady,
68
+ playwright_browser_install_command: browserReady
69
+ ? null
70
+ : runtimeEnvironment?.FORGE_PLAYWRIGHT_BROWSER_INSTALL_COMMAND ?? "npx playwright install chromium",
71
+ attempt_database_schema: runtimeEnvironment?.FORGE_ATTEMPT_DATABASE_SCHEMA ?? null,
72
+ attempt_database_readiness_path: runtimeEnvironment?.FORGE_ATTEMPT_DATABASE_READINESS_PATH ?? null,
73
+ },
74
+ local_equivalence: {
75
+ default: "supported",
76
+ nested_bridge: "provider_only",
77
+ provider_only_specs: ciRepairProviderOnlySpecs,
78
+ provider_only_specs_fingerprint: `sha256:${createHash("sha256").update(providerOnlySpecsJson).digest("hex")}`,
79
+ local_preflight_commands: ciRepairLocalPreflightCommands,
80
+ reason: "A managed Forge attempt disables its hosted reconciler and cannot exercise specs that require the live Bridge/runner control plane. Those specs remain authoritative in provider CI; attempt-local unit, contract, API, and browser coverage remains supported.",
81
+ policy: "Run every listed local_preflight_command. Treat every provider_only_specs pattern as unavailable in the managed attempt, do not override its exclusion or weaken provider CI, and record the provider check that supplies that proof in workflow_validation.",
82
+ },
83
+ };
84
+ await fs.mkdir(metadataRoot, { recursive: true });
85
+ await fs.writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
86
+ return { path: manifestPath, environment, manifest };
87
+ }
88
+ export function assertCiRepairPreflightContract(providerOnlySpecs, localPreflightCommands) {
89
+ const providerOnlyFileNames = new Set(providerOnlySpecs.map(fileName));
90
+ for (const preflight of localPreflightCommands) {
91
+ const conflictingArgument = preflight.command.find(argument => providerOnlyFileNames.has(fileName(argument)));
92
+ if (conflictingArgument) {
93
+ throw new Error(`ci_repair_readiness_invalid: local preflight '${preflight.id}' references provider-only spec '${conflictingArgument}'.`);
94
+ }
95
+ }
96
+ }
97
+ async function isFile(candidate) {
98
+ try {
99
+ return (await fs.stat(candidate)).isFile();
100
+ }
101
+ catch {
102
+ return false;
103
+ }
104
+ }
105
+ function relativePath(worktreePath, candidate) {
106
+ return path.relative(worktreePath, candidate).replaceAll(path.sep, "/");
107
+ }
108
+ function fileName(candidate) {
109
+ return path.posix.basename(candidate.replaceAll("\\", "/"));
110
+ }