@loucompanion/forge-bridge 0.1.1-dev.2bc1e7f19b3a → 0.1.1-dev.4f31cdd58cac
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/session/provider-cli/provider-cli.service.js +148 -2
- package/dist/session/provider-cli/provider-usage.d.ts +25 -0
- package/dist/session/provider-cli/provider-usage.js +64 -0
- package/dist/session/session.types.d.ts +4 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -8,8 +8,10 @@ import { GitClient } from "../../shared/git/git.js";
|
|
|
8
8
|
import { resolveCursorAgentDirectLaunch } from "../../shared/cursor-agent/cursor-agent.launch.js";
|
|
9
9
|
import { buildSpecBody, selectLaneCommand } from "../../worktree/artifact-injector.js";
|
|
10
10
|
import { codexMcpConfigArgs, completionPhaseFromDispatch, completionPromptForDevelopCycle, completionPromptForPhase, completionRedactionEnv, expectedCompletionToolName, prepareCompletionToolRuntime, readCompletionArtifact, usesDevelopCycleCompletion, writeCompletionArtifact } from "../phase-completion.js";
|
|
11
|
+
import { addUsage, buildProviderUsageEvent, emptyUsage, hasUsage, readUsageNumber } from "./provider-usage.js";
|
|
11
12
|
const fakeWorkerModel = "server-local-fake-worker";
|
|
12
13
|
const execFileAsync = promisify(execFile);
|
|
14
|
+
const developCyclePhaseOrder = ["implementation", "self_review", "validation"];
|
|
13
15
|
export class RoutingProviderCliService {
|
|
14
16
|
realProvider;
|
|
15
17
|
deterministicProvider;
|
|
@@ -75,8 +77,10 @@ export class ProcessBackedProviderCliService {
|
|
|
75
77
|
eventType: "completion_tools_configured"
|
|
76
78
|
});
|
|
77
79
|
const outputState = createProviderOutputState(dispatch.execution.provider);
|
|
80
|
+
const liveCompletionEvents = new LiveCompletionArtifactEmitter(worktree.worktreePath, dispatch.workItem.id, phase, developCycle, context.emit);
|
|
78
81
|
let result;
|
|
79
82
|
try {
|
|
83
|
+
liveCompletionEvents.start();
|
|
80
84
|
result = await this.processRunner.run({
|
|
81
85
|
command: command.command,
|
|
82
86
|
args: command.args,
|
|
@@ -92,6 +96,7 @@ export class ProcessBackedProviderCliService {
|
|
|
92
96
|
}, context.signal);
|
|
93
97
|
}
|
|
94
98
|
finally {
|
|
99
|
+
await liveCompletionEvents.stop();
|
|
95
100
|
await cleanupCompletionTools(completionTools, context.emit);
|
|
96
101
|
}
|
|
97
102
|
if (result.exitCode !== 0) {
|
|
@@ -104,11 +109,15 @@ export class ProcessBackedProviderCliService {
|
|
|
104
109
|
content: `Provider CLI completed: ${command.command} exit ${result.exitCode}${outputState.sessionLabel ? ` ${outputState.sessionLabel}` : ""}.`,
|
|
105
110
|
eventType: "provider_cli_completed"
|
|
106
111
|
});
|
|
112
|
+
await emitProviderUsageEvent(context.emit, dispatch, outputState);
|
|
107
113
|
const committed = await commitWorktreeChanges(this.git, worktree.worktreePath, dispatch.workItem.id);
|
|
108
114
|
const completionArtifacts = await readCompletionArtifactsForRun(worktree.worktreePath, dispatch.workItem.id, phase, developCycle);
|
|
109
115
|
for (const artifact of completionArtifacts) {
|
|
110
|
-
|
|
111
|
-
|
|
116
|
+
if (!liveCompletionEvents.hasEmitted(completionPhaseFromArtifact(artifact))) {
|
|
117
|
+
await emitCompletionArtifactRecorded(context.emit, worktree.worktreePath, artifact);
|
|
118
|
+
await emitPhaseCompletionEvent(context.emit, artifact);
|
|
119
|
+
await emitPhaseGateEvents(context.emit, artifact);
|
|
120
|
+
}
|
|
112
121
|
}
|
|
113
122
|
const completionArtifact = completionArtifacts[0];
|
|
114
123
|
if (outputState.finalMessage) {
|
|
@@ -173,6 +182,7 @@ export class ProcessBackedProviderCliService {
|
|
|
173
182
|
content: `Provider CLI QA completed: ${command.command} exit ${result.exitCode}${outputState.sessionLabel ? ` ${outputState.sessionLabel}` : ""}.`,
|
|
174
183
|
eventType: "provider_cli_completed"
|
|
175
184
|
});
|
|
185
|
+
await emitProviderUsageEvent(emit, dispatch, outputState);
|
|
176
186
|
return {
|
|
177
187
|
summary: `${dispatch.execution.provider} CLI QA passed.`
|
|
178
188
|
};
|
|
@@ -208,6 +218,7 @@ export class ProcessBackedProviderCliService {
|
|
|
208
218
|
}
|
|
209
219
|
const committed = await commitWorktreeChanges(this.git, worktree.worktreePath, dispatch.workItem.id);
|
|
210
220
|
await this.git.run(worktree.worktreePath, ["push", "origin", `HEAD:${worktree.branchName}`]);
|
|
221
|
+
await emitProviderUsageEvent(context.emit, dispatch, outputState);
|
|
211
222
|
await context.emit({
|
|
212
223
|
role: "assistant",
|
|
213
224
|
kind: "message",
|
|
@@ -283,6 +294,7 @@ export class DeterministicProviderCliService {
|
|
|
283
294
|
eventType: phaseCompleteEventType(completionPhase)
|
|
284
295
|
});
|
|
285
296
|
}
|
|
297
|
+
await context.emit(buildProviderUsageEvent(dispatch, estimatedDeterministicUsage()));
|
|
286
298
|
return {
|
|
287
299
|
summary: `forge-bridge completed ${worktree.branchName} (${developCycle ? "develop cycle" : phase}).`,
|
|
288
300
|
spec: {
|
|
@@ -309,6 +321,7 @@ export class DeterministicProviderCliService {
|
|
|
309
321
|
content: "All checks passed. forge-bridge QA completed.",
|
|
310
322
|
eventType: "qa_complete"
|
|
311
323
|
});
|
|
324
|
+
await emit(buildProviderUsageEvent(dispatch, estimatedDeterministicUsage()));
|
|
312
325
|
return {
|
|
313
326
|
summary: "forge-bridge QA passed."
|
|
314
327
|
};
|
|
@@ -316,6 +329,7 @@ export class DeterministicProviderCliService {
|
|
|
316
329
|
async runConflictResolve(context) {
|
|
317
330
|
const { dispatch, worktree } = context;
|
|
318
331
|
await this.git.run(worktree.worktreePath, ["commit", "--allow-empty", "-m", `forge bridge conflict resolve for ${dispatch.workItem.id.slice(0, 8)}`]);
|
|
332
|
+
await context.emit(buildProviderUsageEvent(dispatch, estimatedDeterministicUsage()));
|
|
319
333
|
await context.emit({
|
|
320
334
|
role: "assistant",
|
|
321
335
|
kind: "message",
|
|
@@ -430,12 +444,93 @@ async function emitPhaseCompletionEvent(emit, artifact) {
|
|
|
430
444
|
eventType: phaseCompleteEventType(phase)
|
|
431
445
|
});
|
|
432
446
|
}
|
|
447
|
+
async function emitPhaseGateEvents(emit, artifact) {
|
|
448
|
+
const phase = completionPhaseFromArtifact(artifact);
|
|
449
|
+
const status = (artifact.status ?? "").trim().toLowerCase() || "unknown";
|
|
450
|
+
await emit({
|
|
451
|
+
role: "hook",
|
|
452
|
+
kind: "checkpoint",
|
|
453
|
+
content: `phase_gate: ${phase} artifact accepted with status ${status}.`,
|
|
454
|
+
eventType: "phase_gate"
|
|
455
|
+
});
|
|
456
|
+
if (status !== "pass") {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
const progression = phase === "implementation"
|
|
460
|
+
? "phase_progression: implementation -> self_review"
|
|
461
|
+
: phase === "self_review"
|
|
462
|
+
? "phase_progression: self_review -> validation"
|
|
463
|
+
: "phase_progression: validation -> Dev Test ready";
|
|
464
|
+
await emit({
|
|
465
|
+
role: "hook",
|
|
466
|
+
kind: "checkpoint",
|
|
467
|
+
content: progression,
|
|
468
|
+
eventType: "phase_gate"
|
|
469
|
+
});
|
|
470
|
+
}
|
|
433
471
|
function completionPhaseFromArtifact(artifact) {
|
|
434
472
|
const phase = artifact.phase?.trim();
|
|
435
473
|
return phase === "self_review" || phase === "validation" || phase === "implementation"
|
|
436
474
|
? phase
|
|
437
475
|
: "implementation";
|
|
438
476
|
}
|
|
477
|
+
class LiveCompletionArtifactEmitter {
|
|
478
|
+
worktreePath;
|
|
479
|
+
workItemId;
|
|
480
|
+
emit;
|
|
481
|
+
phases;
|
|
482
|
+
emitted = new Set();
|
|
483
|
+
timer = null;
|
|
484
|
+
pending = Promise.resolve();
|
|
485
|
+
constructor(worktreePath, workItemId, phase, developCycle, emit) {
|
|
486
|
+
this.worktreePath = worktreePath;
|
|
487
|
+
this.workItemId = workItemId;
|
|
488
|
+
this.emit = emit;
|
|
489
|
+
this.phases = developCycle
|
|
490
|
+
? developCyclePhaseOrder.slice(developCyclePhaseOrder.indexOf(phase))
|
|
491
|
+
: [phase];
|
|
492
|
+
}
|
|
493
|
+
start() {
|
|
494
|
+
void this.pollQueued();
|
|
495
|
+
this.timer = setInterval(() => {
|
|
496
|
+
void this.pollQueued();
|
|
497
|
+
}, 250);
|
|
498
|
+
}
|
|
499
|
+
async stop() {
|
|
500
|
+
if (this.timer) {
|
|
501
|
+
clearInterval(this.timer);
|
|
502
|
+
this.timer = null;
|
|
503
|
+
}
|
|
504
|
+
await this.pollQueued();
|
|
505
|
+
}
|
|
506
|
+
hasEmitted(phase) {
|
|
507
|
+
return this.emitted.has(phase);
|
|
508
|
+
}
|
|
509
|
+
pollQueued() {
|
|
510
|
+
this.pending = this.pending
|
|
511
|
+
.then(() => this.poll())
|
|
512
|
+
.catch(() => undefined);
|
|
513
|
+
return this.pending;
|
|
514
|
+
}
|
|
515
|
+
async poll() {
|
|
516
|
+
for (const phase of this.phases) {
|
|
517
|
+
if (this.emitted.has(phase)) {
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
const artifact = await readCompletionArtifact(this.worktreePath, this.workItemId, phase);
|
|
521
|
+
if (!artifact) {
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
this.emitted.add(phase);
|
|
525
|
+
await emitCompletionArtifactRecorded(this.emit, this.worktreePath, artifact);
|
|
526
|
+
await emitPhaseCompletionEvent(this.emit, artifact);
|
|
527
|
+
await emitPhaseGateEvents(this.emit, artifact);
|
|
528
|
+
if ((artifact.status ?? "").trim().toLowerCase() !== "pass") {
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
439
534
|
async function readCompletionArtifactsForRun(worktreePath, workItemId, phase, developCycle) {
|
|
440
535
|
if (!developCycle) {
|
|
441
536
|
const artifact = await readCompletionArtifact(worktreePath, workItemId, phase);
|
|
@@ -471,6 +566,19 @@ function providerRedactionEnv(dispatch) {
|
|
|
471
566
|
function exactRedactionSecrets(dispatch) {
|
|
472
567
|
return dispatch.apiKeySecretGrant?.secret ? [dispatch.apiKeySecretGrant.secret] : [];
|
|
473
568
|
}
|
|
569
|
+
async function emitProviderUsageEvent(emit, dispatch, outputState) {
|
|
570
|
+
const usage = outputState.usage;
|
|
571
|
+
if (hasUsage(usage)) {
|
|
572
|
+
await emit(buildProviderUsageEvent(dispatch, usage));
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
function estimatedDeterministicUsage() {
|
|
576
|
+
return addUsage(emptyUsage("estimated"), {
|
|
577
|
+
inputTokens: 1000,
|
|
578
|
+
outputTokens: 400,
|
|
579
|
+
source: "estimated"
|
|
580
|
+
});
|
|
581
|
+
}
|
|
474
582
|
export class StreamingProviderProcessRunner {
|
|
475
583
|
async run(request, handlers = {}, signal) {
|
|
476
584
|
const launch = await resolveProviderProcessLaunch(request.command, request.args);
|
|
@@ -777,9 +885,13 @@ class CursorStreamJsonState {
|
|
|
777
885
|
sessionId = null;
|
|
778
886
|
finalMessage = null;
|
|
779
887
|
emittedSession = false;
|
|
888
|
+
accumulatedUsage = null;
|
|
780
889
|
get sessionLabel() {
|
|
781
890
|
return this.sessionId ? `session ${this.sessionId}` : null;
|
|
782
891
|
}
|
|
892
|
+
get usage() {
|
|
893
|
+
return this.accumulatedUsage;
|
|
894
|
+
}
|
|
783
895
|
consume(line) {
|
|
784
896
|
const event = parseJsonLine(line);
|
|
785
897
|
if (!event) {
|
|
@@ -841,6 +953,7 @@ class CursorStreamJsonState {
|
|
|
841
953
|
if (result) {
|
|
842
954
|
this.finalMessage = clip(result, 4000);
|
|
843
955
|
}
|
|
956
|
+
this.accumulateUsage(event);
|
|
844
957
|
}
|
|
845
958
|
if (type === "error" || (type === "result" && event.is_error === true)) {
|
|
846
959
|
return {
|
|
@@ -852,6 +965,21 @@ class CursorStreamJsonState {
|
|
|
852
965
|
}
|
|
853
966
|
return null;
|
|
854
967
|
}
|
|
968
|
+
accumulateUsage(event) {
|
|
969
|
+
const usage = objectField(event, "usage");
|
|
970
|
+
const durationMs = readUsageNumber(event, "duration_ms") || readUsageNumber(event, "duration_api_ms");
|
|
971
|
+
if (Object.keys(usage).length === 0 && durationMs === 0) {
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
this.accumulatedUsage = addUsage(this.accumulatedUsage ?? emptyUsage("provider_reported"), {
|
|
975
|
+
inputTokens: readUsageNumber(usage, "inputTokens"),
|
|
976
|
+
outputTokens: readUsageNumber(usage, "outputTokens"),
|
|
977
|
+
cacheReadTokens: readUsageNumber(usage, "cacheReadTokens"),
|
|
978
|
+
cacheCreationTokens: readUsageNumber(usage, "cacheWriteTokens"),
|
|
979
|
+
providerDurationMs: durationMs > 0 ? durationMs : null,
|
|
980
|
+
source: "provider_reported"
|
|
981
|
+
});
|
|
982
|
+
}
|
|
855
983
|
}
|
|
856
984
|
function formatCursorToolCallStarted(toolCall) {
|
|
857
985
|
const readArgs = objectField(objectField(toolCall, "readToolCall"), "args");
|
|
@@ -956,9 +1084,13 @@ class CodexJsonState {
|
|
|
956
1084
|
threadId = null;
|
|
957
1085
|
finalMessage = null;
|
|
958
1086
|
emittedThread = false;
|
|
1087
|
+
accumulatedUsage = null;
|
|
959
1088
|
get sessionLabel() {
|
|
960
1089
|
return this.threadId ? `thread ${this.threadId}` : null;
|
|
961
1090
|
}
|
|
1091
|
+
get usage() {
|
|
1092
|
+
return this.accumulatedUsage;
|
|
1093
|
+
}
|
|
962
1094
|
consume(line) {
|
|
963
1095
|
const event = parseJsonLine(line);
|
|
964
1096
|
if (!event) {
|
|
@@ -978,6 +1110,7 @@ class CodexJsonState {
|
|
|
978
1110
|
}
|
|
979
1111
|
}
|
|
980
1112
|
if (type === "turn.completed") {
|
|
1113
|
+
this.accumulateUsage(event);
|
|
981
1114
|
return {
|
|
982
1115
|
role: "runner",
|
|
983
1116
|
kind: "checkpoint",
|
|
@@ -1023,6 +1156,19 @@ class CodexJsonState {
|
|
|
1023
1156
|
}
|
|
1024
1157
|
return null;
|
|
1025
1158
|
}
|
|
1159
|
+
accumulateUsage(event) {
|
|
1160
|
+
const usage = objectField(event, "usage");
|
|
1161
|
+
if (Object.keys(usage).length === 0) {
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
this.accumulatedUsage = addUsage(this.accumulatedUsage ?? emptyUsage("provider_reported"), {
|
|
1165
|
+
inputTokens: readUsageNumber(usage, "input_tokens"),
|
|
1166
|
+
outputTokens: readUsageNumber(usage, "output_tokens"),
|
|
1167
|
+
cacheReadTokens: readUsageNumber(usage, "cached_input_tokens"),
|
|
1168
|
+
reasoningOutputTokens: readUsageNumber(usage, "reasoning_output_tokens"),
|
|
1169
|
+
source: "provider_reported"
|
|
1170
|
+
});
|
|
1171
|
+
}
|
|
1026
1172
|
}
|
|
1027
1173
|
function objectField(source, key) {
|
|
1028
1174
|
const value = source[key];
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { RunOnceDispatchPacket, RunnerDispatchEvent } from "../session.types.js";
|
|
2
|
+
export type UsageSource = "provider_reported" | "cli_reported" | "estimated" | "unknown";
|
|
3
|
+
/**
|
|
4
|
+
* Normalized, provider-agnostic token usage accumulated for a dispatch. Cost is never computed
|
|
5
|
+
* here; the API recomputes cost from these tokens x model rates (ADR-0006).
|
|
6
|
+
*/
|
|
7
|
+
export interface ProviderUsage {
|
|
8
|
+
readonly inputTokens: number;
|
|
9
|
+
readonly outputTokens: number;
|
|
10
|
+
readonly cacheReadTokens: number;
|
|
11
|
+
readonly cacheCreationTokens: number;
|
|
12
|
+
readonly reasoningOutputTokens: number;
|
|
13
|
+
readonly providerDurationMs: number | null;
|
|
14
|
+
readonly source: UsageSource;
|
|
15
|
+
}
|
|
16
|
+
export declare function emptyUsage(source?: UsageSource): ProviderUsage;
|
|
17
|
+
export declare function addUsage(base: ProviderUsage, next: Partial<ProviderUsage>): ProviderUsage;
|
|
18
|
+
export declare function totalTokens(usage: ProviderUsage): number;
|
|
19
|
+
export declare function hasUsage(usage: ProviderUsage | null): usage is ProviderUsage;
|
|
20
|
+
/**
|
|
21
|
+
* Builds the durable `provider_usage` event. Token numbers travel as a structured `data` JSON
|
|
22
|
+
* string (snake_case) that the API parses into a usage_event row.
|
|
23
|
+
*/
|
|
24
|
+
export declare function buildProviderUsageEvent(dispatch: RunOnceDispatchPacket, usage: ProviderUsage): RunnerDispatchEvent;
|
|
25
|
+
export declare function readUsageNumber(source: Record<string, unknown>, key: string): number;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export function emptyUsage(source = "unknown") {
|
|
2
|
+
return {
|
|
3
|
+
inputTokens: 0,
|
|
4
|
+
outputTokens: 0,
|
|
5
|
+
cacheReadTokens: 0,
|
|
6
|
+
cacheCreationTokens: 0,
|
|
7
|
+
reasoningOutputTokens: 0,
|
|
8
|
+
providerDurationMs: null,
|
|
9
|
+
source
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export function addUsage(base, next) {
|
|
13
|
+
return {
|
|
14
|
+
inputTokens: base.inputTokens + nonNegative(next.inputTokens),
|
|
15
|
+
outputTokens: base.outputTokens + nonNegative(next.outputTokens),
|
|
16
|
+
cacheReadTokens: base.cacheReadTokens + nonNegative(next.cacheReadTokens),
|
|
17
|
+
cacheCreationTokens: base.cacheCreationTokens + nonNegative(next.cacheCreationTokens),
|
|
18
|
+
reasoningOutputTokens: base.reasoningOutputTokens + nonNegative(next.reasoningOutputTokens),
|
|
19
|
+
providerDurationMs: next.providerDurationMs ?? base.providerDurationMs,
|
|
20
|
+
source: next.source ?? base.source
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function totalTokens(usage) {
|
|
24
|
+
return usage.inputTokens + usage.outputTokens + usage.cacheReadTokens + usage.cacheCreationTokens;
|
|
25
|
+
}
|
|
26
|
+
export function hasUsage(usage) {
|
|
27
|
+
return usage !== null && totalTokens(usage) > 0;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Builds the durable `provider_usage` event. Token numbers travel as a structured `data` JSON
|
|
31
|
+
* string (snake_case) that the API parses into a usage_event row.
|
|
32
|
+
*/
|
|
33
|
+
export function buildProviderUsageEvent(dispatch, usage) {
|
|
34
|
+
const data = {
|
|
35
|
+
provider: dispatch.execution.provider,
|
|
36
|
+
model: dispatch.execution.model,
|
|
37
|
+
lane: dispatch.execution.lane,
|
|
38
|
+
phase: dispatch.cycleRun.phase,
|
|
39
|
+
attempt: dispatch.cycleRun.attempt,
|
|
40
|
+
input_tokens: usage.inputTokens,
|
|
41
|
+
output_tokens: usage.outputTokens,
|
|
42
|
+
cache_read_tokens: usage.cacheReadTokens,
|
|
43
|
+
cache_creation_tokens: usage.cacheCreationTokens,
|
|
44
|
+
reasoning_output_tokens: usage.reasoningOutputTokens,
|
|
45
|
+
metered: dispatch.execution.authKind === "api_key",
|
|
46
|
+
usage_source: usage.source,
|
|
47
|
+
provider_duration_ms: usage.providerDurationMs
|
|
48
|
+
};
|
|
49
|
+
const total = totalTokens(usage);
|
|
50
|
+
return {
|
|
51
|
+
role: "runner",
|
|
52
|
+
kind: "checkpoint",
|
|
53
|
+
content: `Provider usage: ${total} tokens (${usage.inputTokens} in / ${usage.outputTokens} out) for ${dispatch.execution.model}.`,
|
|
54
|
+
eventType: "provider_usage",
|
|
55
|
+
data: JSON.stringify(data)
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export function readUsageNumber(source, key) {
|
|
59
|
+
const value = source[key];
|
|
60
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
|
|
61
|
+
}
|
|
62
|
+
function nonNegative(value) {
|
|
63
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
|
|
64
|
+
}
|
|
@@ -87,6 +87,10 @@ export interface RunnerDispatchEvent {
|
|
|
87
87
|
readonly kind: string;
|
|
88
88
|
readonly content: string;
|
|
89
89
|
readonly eventType: string;
|
|
90
|
+
/** Provider/runner-reported event time (ISO-8601) when available, preserved for accurate durations. */
|
|
91
|
+
readonly occurredAt?: string | null;
|
|
92
|
+
/** Optional structured telemetry payload (JSON string), e.g. token usage for provider_usage events. */
|
|
93
|
+
readonly data?: string | null;
|
|
90
94
|
}
|
|
91
95
|
export interface RunnerDispatchSpec {
|
|
92
96
|
readonly repoPath: string;
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const forgeBridgeVersion = "0.1.1-dev.
|
|
1
|
+
export declare const forgeBridgeVersion = "0.1.1-dev.4f31cdd58cac";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const forgeBridgeVersion = "0.1.1-dev.
|
|
1
|
+
export const forgeBridgeVersion = "0.1.1-dev.4f31cdd58cac";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loucompanion/forge-bridge",
|
|
3
|
-
"version": "0.1.1-dev.
|
|
3
|
+
"version": "0.1.1-dev.4f31cdd58cac",
|
|
4
4
|
"description": "Forge runner bridge CLI for connecting local developer machines to Forge dispatch.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|