@loucompanion/forge-bridge 0.1.3-dev.09aeeb7ccadf → 0.1.3-dev.1fe428dd78ab

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 (51) hide show
  1. package/README.md +44 -0
  2. package/dist/bridge/bridge.base.d.ts +5 -1
  3. package/dist/bridge/bridge.service.d.ts +36 -2
  4. package/dist/bridge/bridge.service.js +564 -14
  5. package/dist/bridge/bridge.types.d.ts +110 -1
  6. package/dist/cli/cli.help.js +12 -0
  7. package/dist/cli/cli.service.d.ts +12 -0
  8. package/dist/cli/cli.service.js +168 -1
  9. package/dist/sandbox/command-runner.d.ts +4 -0
  10. package/dist/sandbox/command-runner.js +47 -0
  11. package/dist/sandbox/contract.d.ts +5 -0
  12. package/dist/sandbox/contract.js +276 -0
  13. package/dist/sandbox/event-budget.d.ts +11 -0
  14. package/dist/sandbox/event-budget.js +27 -0
  15. package/dist/sandbox/image-policy.d.ts +33 -0
  16. package/dist/sandbox/image-policy.js +245 -0
  17. package/dist/sandbox/index.d.ts +5 -0
  18. package/dist/sandbox/index.js +5 -0
  19. package/dist/sandbox/lease-watchdog.d.ts +18 -0
  20. package/dist/sandbox/lease-watchdog.js +67 -0
  21. package/dist/sandbox/preflight.d.ts +36 -0
  22. package/dist/sandbox/preflight.js +239 -0
  23. package/dist/sandbox/process.d.ts +20 -0
  24. package/dist/sandbox/process.js +124 -0
  25. package/dist/sandbox/provider-auth/codex.d.ts +26 -0
  26. package/dist/sandbox/provider-auth/codex.js +212 -0
  27. package/dist/sandbox/repository-lock.d.ts +5 -0
  28. package/dist/sandbox/repository-lock.js +83 -0
  29. package/dist/sandbox/runtime.d.ts +218 -0
  30. package/dist/sandbox/runtime.js +1672 -0
  31. package/dist/sandbox/sandbox.types.d.ts +83 -0
  32. package/dist/sandbox/sandbox.types.js +1 -0
  33. package/dist/sandbox/worker-supervisor.d.ts +13 -0
  34. package/dist/sandbox/worker-supervisor.js +36 -0
  35. package/dist/sandbox/worker.d.ts +1 -0
  36. package/dist/sandbox/worker.js +228 -0
  37. package/dist/sandbox/workspace.service.d.ts +12 -0
  38. package/dist/sandbox/workspace.service.js +49 -0
  39. package/dist/session/provider-cli/provider-cli.base.d.ts +1 -0
  40. package/dist/session/provider-cli/provider-cli.deterministic.d.ts +2 -0
  41. package/dist/session/provider-cli/provider-cli.deterministic.js +20 -9
  42. package/dist/session/provider-cli/provider-cli.prompts.d.ts +2 -0
  43. package/dist/session/provider-cli/provider-cli.prompts.js +31 -0
  44. package/dist/session/provider-cli/provider-cli.service.d.ts +3 -0
  45. package/dist/session/provider-cli/provider-cli.service.js +31 -13
  46. package/dist/session/session.service.js +14 -7
  47. package/dist/session/session.types.d.ts +41 -1
  48. package/dist/session/session.types.js +119 -2
  49. package/dist/version.d.ts +1 -1
  50. package/dist/version.js +1 -1
  51. package/package.json +4 -2
@@ -5,7 +5,7 @@ import { buildSpecBody, selectLaneCommand } from "../../worktree/artifact-inject
5
5
  import { completionPhaseFromDispatch, prepareCompletionToolRuntime, readCompletionArtifact, usesDebugCycleCompletion, usesDevelopCycleCompletion } from "../phase-completion.js";
