@loucompanion/forge-bridge 0.1.1-dev.8dcbc6245e51 → 0.1.1-dev.9acab970e5d1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bridge/bridge.service.js +74 -9
- package/dist/bridge/bridge.types.d.ts +15 -0
- package/dist/cli/cli.service.d.ts +27 -2
- package/dist/cli/cli.service.js +406 -16
- package/dist/cli/local-config.d.ts +3 -0
- package/dist/cli/local-config.js +26 -3
- package/dist/session/index.d.ts +2 -0
- package/dist/session/index.js +1 -0
- package/dist/session/internals.d.ts +5 -3
- package/dist/session/internals.js +2 -1
- package/dist/session/phase-completion.d.ts +111 -0
- package/dist/session/phase-completion.js +2350 -0
- package/dist/session/provider-cli/index.d.ts +2 -2
- package/dist/session/provider-cli/index.js +1 -1
- package/dist/session/provider-cli/provider-cli.base.d.ts +2 -2
- package/dist/session/provider-cli/provider-cli.service.d.ts +48 -3
- package/dist/session/provider-cli/provider-cli.service.js +1870 -41
- package/dist/session/provider-cli/provider-cli.types.d.ts +2 -0
- package/dist/session/provider-cli/provider-usage.d.ts +25 -0
- package/dist/session/provider-cli/provider-usage.js +64 -0
- package/dist/session/qa-sidecar-validation.d.ts +3 -0
- package/dist/session/qa-sidecar-validation.js +44 -0
- package/dist/session/session.service.js +25 -11
- package/dist/session/session.types.d.ts +55 -0
- package/dist/session/session.types.js +119 -2
- package/dist/shared/cursor-agent/cursor-agent.launch.d.ts +9 -0
- package/dist/shared/cursor-agent/cursor-agent.launch.js +66 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worktree/artifact-injector.d.ts +2 -1
- package/dist/worktree/artifact-injector.js +38 -9
- package/dist/worktree/worktree.service.d.ts +2 -0
- package/dist/worktree/worktree.service.js +111 -5
- package/dist/worktree/worktree.types.d.ts +2 -0
- package/package.json +1 -1
|
@@ -87,11 +87,20 @@ export class ForgeBridgeService {
|
|
|
87
87
|
const normalized = this.normalizeDispatch(dispatch);
|
|
88
88
|
const result = await this.sessions.runOnce(normalized, {
|
|
89
89
|
emit: async (event) => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
90
|
+
try {
|
|
91
|
+
await this.invokeAck("DispatchEvent", {
|
|
92
|
+
leaseId,
|
|
93
|
+
fencingToken,
|
|
94
|
+
event: redactSecrets(event, redactionSecrets)
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
if (isDispatchNoLongerPending(error)) {
|
|
99
|
+
controller.abort(error instanceof Error ? error.message : "Dispatch is no longer pending.");
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
95
104
|
}
|
|
96
105
|
}, controller.signal);
|
|
97
106
|
await this.sendResult(leaseId, fencingToken, redactSecrets(result, redactionSecrets));
|
|
@@ -123,6 +132,7 @@ export class ForgeBridgeService {
|
|
|
123
132
|
const mapping = findRepoMapping(dispatch, this.config.repoMappings);
|
|
124
133
|
const localPath = mapping?.localPath?.trim();
|
|
125
134
|
const repoRoot = localPath ? path.dirname(path.resolve(localPath)) : this.config.defaultRepoRoot;
|
|
135
|
+
const qaLaunchTarget = normalizeQaAppLaunchTarget(mapping?.qaAppLaunchTarget) ?? dispatch.qaBrowser?.launchTarget ?? null;
|
|
126
136
|
return {
|
|
127
137
|
...dispatch,
|
|
128
138
|
repo: {
|
|
@@ -133,7 +143,13 @@ export class ForgeBridgeService {
|
|
|
133
143
|
serverLocal: {
|
|
134
144
|
repoRoot,
|
|
135
145
|
cleanupWorktrees: this.config.cleanupWorktrees
|
|
136
|
-
}
|
|
146
|
+
},
|
|
147
|
+
qaBrowser: dispatch.qaBrowser
|
|
148
|
+
? {
|
|
149
|
+
...dispatch.qaBrowser,
|
|
150
|
+
launchTarget: qaLaunchTarget
|
|
151
|
+
}
|
|
152
|
+
: dispatch.qaBrowser
|
|
137
153
|
};
|
|
138
154
|
}
|
|
139
155
|
async sendResult(leaseId, fencingToken, result) {
|
|
@@ -142,7 +158,15 @@ export class ForgeBridgeService {
|
|
|
142
158
|
fencingToken,
|
|
143
159
|
result
|
|
144
160
|
};
|
|
145
|
-
|
|
161
|
+
try {
|
|
162
|
+
await this.invokeAck("DispatchResult", payload);
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
if (isDispatchNoLongerPending(error)) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
146
170
|
}
|
|
147
171
|
startHeartbeat() {
|
|
148
172
|
this.stopHeartbeat();
|
|
@@ -176,7 +200,10 @@ export class ForgeBridgeService {
|
|
|
176
200
|
repoMappings: this.config.repoMappings,
|
|
177
201
|
os: this.config.os,
|
|
178
202
|
sandboxProfiles: this.config.sandboxProfiles,
|
|
179
|
-
supportsApiSecretGrant: this.config.supportsApiSecretGrant
|
|
203
|
+
supportsApiSecretGrant: this.config.supportsApiSecretGrant,
|
|
204
|
+
supportsManagedWorktrees: this.config.supportsManagedWorktrees,
|
|
205
|
+
supportsManagedForgeArtifacts: this.config.supportsManagedForgeArtifacts,
|
|
206
|
+
supportsRunnerAuthoredPhaseArtifacts: this.config.supportsRunnerAuthoredPhaseArtifacts
|
|
180
207
|
};
|
|
181
208
|
}
|
|
182
209
|
async invokeAck(methodName, payload) {
|
|
@@ -186,7 +213,7 @@ export class ForgeBridgeService {
|
|
|
186
213
|
}
|
|
187
214
|
const ack = await connection.invoke(methodName, payload);
|
|
188
215
|
if (!ack.accepted) {
|
|
189
|
-
throw new
|
|
216
|
+
throw new BridgeCallbackRejectedError(ack.code ?? null, ack.message ?? ack.code ?? `${methodName} callback was rejected.`);
|
|
190
217
|
}
|
|
191
218
|
return ack;
|
|
192
219
|
}
|
|
@@ -204,6 +231,20 @@ export class ForgeBridgeService {
|
|
|
204
231
|
}
|
|
205
232
|
}
|
|
206
233
|
}
|
|
234
|
+
class BridgeCallbackRejectedError extends Error {
|
|
235
|
+
code;
|
|
236
|
+
constructor(code, message) {
|
|
237
|
+
super(message);
|
|
238
|
+
this.code = code;
|
|
239
|
+
this.name = "BridgeCallbackRejectedError";
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
function isDispatchNoLongerPending(error) {
|
|
243
|
+
if (error instanceof BridgeCallbackRejectedError) {
|
|
244
|
+
return error.code === "bridge.dispatch_not_pending" || error.code === "bridge.stale_dispatch";
|
|
245
|
+
}
|
|
246
|
+
return error instanceof Error && error.message === "Dispatch is no longer pending.";
|
|
247
|
+
}
|
|
207
248
|
export class SignalRBridgeConnectionFactory {
|
|
208
249
|
create(config) {
|
|
209
250
|
return new SignalRBridgeConnection(config);
|
|
@@ -270,6 +311,9 @@ export function defaultBridgeServiceConfig(overrides = {}) {
|
|
|
270
311
|
os: process.platform,
|
|
271
312
|
sandboxProfiles: ["default"],
|
|
272
313
|
supportsApiSecretGrant: true,
|
|
314
|
+
supportsManagedWorktrees: true,
|
|
315
|
+
supportsManagedForgeArtifacts: true,
|
|
316
|
+
supportsRunnerAuthoredPhaseArtifacts: true,
|
|
273
317
|
version: process.env.FORGE_BRIDGE_VERSION ?? forgeBridgeVersion,
|
|
274
318
|
protocolVersion: 1,
|
|
275
319
|
minServerVersion: null,
|
|
@@ -317,6 +361,27 @@ function findRepoMapping(dispatch, mappings) {
|
|
|
317
361
|
(!!mapping.remoteUrl?.trim() && equalsIgnoreCase(mapping.remoteUrl, dispatch.repo.remoteUrl)));
|
|
318
362
|
});
|
|
319
363
|
}
|
|
364
|
+
function normalizeQaAppLaunchTarget(target) {
|
|
365
|
+
if (!target) {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
const routes = [...new Set((target.routes ?? []).map((route) => route.trim()).filter(Boolean))];
|
|
369
|
+
const normalized = {
|
|
370
|
+
url: cleanString(target.url),
|
|
371
|
+
command: cleanString(target.command),
|
|
372
|
+
working_directory: cleanString(target.working_directory),
|
|
373
|
+
ready_url: cleanString(target.ready_url),
|
|
374
|
+
routes,
|
|
375
|
+
notes: cleanString(target.notes)
|
|
376
|
+
};
|
|
377
|
+
return normalized.url || normalized.command || normalized.ready_url || routes.length > 0
|
|
378
|
+
? normalized
|
|
379
|
+
: null;
|
|
380
|
+
}
|
|
381
|
+
function cleanString(value) {
|
|
382
|
+
const clean = value?.trim();
|
|
383
|
+
return clean ? clean : null;
|
|
384
|
+
}
|
|
320
385
|
function equalsIgnoreCase(left, right) {
|
|
321
386
|
return !!left?.trim() && !!right?.trim() && left.trim().toLowerCase() === right.trim().toLowerCase();
|
|
322
387
|
}
|
|
@@ -13,6 +13,9 @@ export interface BridgeServiceConfig {
|
|
|
13
13
|
readonly os: string;
|
|
14
14
|
readonly sandboxProfiles: readonly string[];
|
|
15
15
|
readonly supportsApiSecretGrant: boolean;
|
|
16
|
+
readonly supportsManagedWorktrees: boolean;
|
|
17
|
+
readonly supportsManagedForgeArtifacts: boolean;
|
|
18
|
+
readonly supportsRunnerAuthoredPhaseArtifacts: boolean;
|
|
16
19
|
readonly version: string;
|
|
17
20
|
readonly protocolVersion: number;
|
|
18
21
|
readonly minServerVersion?: string | null;
|
|
@@ -24,6 +27,15 @@ export interface BridgeRepoMapping {
|
|
|
24
27
|
readonly name?: string | null;
|
|
25
28
|
readonly remoteUrl?: string | null;
|
|
26
29
|
readonly localPath?: string | null;
|
|
30
|
+
readonly qaAppLaunchTarget?: QaAppLaunchTarget | null;
|
|
31
|
+
}
|
|
32
|
+
export interface QaAppLaunchTarget {
|
|
33
|
+
readonly url?: string | null;
|
|
34
|
+
readonly command?: string | null;
|
|
35
|
+
readonly working_directory?: string | null;
|
|
36
|
+
readonly ready_url?: string | null;
|
|
37
|
+
readonly routes?: readonly string[] | null;
|
|
38
|
+
readonly notes?: string | null;
|
|
27
39
|
}
|
|
28
40
|
export interface BridgeProviderStatus {
|
|
29
41
|
readonly signedIn?: boolean | null;
|
|
@@ -40,6 +52,9 @@ export interface BridgeCapabilities {
|
|
|
40
52
|
readonly os?: string | null;
|
|
41
53
|
readonly sandboxProfiles?: readonly string[] | null;
|
|
42
54
|
readonly supportsApiSecretGrant?: boolean | null;
|
|
55
|
+
readonly supportsManagedWorktrees?: boolean | null;
|
|
56
|
+
readonly supportsManagedForgeArtifacts?: boolean | null;
|
|
57
|
+
readonly supportsRunnerAuthoredPhaseArtifacts?: boolean | null;
|
|
43
58
|
}
|
|
44
59
|
export interface BridgeHelloRequest {
|
|
45
60
|
readonly version: string;
|
|
@@ -5,7 +5,8 @@ import type { CliIo, CliService } from "./cli.base.js";
|
|
|
5
5
|
export declare class ForgeBridgeCliService implements CliService {
|
|
6
6
|
private readonly sessions;
|
|
7
7
|
private readonly bridgeFactory;
|
|
8
|
-
|
|
8
|
+
private readonly pairRunner;
|
|
9
|
+
constructor(sessions?: SessionService, bridgeFactory?: (config: BridgeServiceConfig) => BridgeService, pairRunner?: PairRunnerClient);
|
|
9
10
|
run(argv: readonly string[], io?: CliIo): Promise<number>;
|
|
10
11
|
}
|
|
11
12
|
export declare function parseArgs(argv: readonly string[]): {
|
|
@@ -13,11 +14,18 @@ export declare function parseArgs(argv: readonly string[]): {
|
|
|
13
14
|
readonly command: "run-once";
|
|
14
15
|
readonly dispatchPath: string;
|
|
15
16
|
readonly resultPath: string;
|
|
17
|
+
} | {
|
|
18
|
+
readonly ok: true;
|
|
19
|
+
readonly command: "mcp";
|
|
20
|
+
readonly argv: readonly string[];
|
|
16
21
|
} | {
|
|
17
22
|
readonly ok: true;
|
|
18
23
|
readonly command: "connect";
|
|
19
24
|
readonly config: BridgeServiceConfig;
|
|
20
|
-
} | {
|
|
25
|
+
} | ({
|
|
26
|
+
readonly ok: true;
|
|
27
|
+
readonly command: "pair";
|
|
28
|
+
} & PairArgs) | {
|
|
21
29
|
readonly ok: true;
|
|
22
30
|
readonly command: "add-repo";
|
|
23
31
|
readonly label: string;
|
|
@@ -41,5 +49,22 @@ export declare function parseArgs(argv: readonly string[]): {
|
|
|
41
49
|
readonly ok: false;
|
|
42
50
|
readonly error: string;
|
|
43
51
|
};
|
|
52
|
+
interface PairArgs {
|
|
53
|
+
readonly serverUrl: string;
|
|
54
|
+
readonly code?: string;
|
|
55
|
+
readonly name: string;
|
|
56
|
+
readonly fingerprint: string;
|
|
57
|
+
readonly repoRoot?: string;
|
|
58
|
+
readonly cleanupWorktrees: boolean;
|
|
59
|
+
readonly cliProviders: readonly string[];
|
|
60
|
+
readonly projectLabels: readonly string[];
|
|
61
|
+
}
|
|
62
|
+
interface PairRunnerClaim {
|
|
63
|
+
readonly runnerId: string;
|
|
64
|
+
readonly deviceToken: string;
|
|
65
|
+
}
|
|
66
|
+
type PairRunnerClient = (args: PairArgs) => Promise<PairRunnerClaim>;
|
|
67
|
+
export declare function parseCodexModelCatalog(raw: string): string[];
|
|
68
|
+
export declare function parseCursorModelList(raw: string): string[];
|
|
44
69
|
type CleanupMode = "stale" | "merged" | "all";
|
|
45
70
|
export {};
|