agl 40.5.1 → 41.0.0
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/changelog.md +43 -0
- package/dist_serve/bundle.js +3514 -3357
- package/dist_serve/bundle.js.map +2 -2
- package/dist_serve/bundle.js.third-party-notices.json +58 -32
- package/dist_serve/bundle.js.third-party-notices.txt +108 -33
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/aglapi/aglapisurface.document.js +64 -37
- package/dist_ts/classes.aglhome.d.ts +5 -0
- package/dist_ts/classes.aglhome.js +2 -1
- package/dist_ts/classes.authstore.js +5 -1
- package/dist_ts/classes.controller.d.ts +8 -0
- package/dist_ts/classes.controller.js +119 -22
- package/dist_ts/classes.controllereventdelivery.d.ts +72 -0
- package/dist_ts/classes.controllereventdelivery.js +233 -0
- package/dist_ts/classes.flexmodels.public.js +4 -1
- package/dist_ts/classes.flexprojectionreader.d.ts +6 -0
- package/dist_ts/classes.flexprojectionreader.js +29 -5
- package/dist_ts/classes.flexservice.d.ts +2 -1
- package/dist_ts/classes.flexservice.js +34 -6
- package/dist_ts/classes.flexstore.d.ts +41 -4
- package/dist_ts/classes.flexstore.js +266 -203
- package/dist_ts/classes.inferencegateway.d.ts +35 -1
- package/dist_ts/classes.inferencegateway.js +86 -26
- package/dist_ts/classes.inferenceservice.d.ts +4 -2
- package/dist_ts/classes.inferenceservice.js +5 -4
- package/dist_ts/classes.proxycontrol.d.ts +58 -4
- package/dist_ts/classes.proxycontrol.js +23 -44
- package/dist_ts/classes.proxycontrolclient.d.ts +15 -5
- package/dist_ts/classes.proxycontrolclient.js +67 -17
- package/dist_ts/classes.proxydaemon.d.ts +22 -3
- package/dist_ts/classes.proxydaemon.js +73 -12
- package/dist_ts/classes.proxyleaseholder.d.ts +43 -14
- package/dist_ts/classes.proxyleaseholder.js +66 -22
- package/dist_ts/classes.proxystore.d.ts +9 -0
- package/dist_ts/classes.proxystore.js +15 -7
- package/dist_ts/classes.ticketnotifier.js +4 -2
- package/dist_ts/classes.ticketstore.d.ts +50 -2
- package/dist_ts/classes.ticketstore.js +195 -78
- package/dist_ts/classes.workercallerbindings.d.ts +66 -0
- package/dist_ts/classes.workercallerbindings.js +211 -0
- package/dist_ts/classes.workercallers.d.ts +63 -2
- package/dist_ts/classes.workercallers.js +430 -65
- package/dist_ts/driver/classes.drivereventrelay.d.ts +13 -1
- package/dist_ts/driver/classes.drivereventrelay.js +99 -6
- package/dist_ts/driver/functions.driverinstructions.d.ts +1 -1
- package/dist_ts/driver/functions.driverinstructions.js +1 -1
- package/dist_ts/driver/functions.drivertools.d.ts +11 -2
- package/dist_ts/driver/functions.drivertools.js +19 -9
- package/dist_ts/fleet/classes.boardpump.d.ts +8 -2
- package/dist_ts/fleet/classes.boardpump.js +38 -20
- package/dist_ts/fleet/classes.ticketeffects.d.ts +17 -2
- package/dist_ts/fleet/classes.ticketeffects.js +16 -10
- package/dist_ts/fleet/classes.workerlaunches.d.ts +12 -5
- package/dist_ts/fleet/classes.workerlaunches.js +25 -19
- package/dist_ts/fleet/classes.workers.d.ts +21 -0
- package/dist_ts/fleet/classes.workers.js +110 -17
- package/dist_ts/fleet/functions.workervalidation.js +2 -2
- package/dist_ts/functions.flexprivatesnapshot.d.ts +102 -0
- package/dist_ts/functions.flexprivatesnapshot.js +461 -0
- package/dist_ts/functions.inferencecli.d.ts +3 -2
- package/dist_ts/functions.inferencecli.js +67 -5
- package/dist_ts/functions.inferencecliarguments.d.ts +6 -2
- package/dist_ts/functions.inferencecliarguments.js +29 -2
- package/dist_ts/functions.inferencelaunch.d.ts +24 -0
- package/dist_ts/functions.inferencelaunch.js +42 -2
- package/dist_ts/functions.mcptickettools.d.ts +3 -0
- package/dist_ts/functions.mcptickettools.js +2 -2
- package/dist_ts/functions.proxycontract.d.ts +11 -0
- package/dist_ts/functions.proxycontract.js +12 -1
- package/dist_ts/functions.proxysocket.d.ts +6 -0
- package/dist_ts/functions.proxysocket.js +46 -0
- package/dist_ts/functions.ticketcli.d.ts +1 -1
- package/dist_ts/functions.ticketcli.js +8 -4
- package/dist_ts/functions.ticketvalidation.d.ts +3 -0
- package/dist_ts/functions.ticketvalidation.js +7 -4
- package/dist_ts/functions.workerprocessproof.d.ts +6 -0
- package/dist_ts/functions.workerprocessproof.js +28 -4
- package/dist_ts/interfaces.flexipc.d.ts +21 -2
- package/dist_ts/interfaces.flexipc.js +33 -16
- package/dist_ts_interfaces/fleetworkers.d.ts +6 -0
- package/dist_ts_interfaces/interfaces.d.ts +1 -1
- package/dist_ts_interfaces/interfaces.js +1 -1
- package/dist_ts_interfaces/requests.tickets.d.ts +8 -12
- package/dist_ts_interfaces/tickets.d.ts +37 -9
- package/dist_ts_interfaces/tickets.js +7 -1
- package/dist_ts_interfaces/workercallers.d.ts +43 -4
- package/package.json +7 -7
- package/readme.md +156 -23
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/aglapi/aglapisurface.document.ts +63 -36
- package/ts/classes.aglhome.ts +6 -0
- package/ts/classes.authstore.ts +4 -0
- package/ts/classes.controller.ts +141 -32
- package/ts/classes.controllereventdelivery.ts +289 -0
- package/ts/classes.flexmodels.public.ts +10 -0
- package/ts/classes.flexprojectionreader.ts +30 -3
- package/ts/classes.flexservice.ts +33 -5
- package/ts/classes.flexstore.ts +381 -246
- package/ts/classes.inferencegateway.ts +104 -23
- package/ts/classes.inferenceservice.ts +6 -3
- package/ts/classes.proxycontrol.ts +76 -39
- package/ts/classes.proxycontrolclient.ts +72 -20
- package/ts/classes.proxydaemon.ts +85 -15
- package/ts/classes.proxyleaseholder.ts +84 -28
- package/ts/classes.proxystore.ts +16 -5
- package/ts/classes.ticketnotifier.ts +3 -1
- package/ts/classes.ticketstore.ts +201 -75
- package/ts/classes.workercallerbindings.ts +147 -0
- package/ts/classes.workercallers.ts +410 -59
- package/ts/driver/classes.drivereventrelay.ts +89 -4
- package/ts/driver/functions.driverinstructions.ts +1 -1
- package/ts/driver/functions.drivertools.ts +22 -8
- package/ts/fleet/classes.boardpump.ts +51 -19
- package/ts/fleet/classes.ticketeffects.ts +25 -11
- package/ts/fleet/classes.workerlaunches.ts +23 -15
- package/ts/fleet/classes.workers.ts +79 -17
- package/ts/fleet/functions.workervalidation.ts +1 -1
- package/ts/functions.flexprivatesnapshot.ts +601 -0
- package/ts/functions.inferencecli.ts +61 -7
- package/ts/functions.inferencecliarguments.ts +32 -1
- package/ts/functions.inferencelaunch.ts +49 -2
- package/ts/functions.mcptickettools.ts +1 -1
- package/ts/functions.proxycontract.ts +12 -0
- package/ts/functions.proxysocket.ts +39 -0
- package/ts/functions.ticketcli.ts +7 -3
- package/ts/functions.ticketvalidation.ts +7 -3
- package/ts/functions.workerprocessproof.ts +27 -4
- package/ts/interfaces.flexipc.ts +50 -21
- package/ts_interfaces/fleetworkers.ts +6 -0
- package/ts_interfaces/interfaces.ts +1 -1
- package/ts_interfaces/requests.tickets.ts +9 -6
- package/ts_interfaces/tickets.ts +32 -1
- package/ts_interfaces/workercallers.ts +32 -4
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements.harnesscontrollerapp.ts +19 -8
- package/ts_web/elements.ticketboard.ts +16 -4
- package/ts_web/settings.general.ts +10 -4
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as plugins from '../plugins.js';
|
|
2
|
-
import { controllerRuntimeIdKey } from '../../ts_interfaces/index.js';
|
|
3
|
-
import type { IFleetWorker, IFleetWorkerProfile, IFleetWorkerJob, IFleetNativeMessageReceipt, TFleetEventKind, TFleetWorkerAction, TFleetWorkerRequest, TFleetWorkerResponse, TFleetWorkerJobAction, IFleetWorkerReport, IFleetWorkerDispatchHolder } from '../../ts_interfaces/fleetworkers.js';
|
|
2
|
+
import { controllerRuntimeIdKey, type IWorkerClaudeJobRequest, type TWorkerClaudeJobObservation } from '../../ts_interfaces/index.js';
|
|
3
|
+
import type { IFleetEvent, IFleetWorker, IFleetWorkerProfile, IFleetWorkerJob, IFleetNativeMessageReceipt, TFleetEventKind, TFleetWorkerAction, TFleetWorkerRequest, TFleetWorkerResponse, TFleetWorkerJobAction, IFleetWorkerReport, IFleetWorkerDispatchHolder } from '../../ts_interfaces/fleetworkers.js';
|
|
4
4
|
import type { IFleetConfiguration, IFleetOperation, IFleetTicketSync } from '../../ts_interfaces/fleet.js';
|
|
5
5
|
import type { ITicketActor } from '../../ts_interfaces/tickets.js';
|
|
6
|
-
import type { FleetTicketEffects } from './classes.ticketeffects.js';
|
|
6
|
+
import type { FleetTicketEffects, IFleetTicketReport } from './classes.ticketeffects.js';
|
|
7
7
|
import type { IControllerSystemMetrics, IControllerFleetWorkerView, IReq_ControllerFleetWorkerRead, IControllerPermission, IControllerQuestion, TControllerPermissionReply } from '../../ts_interfaces/index.js';
|
|
8
8
|
import { FleetWorkerStore, type IFleetWorkerStore, type IFleetWorkerDocument } from './classes.workerstore.js';
|
|
9
9
|
import { FleetEvents } from './classes.events.js';
|
|
@@ -14,6 +14,7 @@ import { FleetDispatchError, fleetMessageDigest, fleetReportMarker, type IFleetW
|
|
|
14
14
|
import { assertFleetWorkerRequest, validateFleetWorkerProfiles } from './functions.workervalidation.js';
|
|
15
15
|
import { readControllerProcessIdentity, controllerProcessIdentityIsLive } from '../classes.processinspection.js';
|
|
16
16
|
import { ticketActorSchema } from '../functions.ticketvalidation.js';
|
|
17
|
+
import { isWorkerCallerProofRefusal, readWorkerProcessSnapshot } from '../functions.workerprocessproof.js';
|
|
17
18
|
|
|
18
19
|
/** A binding that stayed on `workerName` though its native session lives on `nextName` now. */
|
|
19
20
|
export interface IFleetSessionBindingFailure { workerName: string; nextName: string; error: string }
|
|
@@ -80,6 +81,10 @@ export class FleetWorkers {
|
|
|
80
81
|
private lastLoad = 0;
|
|
81
82
|
private readonly controllerId = plugins.crypto.randomUUID();
|
|
82
83
|
private holder?: Promise<IFleetWorkerDispatchHolder>;
|
|
84
|
+
/** The chain the caller job re-proofs read their inventories on, one at a time. */
|
|
85
|
+
private callerJobs: Promise<unknown> = Promise.resolve();
|
|
86
|
+
/** Set once the controller began to stop: no new worker job is admitted. */
|
|
87
|
+
private admissionClosed = false;
|
|
83
88
|
constructor(private readonly options: IFleetWorkersOptions = {}) {
|
|
84
89
|
this.store = options.store ?? new FleetWorkerStore(); this.events = options.events ?? new FleetEvents();
|
|
85
90
|
this.backends = options.backends ?? { claude: new FleetClaudeWorkers(this.abort.signal, undefined, undefined, options.callers, options.claudeReleases),
|
|
@@ -110,15 +115,21 @@ export class FleetWorkers {
|
|
|
110
115
|
try {
|
|
111
116
|
const backend = this.backends[worker.harness], observed = backend.observed?.(worker), excerpt = backend.observedExcerpt?.(worker);
|
|
112
117
|
const events = await this.backends[worker.harness].poll(worker, worker.profile);
|
|
118
|
+
const ticketed = this.options.ticketEffects && worker.ticketKey && worker.ticketActor;
|
|
113
119
|
for (const { nativeId: _nativeId, ...event } of events) {
|
|
114
|
-
|
|
115
|
-
if (
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
120
|
+
const published = { ...event, workerId: worker.id, workerName: worker.name, ...(worker.ticketKey ? { ticketKey: worker.ticketKey } : {}) };
|
|
121
|
+
if (ticketed && event.kind === 'worker.report.mid_turn' && event.text && event.reportId) {
|
|
122
|
+
await this.reportTicket(owner, worker, { reportId: event.reportId, text: event.text, truncated: event.truncated ?? false }, published);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (ticketed && event.kind === 'worker.turn.ended') {
|
|
126
|
+
let report: IFleetWorkerReport;
|
|
127
|
+
// The turn's end is published whether or not its report can be observed.
|
|
128
|
+
try { report = await this.backends[worker.harness].observe(worker, worker.profile); }
|
|
129
|
+
catch (error) { this.events.publish(published, owner); throw error; }
|
|
130
|
+
if (report.reportId && report.text.trim()) { await this.reportTicket(owner, worker, report, published); continue; }
|
|
121
131
|
}
|
|
132
|
+
this.events.publish(published, owner);
|
|
122
133
|
}
|
|
123
134
|
if (this.options.ticketEffects && worker.ticketKey && worker.ticketActor) {
|
|
124
135
|
const baseline = `${worker.id}:${worker.nativeId}:${worker.ticketKey}`;
|
|
@@ -157,8 +168,9 @@ export class FleetWorkers {
|
|
|
157
168
|
let report: IFleetWorkerReport;
|
|
158
169
|
try { report = await backend.observe(worker, worker.profile); } catch { return; }
|
|
159
170
|
if (!report.reportId || !report.text.trim() || !fleetReportMarker.test(report.text)) return;
|
|
160
|
-
|
|
161
|
-
if (this.options.ticketEffects && worker.ticketKey && worker.ticketActor) await this.reportTicket(owner, worker, report);
|
|
171
|
+
const event: Omit<IFleetEvent, 'id' | 'occurredAt'> = { kind: 'worker.report.mid_turn', workerId: worker.id, workerName: worker.name, ...ticket, reportId: report.reportId, text: report.text, truncated: report.truncated, status: report.status };
|
|
172
|
+
if (this.options.ticketEffects && worker.ticketKey && worker.ticketActor) await this.reportTicket(owner, worker, report, event);
|
|
173
|
+
else this.events.publish(event, owner);
|
|
162
174
|
}
|
|
163
175
|
public releaseEvent(operation: IFleetOperation, owner: string, repo?: string): void {
|
|
164
176
|
if (operation.operation !== 'release' || !['succeeded', 'failed'].includes(operation.state)) return;
|
|
@@ -170,11 +182,16 @@ export class FleetWorkers {
|
|
|
170
182
|
this.events.publish({ kind: ticketSync.state === 'applied' ? 'ticket.applied' : ticketSync.state === 'failed' ? 'ticket.failed' : 'ticket.unknown',
|
|
171
183
|
ticketKey, ticketSync, ...(workerId ? { workerId } : {}), ...(operationId ? { operationId } : {}) }, owner);
|
|
172
184
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
185
|
+
/**
|
|
186
|
+
* Comments the report on the worker's ticket first, then publishes `event`, naming the comment that holds its whole
|
|
187
|
+
* text when the board wrote it, and then the comment's ticket event.
|
|
188
|
+
*/
|
|
189
|
+
private async reportTicket(owner: string, worker: IFleetWorker, report: { reportId?: string; text: string; truncated: boolean }, event?: Omit<IFleetEvent, 'id' | 'occurredAt'>): Promise<IFleetTicketSync> {
|
|
190
|
+
let written: IFleetTicketReport;
|
|
191
|
+
try { written = await this.options.ticketEffects!.report(owner, worker.ticketKey!, worker.ticketActor!, worker, report, this.abort.signal); }
|
|
192
|
+
catch (error) { written = { sync: { state: 'unknown', effects: [], error: this.error(error) } }; }
|
|
193
|
+
if (event) this.events.publish({ ...event, ...(written.commentId ? { commentId: written.commentId } : {}) }, owner);
|
|
194
|
+
this.ticketEvent(owner, worker.ticketKey!, written.sync, worker.id); return written.sync;
|
|
178
195
|
}
|
|
179
196
|
/** `reportsTo` names the direct report whose session asks; a worker it starts or adopts reports to it. */
|
|
180
197
|
public async execute<T extends TFleetWorkerAction>(action: T, request: TFleetWorkerRequest<T>, configuration: IFleetConfiguration, owner: string, signal?: AbortSignal, actor?: ITicketActor, reportsTo?: string): Promise<TFleetWorkerResponse<T>> {
|
|
@@ -298,11 +315,43 @@ export class FleetWorkers {
|
|
|
298
315
|
public async nativeAgents(home: string | undefined, maxAgeMs: number): Promise<IFleetNativeAgent[]> {
|
|
299
316
|
return await this.backends.claude.inventory?.(home, plugins.os.homedir(), maxAgeMs) ?? [];
|
|
300
317
|
}
|
|
318
|
+
/**
|
|
319
|
+
* What a fresh inventory shows of the Claude background job a worker's caller launch is bound to, for the controller
|
|
320
|
+
* to prove the job's next process. One read at a time, however many bridges ask.
|
|
321
|
+
*/
|
|
322
|
+
public observeCallerJob(request: IWorkerClaudeJobRequest): Promise<TWorkerClaudeJobObservation> {
|
|
323
|
+
const task = this.callerJobs.then(() => this.readCallerJob(request));
|
|
324
|
+
this.callerJobs = task.then(() => undefined, () => undefined);
|
|
325
|
+
return task;
|
|
326
|
+
}
|
|
327
|
+
private async readCallerJob(request: IWorkerClaudeJobRequest): Promise<TWorkerClaudeJobObservation> {
|
|
328
|
+
if (this.abort.signal.aborted) return { state: 'unproven', reason: 'the fleet is closing' };
|
|
329
|
+
if (!request.workerId.startsWith(`${request.projectId}:`)) return { state: 'ended', reason: 'its launch names no worker of its project' };
|
|
330
|
+
let worker: IFleetWorker | undefined;
|
|
331
|
+
try { worker = (await this.store.list(request.projectId)).find((doc) => doc.id === request.workerId)?.worker; }
|
|
332
|
+
catch (error) { return { state: 'unproven', reason: `the fleet registry could not be read (${this.error(error)})` }; }
|
|
333
|
+
if (!worker || worker.state === 'archived') return { state: 'ended', reason: `fleet worker ${request.workerId} is ${worker ? 'archived' : 'gone'}` };
|
|
334
|
+
if (worker.harness !== 'claude' || worker.nativeId !== request.nativeSessionId) return { state: 'ended', reason: 'its worker continues in another session' };
|
|
335
|
+
let agents: IFleetNativeAgent[] | undefined;
|
|
336
|
+
try { agents = await this.backends.claude.inventory?.(worker.profile.home, plugins.os.homedir(), 0); }
|
|
337
|
+
catch (error) { return { state: 'unproven', reason: `the Claude inventory could not be read (${this.error(error)})` }; }
|
|
338
|
+
const listed = (agents ?? []).filter((agent) => agent.sessionId === request.nativeSessionId);
|
|
339
|
+
if (listed.length !== 1) return { state: 'unproven', reason: `the Claude inventory lists its session ${listed.length ? 'more than once' : 'nowhere'}` };
|
|
340
|
+
const agent = listed[0]!;
|
|
341
|
+
if (agent.kind !== 'background' || agent.id !== request.jobId) return { state: 'ended', reason: 'its session continues as another Claude job' };
|
|
342
|
+
if (agent.pid === undefined) return { state: 'settled' };
|
|
343
|
+
try { return { state: 'running', process: { jobId: request.jobId, pid: agent.pid, startTicks: (await readWorkerProcessSnapshot(agent.pid)).startTicks } }; }
|
|
344
|
+
catch (error) {
|
|
345
|
+
if (!isWorkerCallerProofRefusal(error)) throw error;
|
|
346
|
+
return { state: 'unproven', reason: 'the process of its Claude job could not be read' };
|
|
347
|
+
}
|
|
348
|
+
}
|
|
301
349
|
/** The newest root threads on the host's shared Codex app-server, read at most `maxAgeMs` ago. */
|
|
302
350
|
public async nativeThreads(maxAgeMs: number): Promise<IFleetNativeThread[]> {
|
|
303
351
|
return await this.backends.codex.threads?.(plugins.os.homedir(), maxAgeMs) ?? [];
|
|
304
352
|
}
|
|
305
353
|
private admitJob(): void {
|
|
354
|
+
if (this.admissionClosed || this.abort.signal.aborted) throw new Error('The fleet is closing and admits no new worker job.');
|
|
306
355
|
if (this.jobs.size < 512) return;
|
|
307
356
|
for (const [id, job] of this.jobs) if (['succeeded', 'failed'].includes(job.snapshot.state)) { this.jobs.delete(id); break; }
|
|
308
357
|
if (this.jobs.size >= 512) throw new Error('Fleet worker job capacity reached.');
|
|
@@ -779,6 +828,19 @@ export class FleetWorkers {
|
|
|
779
828
|
throw error;
|
|
780
829
|
}
|
|
781
830
|
}
|
|
831
|
+
/**
|
|
832
|
+
* Admits no new worker job and lets the running ones finish, for at most `waitMs`; the ones still running then are
|
|
833
|
+
* aborted and settle. The controller calls it before it tears down the caller hooks the jobs prepare, bind and
|
|
834
|
+
* revoke launches through, so no job meets them gone.
|
|
835
|
+
*/
|
|
836
|
+
public async closeAdmission(waitMs = 10_000): Promise<void> {
|
|
837
|
+
this.admissionClosed = true;
|
|
838
|
+
const settled = Promise.allSettled([...this.jobs.values()].map((job) => job.completion));
|
|
839
|
+
let timer: NodeJS.Timeout | undefined;
|
|
840
|
+
const waited = await Promise.race([settled.then(() => true), new Promise<false>((resolve) => { timer = setTimeout(() => resolve(false), waitMs); })]);
|
|
841
|
+
if (timer) clearTimeout(timer);
|
|
842
|
+
if (!waited) { this.abort.abort(); await settled; }
|
|
843
|
+
}
|
|
782
844
|
public async close(): Promise<void> {
|
|
783
845
|
if (this.pollTimer) clearInterval(this.pollTimer); this.abort.abort(); this.events.close(); this.viewListeners.clear();
|
|
784
846
|
await Promise.allSettled([...this.jobs.values()].map((job) => job.completion)); await Promise.allSettled([this.polling]);
|
|
@@ -117,7 +117,7 @@ const job = plugins.z.object({ id: text, action: plugins.z.enum(['start', 'adopt
|
|
|
117
117
|
const event = plugins.z.object({ id: plugins.z.number().int().positive(),
|
|
118
118
|
kind: plugins.z.enum(['worker.changed', 'worker.turn.ended', 'worker.report.mid_turn', 'worker.reaped', 'worker.credential.failed', 'worker.observation.failed', 'release.finished', 'release.failed', 'ticket.applied', 'ticket.failed', 'ticket.unknown',
|
|
119
119
|
'ticket.changed', 'ticket.notified', 'ticket.notification.failed', 'ticket.stalled', 'harness.release.discovered', 'host.load']),
|
|
120
|
-
occurredAt: text, workerId: text.optional(), workerName: name.optional(), sessionId: text.optional(), reportId: text.optional(), turnId: text.optional(), status: text.optional(),
|
|
120
|
+
occurredAt: text, workerId: text.optional(), workerName: name.optional(), sessionId: text.optional(), reportId: text.optional(), commentId: text.optional(), turnId: text.optional(), status: text.optional(),
|
|
121
121
|
ticketKey: ticketKey.optional(),
|
|
122
122
|
ticketSync: ticketSync.optional(),
|
|
123
123
|
text: plugins.z.string().max(64 * 1024).optional(), truncated: plugins.z.boolean().optional(), error: plugins.z.string().max(4096).optional(),
|