6
6
  import { cleanupCompletionTools, commitWorktreeChanges, completionPhaseFromArtifact, emitArchitectStructuredEvents, emitCompletionArtifactRecorded, emitDecomposeGateArtifacts, emitDraftGateArtifacts, emitPhaseCompletionEvent, emitPhaseGateEvents, emitQaArtifactRecorded, emitQaStructuredEvents, enforceQaBrowserLaunchTargetGate, LiveArchitectArtifactEmitter, LiveCompletionArtifactEmitter, LiveQaArtifactEmitter, readCompletionArtifactsForRun, readQaCompletionArtifactBundle, summarizeStderr, waitForCompletionArtifact } from "./provider-cli.artifacts.js";
7
7
  import { DeterministicProviderCliService } from "./provider-cli.deterministic.js";
8
- import { buildArchitectPrompt, buildConflictResolvePrompt, buildDebugCyclePrompt, buildDevelopCyclePrompt, buildDraftPrompt, buildDraftSpec, buildImplementationPrompt, buildProviderCliCommand, durableDraftInput, buildPullRequestCommentsPrompt, buildQaPrompt, formatProviderCliCommandForCheckpoint, isDecomposeDraftDispatch, isPullRequestCommentsDispatch } from "./provider-cli.prompts.js";
8
+ import { buildArchitectPrompt, buildConflictResolvePrompt, buildDebugCyclePrompt, buildDevelopCyclePrompt, buildDraftPrompt, buildDraftSpec, buildImplementationPrompt, buildProviderCliCommand, durableDraftInput, buildPullRequestCheckRepairPrompt, buildPullRequestCommentsPrompt, buildQaPrompt, formatProviderCliCommandForCheckpoint, isDecomposeDraftDispatch, isPullRequestCheckRepairDispatch, isPullRequestCommentsDispatch } from "./provider-cli.prompts.js";
9
9
  import { StreamingProviderProcessRunner } from "./provider-cli.process.js";
10
10
  import { emitProviderUsageEvent, providerProcessEnv } from "./provider-cli.runtime.js";
11
11
  import { clip, createProviderOutputState, parseJsonLine } from "./provider-output-state.js";
@@ -70,6 +70,11 @@ export class RoutingProviderCliService {
70
70
  ? await this.deterministicProvider.runArchitect(context)
71
71
  : await this.realProvider.runArchitect(context);
72
72
  }
73
+ async runCiRepair(context) {
74
+ return isFakeWorkerModel(context.dispatch.execution.model)
75
+ ? await this.deterministicProvider.runCiRepair(context)
76
+ : await this.realProvider.runCiRepair(context);
77
+ }
73
78
  async runConflictResolve(context) {
74
79
  return isFakeWorkerModel(context.dispatch.execution.model)
75
80
  ? await this.deterministicProvider.runConflictResolve(context)
@@ -566,19 +571,28 @@ export class ProcessBackedProviderCliService {
566
571
  artifacts: [qaArtifact]
567
572
  };
568
573
  }
574
+ async runCiRepair(context) {
575
+ return await this.runPullRequestRepair(context, "ci_repair");
576
+ }
569
577
  async runConflictResolve(context) {
578
+ return await this.runPullRequestRepair(context, "conflict_resolve");
579
+ }
580
+ async runPullRequestRepair(context, route) {
570
581
  const { dispatch, worktree } = context;
571
- const addressComments = isPullRequestCommentsDispatch(dispatch);
582
+ const repairChecks = route === "ci_repair" || isPullRequestCheckRepairDispatch(dispatch);
583
+ const addressComments = !repairChecks && isPullRequestCommentsDispatch(dispatch);
572
584
  const command = buildProviderCliCommand(dispatch, {
573
585
  worktreePath: worktree.worktreePath,
574
- prompt: addressComments
575
- ? buildPullRequestCommentsPrompt(dispatch, worktree.branchName)
576
- : buildConflictResolvePrompt(dispatch, worktree.branchName)
586
+ prompt: repairChecks
587
+ ? buildPullRequestCheckRepairPrompt(dispatch, worktree.branchName)
588
+ : addressComments
589
+ ? buildPullRequestCommentsPrompt(dispatch, worktree.branchName)
590
+ : buildConflictResolvePrompt(dispatch, worktree.branchName)
577
591
  });
578
592
  await context.emit({
579
593
  role: "runner",
580
594
  kind: "checkpoint",
581
- content: `Starting provider CLI ${addressComments ? "PR comment address" : "conflict resolve"}: ${formatProviderCliCommandForCheckpoint(command)} in ${worktree.worktreePath}`,
595
+ content: `Starting provider CLI ${repairChecks ? "CI repair" : addressComments ? "PR comment address" : "conflict resolve"}: ${formatProviderCliCommandForCheckpoint(command)} in ${worktree.worktreePath}`,
582
596
  eventType: "provider_cli_started"
583
597
  });
584
598
  const outputState = createProviderOutputState(dispatch.execution.provider);
@@ -604,15 +618,19 @@ export class ProcessBackedProviderCliService {
604
618
  await context.emit({
605
619
  role: "assistant",
606
620
  kind: "message",
607
- content: outputState.finalMessage || (addressComments
608
- ? `${dispatch.execution.provider} CLI addressed pull request comments for ${worktree.branchName}.`
609
- : `${dispatch.execution.provider} CLI resolved merge conflicts for ${worktree.branchName}.`),
610
- eventType: addressComments ? "pr_comments_complete" : "conflict_resolve_complete"
621
+ content: outputState.finalMessage || (repairChecks
622
+ ? `${dispatch.execution.provider} CLI repaired pull request checks for ${worktree.branchName}.`
623
+ : addressComments
624
+ ? `${dispatch.execution.provider} CLI addressed pull request comments for ${worktree.branchName}.`
625
+ : `${dispatch.execution.provider} CLI resolved merge conflicts for ${worktree.branchName}.`),
626
+ eventType: repairChecks ? "pr_checks_complete" : addressComments ? "pr_comments_complete" : "conflict_resolve_complete"
611
627
  });
612
628
  return {
613
- summary: addressComments
614
- ? `${dispatch.execution.provider} CLI addressed PR comments on ${worktree.branchName} (${committed.commitSha.slice(0, 12)}).`
615
- : `${dispatch.execution.provider} CLI resolved conflicts on ${worktree.branchName} (${committed.commitSha.slice(0, 12)}).`
629
+ summary: repairChecks
630
+ ? `${dispatch.execution.provider} CLI repaired PR checks on ${worktree.branchName} (${committed.commitSha.slice(0, 12)}).`
631
+ : addressComments
632
+ ? `${dispatch.execution.provider} CLI addressed PR comments on ${worktree.branchName} (${committed.commitSha.slice(0, 12)}).`
633
+ : `${dispatch.execution.provider} CLI resolved conflicts on ${worktree.branchName} (${committed.commitSha.slice(0, 12)}).`
616
634
  };
617
635
  }
618
636
  }
@@ -1,10 +1,13 @@
1
1
  import { redactSecrets } from "../shared/redaction/redaction.js";
2
2
  import { RoutingProviderCliService } from "./provider-cli/provider-cli.service.js";
3
3
  import { GitWorktreeService } from "../worktree/worktree.service.js";
4
+ import { SandboxWorkspaceService } from "../sandbox/workspace.service.js";
4
5
  export class BridgeSessionService {
5
6
  worktrees;
6
7
  providerCli;
7
- constructor(worktrees = new GitWorktreeService(), providerCli = new RoutingProviderCliService()) {
8
+ constructor(worktrees = process.env.FORGE_SANDBOX_ID
9
+ ? new SandboxWorkspaceService()
10
+ : new GitWorktreeService(), providerCli = new RoutingProviderCliService()) {
8
11
  this.worktrees = worktrees;
9
12
  this.providerCli = providerCli;
10
13
  }
@@ -75,10 +78,12 @@ export class BridgeSessionService {
75
78
  }, redactionSecrets);
76
79
  }
77
80
  throwIfAborted(signal);
78
- const lane = dispatch.execution.lane.toLowerCase();
79
- const role = dispatch.execution.role.toLowerCase();
81
+ const lane = dispatch.execution.lane.trim().toLowerCase();
82
+ const role = dispatch.execution.role.trim().toLowerCase();
83
+ const cycleKind = dispatch.cycleRun.kind.trim().toLowerCase();
80
84
  const isQa = role === "qa" || lane === "qa";
81
- const isArchitect = role === "architect" || lane === "architect" || dispatch.cycleRun.kind.toLowerCase() === "architect";
85
+ const isArchitect = role === "architect" || lane === "architect" || cycleKind === "architect";
86
+ const isCiRepair = role === "ci_repair" || lane === "ci_repair" || cycleKind === "pr_checks";
82
87
  const isConflictResolve = role === "conflict_resolve" || lane === "conflict_resolve";
83
88
  const context = {
84
89
  dispatch: providerDispatch,
@@ -90,9 +95,11 @@ export class BridgeSessionService {
90
95
  ? await this.providerCli.runQa(context)
91
96
  : isArchitect
92
97
  ? await this.providerCli.runArchitect(context)
93
- : isConflictResolve
94
- ? await this.providerCli.runConflictResolve(context)
95
- : await this.providerCli.runImplementation(context);
98
+ : isCiRepair
99
+ ? await this.providerCli.runCiRepair(context)
100
+ : isConflictResolve
101
+ ? await this.providerCli.runConflictResolve(context)
102
+ : await this.providerCli.runImplementation(context);
96
103
  throwIfAborted(signal);
97
104
  const phaseArtifacts = run.artifacts?.length ? run.artifacts : run.artifact ? [run.artifact] : [];
98
105
  return redactSecrets({
@@ -1,5 +1,5 @@
1
1
  export interface RunOnceDispatchPacket {
2
- readonly schemaVersion: 1;
2
+ readonly schemaVersion: 1 | 2;
3
3
  readonly userId: string;
4
4
  readonly workItem: DispatchWorkItem;
5
5
  readonly repo: DispatchRepo;
@@ -8,8 +8,10 @@ export interface RunOnceDispatchPacket {
8
8
  readonly lease: DispatchLease;
9
9
  readonly execution: DispatchExecution;
10
10
  readonly serverLocal: DispatchServerLocalConfig;
11
+ readonly sandbox?: DispatchSandboxContext | null;
11
12
  readonly pullRequest?: DispatchPullRequestContext | null;
12
13
  readonly apiKeySecretGrant?: ApiKeySecretGrant | null;
14
+ readonly apiKeySecretGrantHandle?: ApiKeySecretGrantHandle | null;
13
15
  readonly artifacts: readonly DispatchResolvedArtifact[];
14
16
  readonly warmPathOverrides?: readonly string[];
15
17
  readonly qaBrowser?: DispatchQaBrowserContext | null;
@@ -22,6 +24,39 @@ export interface RunOnceDispatchPacket {
22
24
  readonly designerRefs?: DispatchDesignerRefHandoffContext | null;
23
25
  readonly draft?: DispatchDraftPrompt | null;
24
26
  }
27
+ export interface DispatchSandboxContext {
28
+ readonly dispatchAttemptId: string;
29
+ readonly executionLeaseId: string;
30
+ readonly runnerInstanceId: string;
31
+ readonly executionMode: "host" | "docker";
32
+ readonly executionPolicy: "host_allowed" | "sandbox_preferred" | "sandbox_required";
33
+ readonly networkPolicy: DispatchSandboxNetworkPolicy;
34
+ readonly requestedResources: DispatchSandboxResourceRequest;
35
+ readonly runtime?: string | null;
36
+ readonly sandboxConfigCommitSha?: string | null;
37
+ readonly inputCommitSha?: string | null;
38
+ readonly contractDigest?: string | null;
39
+ readonly imageDigest?: string | null;
40
+ readonly publicationMode: "bridge_push" | "shared_filesystem";
41
+ readonly publishGrantHandle?: DispatchPublishGrantHandle | null;
42
+ }
43
+ export interface DispatchPublishGrantHandle {
44
+ readonly grantId: string;
45
+ readonly branch: string;
46
+ readonly expiresAt: string;
47
+ }
48
+ export interface DispatchSandboxResourceRequest {
49
+ readonly sandboxSlots: number;
50
+ readonly cpuMillis: number;
51
+ readonly memoryBytes: number;
52
+ readonly workspaceBytes: number;
53
+ readonly pids: number;
54
+ readonly buildSlots: number;
55
+ }
56
+ export interface DispatchSandboxNetworkPolicy {
57
+ readonly mode: "offline" | "public_allowlist" | "open_public";
58
+ readonly allowedHosts: readonly string[];
59
+ }
25
60
  export interface DispatchDraftPrompt {
26
61
  readonly kind: string;
27
62
  readonly systemPrompt: string;
@@ -279,6 +314,11 @@ export interface ApiKeySecretGrant {
279
314
  readonly secret: string;
280
315
  readonly expiresAt: string;
281
316
  }
317
+ export interface ApiKeySecretGrantHandle {
318
+ readonly grantId: string;
319
+ readonly provider: string;
320
+ readonly expiresAt: string;
321
+ }
282
322
  export interface DispatchServerLocalConfig {
283
323
  readonly repoRoot: string;
284
324
  readonly cleanupWorktrees: boolean;
@@ -2,11 +2,11 @@ import path from "node:path";
2
2
  export function parseRunOnceDispatchPacket(value) {
3
3
  const packet = asObject(value, "dispatch packet");
4
4
  const schemaVersion = requiredNumber(packet, "schemaVersion");
5
- if (schemaVersion !== 1) {
5
+ if (schemaVersion !== 1 && schemaVersion !== 2) {
6
6
  throw new Error(`Unsupported dispatch schemaVersion: ${schemaVersion}`);
7
7
  }
8
8
  return {
9
- schemaVersion: 1,
9
+ schemaVersion,
10
10
  userId: requiredString(packet, "userId"),
11
11
  workItem: parseWorkItem(packet.workItem),
12
12
  repo: parseRepo(packet.repo),
@@ -15,8 +15,10 @@ export function parseRunOnceDispatchPacket(value) {
15
15
  lease: parseLease(packet.lease),
16
16
  execution: parseExecution(packet.execution),
17
17
  serverLocal: parseServerLocal(packet.serverLocal),
18
+ sandbox: parseSandbox(packet.sandbox, schemaVersion),
18
19
  pullRequest: parsePullRequest(packet.pullRequest),
19
20
  apiKeySecretGrant: parseApiKeySecretGrant(packet.apiKeySecretGrant),
21
+ apiKeySecretGrantHandle: parseApiKeySecretGrantHandle(packet.apiKeySecretGrantHandle),
20
22
  artifacts: parseArtifacts(packet.artifacts),
21
23
  warmPathOverrides: parseWarmPathOverrides(packet.warmPathOverrides),
22
24
  qaBrowser: parseQaBrowser(packet.qaBrowser),
@@ -30,6 +32,104 @@ export function parseRunOnceDispatchPacket(value) {
30
32
  draft: parseDraftPrompt(packet.draft)
31
33
  };
32
34
  }
35
+ function parseSandbox(value, schemaVersion) {
36
+ if (value === undefined || value === null) {
37
+ if (schemaVersion === 2) {
38
+ throw new Error("sandbox is required for dispatch schemaVersion 2.");
39
+ }
40
+ return null;
41
+ }
42
+ const sandbox = asObject(value, "sandbox");
43
+ const executionMode = requiredString(sandbox, "executionMode");
44
+ if (executionMode !== "host" && executionMode !== "docker") {
45
+ throw new Error("sandbox.executionMode must be host or docker.");
46
+ }
47
+ const executionPolicy = requiredString(sandbox, "executionPolicy");
48
+ if (executionPolicy !== "host_allowed" && executionPolicy !== "sandbox_preferred" && executionPolicy !== "sandbox_required") {
49
+ throw new Error("sandbox.executionPolicy is invalid.");
50
+ }
51
+ return {
52
+ dispatchAttemptId: requiredString(sandbox, "dispatchAttemptId"),
53
+ executionLeaseId: requiredString(sandbox, "executionLeaseId"),
54
+ runnerInstanceId: requiredString(sandbox, "runnerInstanceId"),
55
+ executionMode,
56
+ executionPolicy,
57
+ networkPolicy: parseSandboxNetworkPolicy(sandbox.networkPolicy),
58
+ requestedResources: parseSandboxResourceRequest(sandbox.requestedResources),
59
+ runtime: optionalString(sandbox, "runtime"),
60
+ sandboxConfigCommitSha: optionalString(sandbox, "sandboxConfigCommitSha"),
61
+ inputCommitSha: optionalString(sandbox, "inputCommitSha"),
62
+ contractDigest: optionalString(sandbox, "contractDigest"),
63
+ imageDigest: optionalString(sandbox, "imageDigest"),
64
+ publicationMode: parsePublicationMode(sandbox.publicationMode),
65
+ publishGrantHandle: parsePublishGrantHandle(sandbox.publishGrantHandle)
66
+ };
67
+ }
68
+ function parsePublicationMode(value) {
69
+ if (value === undefined || value === null)
70
+ return "shared_filesystem";
71
+ if (value !== "bridge_push" && value !== "shared_filesystem")
72
+ throw new Error("sandbox.publicationMode is invalid.");
73
+ return value;
74
+ }
75
+ function parsePublishGrantHandle(value) {
76
+ if (value === undefined || value === null)
77
+ return null;
78
+ const handle = asObject(value, "sandbox.publishGrantHandle");
79
+ const grantId = requiredString(handle, "grantId");
80
+ const branch = requiredString(handle, "branch");
81
+ const expiresAt = requiredString(handle, "expiresAt");
82
+ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu.test(grantId)) {
83
+ throw new Error("sandbox.publishGrantHandle.grantId is invalid.");
84
+ }
85
+ if (branch.length > 240)
86
+ throw new Error("sandbox.publishGrantHandle.branch is too long.");
87
+ if (!Number.isFinite(Date.parse(expiresAt)))
88
+ throw new Error("sandbox.publishGrantHandle.expiresAt is invalid.");
89
+ return { grantId, branch, expiresAt };
90
+ }
91
+ function parseSandboxResourceRequest(value) {
92
+ if (value === undefined || value === null) {
93
+ return {
94
+ sandboxSlots: 1,
95
+ cpuMillis: 2000,
96
+ memoryBytes: 4 * 1024 ** 3,
97
+ workspaceBytes: 10 * 1024 ** 3,
98
+ pids: 512,
99
+ buildSlots: 1
100
+ };
101
+ }
102
+ const resources = asObject(value, "sandbox.requestedResources");
103
+ return {
104
+ sandboxSlots: boundedInteger(resources, "sandboxSlots", 1, 4),
105
+ cpuMillis: boundedInteger(resources, "cpuMillis", 100, 64_000),
106
+ memoryBytes: boundedInteger(resources, "memoryBytes", 128 * 1024 ** 2, 512 * 1024 ** 3),
107
+ workspaceBytes: boundedInteger(resources, "workspaceBytes", 1024 ** 3, 10 * 1024 ** 4),
108
+ pids: boundedInteger(resources, "pids", 32, 65_536),
109
+ buildSlots: boundedInteger(resources, "buildSlots", 0, 4)
110
+ };
111
+ }
112
+ function parseSandboxNetworkPolicy(value) {
113
+ if (value === undefined || value === null)
114
+ return { mode: "public_allowlist", allowedHosts: [] };
115
+ const policy = asObject(value, "sandbox.networkPolicy");
116
+ const mode = requiredString(policy, "mode");
117
+ if (mode !== "offline" && mode !== "public_allowlist" && mode !== "open_public") {
118
+ throw new Error("sandbox.networkPolicy.mode is invalid.");
119
+ }
120
+ const rawHosts = policy.allowedHosts ?? [];
121
+ if (!Array.isArray(rawHosts) || rawHosts.some((host) => typeof host !== "string")) {
122
+ throw new Error("sandbox.networkPolicy.allowedHosts must be a string array.");
123
+ }
124
+ const allowedHosts = [...new Set(rawHosts.map(host => host.trim().toLowerCase()).filter(Boolean))];
125
+ if (allowedHosts.length > 128 || allowedHosts.some(host => !/^(?:\*\.)?(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z](?:[a-z0-9-]{0,61}[a-z0-9])?$/u.test(host))) {
126
+ throw new Error("sandbox.networkPolicy.allowedHosts contains an invalid hostname.");
127
+ }
128
+ if (mode !== "public_allowlist" && allowedHosts.length > 0) {
129
+ throw new Error("sandbox.networkPolicy.allowedHosts requires public_allowlist mode.");
130
+ }
131
+ return { mode, allowedHosts };
132
+ }
33
133
  export function failureResult(summary, events = []) {
34
134
  return {
35
135
  schemaVersion: 1,
@@ -172,6 +272,16 @@ function parseApiKeySecretGrant(value) {
172
272
  expiresAt: requiredString(grant, "expiresAt")
173
273
  };
174
274
  }
275
+ function parseApiKeySecretGrantHandle(value) {
276
+ if (value === undefined || value === null)
277
+ return null;
278
+ const grant = asObject(value, "apiKeySecretGrantHandle");
279
+ return {
280
+ grantId: requiredString(grant, "grantId"),
281
+ provider: requiredString(grant, "provider"),
282
+ expiresAt: requiredString(grant, "expiresAt")
283
+ };
284
+ }
175
285
  function parseServerLocal(value) {
176
286
  const serverLocal = asObject(value, "serverLocal");
177
287
  return {
@@ -616,3 +726,10 @@ function requiredNumber(source, key) {
616
726
  }
617
727
  return value;
618
728
  }
729
+ function boundedInteger(source, key, minimum, maximum) {
730
+ const value = requiredNumber(source, key);
731
+ if (!Number.isSafeInteger(value) || value < minimum || value > maximum) {
732
+ throw new Error(`${key} must be an integer from ${minimum} through ${maximum}.`);
733
+ }
734
+ return value;
735
+ }
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const forgeBridgeVersion = "0.1.3-dev.09aeeb7ccadf";
1
+ export declare const forgeBridgeVersion = "0.1.3-dev.1fe428dd78ab";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const forgeBridgeVersion = "0.1.3-dev.09aeeb7ccadf";
1
+ export const forgeBridgeVersion = "0.1.3-dev.1fe428dd78ab";
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@loucompanion/forge-bridge",
3
- "version": "0.1.3-dev.09aeeb7ccadf",
3
+ "version": "0.1.3-dev.1fe428dd78ab",
4
4
  "description": "Forge runner bridge CLI for connecting local developer machines to Forge dispatch.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
7
7
  "bin": {
8
+ "forge": "dist/cli/bin.js",
8
9
  "forge-bridge": "dist/cli/bin.js"
9
10
  },
10
11
  "main": "./dist/index.js",
@@ -43,7 +44,8 @@
43
44
  "lint": "eslint \"src/**/*.ts\" \"scripts/**/*.mjs\" \"vitest.config.ts\""
44
45
  },
45
46
  "dependencies": {
46
- "@microsoft/signalr": "^8.0.17"
47
+ "@microsoft/signalr": "^8.0.17",
48
+ "yaml": "^2.9.0"
47
49
  },
48
50
  "devDependencies": {
49
51
  "@eslint/js": "^10.0.1",