agl 40.6.0 → 41.0.1

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 (90) hide show
  1. package/changelog.md +40 -0
  2. package/dist_serve/bundle.js +3514 -3357
  3. package/dist_serve/bundle.js.map +2 -2
  4. package/dist_serve/bundle.js.third-party-notices.json +58 -32
  5. package/dist_serve/bundle.js.third-party-notices.txt +108 -33
  6. package/dist_ts/00_commitinfo_data.js +1 -1
  7. package/dist_ts/aglapi/aglapisurface.document.js +64 -37
  8. package/dist_ts/classes.controller.d.ts +8 -0
  9. package/dist_ts/classes.controller.js +110 -22
  10. package/dist_ts/classes.controllereventdelivery.d.ts +72 -0
  11. package/dist_ts/classes.controllereventdelivery.js +233 -0
  12. package/dist_ts/classes.flexmodels.public.js +4 -1
  13. package/dist_ts/classes.flexprojectionreader.d.ts +6 -0
  14. package/dist_ts/classes.flexprojectionreader.js +29 -5
  15. package/dist_ts/classes.flexservice.d.ts +2 -1
  16. package/dist_ts/classes.flexservice.js +34 -6
  17. package/dist_ts/classes.flexstore.d.ts +41 -4
  18. package/dist_ts/classes.flexstore.js +266 -203
  19. package/dist_ts/classes.mcpreexec.js +4 -4
  20. package/dist_ts/classes.ticketnotifier.js +4 -2
  21. package/dist_ts/classes.ticketstore.d.ts +50 -2
  22. package/dist_ts/classes.ticketstore.js +195 -78
  23. package/dist_ts/classes.workercallers.d.ts +2 -0
  24. package/dist_ts/classes.workercallers.js +11 -8
  25. package/dist_ts/driver/classes.drivereventrelay.d.ts +13 -1
  26. package/dist_ts/driver/classes.drivereventrelay.js +99 -6
  27. package/dist_ts/driver/functions.driverinstructions.d.ts +1 -1
  28. package/dist_ts/driver/functions.driverinstructions.js +1 -1
  29. package/dist_ts/driver/functions.drivertools.d.ts +11 -2
  30. package/dist_ts/driver/functions.drivertools.js +19 -9
  31. package/dist_ts/fleet/classes.boardpump.d.ts +8 -2
  32. package/dist_ts/fleet/classes.boardpump.js +38 -20
  33. package/dist_ts/fleet/classes.ticketeffects.d.ts +17 -2
  34. package/dist_ts/fleet/classes.ticketeffects.js +16 -10
  35. package/dist_ts/fleet/classes.workers.d.ts +4 -0
  36. package/dist_ts/fleet/classes.workers.js +37 -17
  37. package/dist_ts/fleet/functions.workervalidation.js +2 -2
  38. package/dist_ts/functions.flexprivatesnapshot.d.ts +102 -0
  39. package/dist_ts/functions.flexprivatesnapshot.js +461 -0
  40. package/dist_ts/functions.mcptickettools.d.ts +3 -0
  41. package/dist_ts/functions.mcptickettools.js +2 -2
  42. package/dist_ts/functions.ticketcli.d.ts +1 -1
  43. package/dist_ts/functions.ticketcli.js +8 -4
  44. package/dist_ts/functions.ticketvalidation.d.ts +3 -0
  45. package/dist_ts/functions.ticketvalidation.js +7 -4
  46. package/dist_ts/functions.workerprocessproof.d.ts +12 -3
  47. package/dist_ts/functions.workerprocessproof.js +17 -6
  48. package/dist_ts/interfaces.flexipc.d.ts +21 -2
  49. package/dist_ts/interfaces.flexipc.js +33 -16
  50. package/dist_ts_interfaces/fleetworkers.d.ts +6 -0
  51. package/dist_ts_interfaces/interfaces.d.ts +1 -1
  52. package/dist_ts_interfaces/interfaces.js +1 -1
  53. package/dist_ts_interfaces/requests.tickets.d.ts +8 -12
  54. package/dist_ts_interfaces/tickets.d.ts +37 -9
  55. package/dist_ts_interfaces/tickets.js +7 -1
  56. package/package.json +7 -7
  57. package/readme.md +62 -15
  58. package/ts/00_commitinfo_data.ts +1 -1
  59. package/ts/aglapi/aglapisurface.document.ts +63 -36
  60. package/ts/classes.controller.ts +132 -32
  61. package/ts/classes.controllereventdelivery.ts +289 -0
  62. package/ts/classes.flexmodels.public.ts +10 -0
  63. package/ts/classes.flexprojectionreader.ts +30 -3
  64. package/ts/classes.flexservice.ts +33 -5
  65. package/ts/classes.flexstore.ts +381 -246
  66. package/ts/classes.mcpreexec.ts +3 -3
  67. package/ts/classes.ticketnotifier.ts +3 -1
  68. package/ts/classes.ticketstore.ts +201 -75
  69. package/ts/classes.workercallers.ts +12 -7
  70. package/ts/driver/classes.drivereventrelay.ts +89 -4
  71. package/ts/driver/functions.driverinstructions.ts +1 -1
  72. package/ts/driver/functions.drivertools.ts +22 -8
  73. package/ts/fleet/classes.boardpump.ts +51 -19
  74. package/ts/fleet/classes.ticketeffects.ts +25 -11
  75. package/ts/fleet/classes.workers.ts +28 -16
  76. package/ts/fleet/functions.workervalidation.ts +1 -1
  77. package/ts/functions.flexprivatesnapshot.ts +601 -0
  78. package/ts/functions.mcptickettools.ts +1 -1
  79. package/ts/functions.ticketcli.ts +7 -3
  80. package/ts/functions.ticketvalidation.ts +7 -3
  81. package/ts/functions.workerprocessproof.ts +17 -3
  82. package/ts/interfaces.flexipc.ts +50 -21
  83. package/ts_interfaces/fleetworkers.ts +6 -0
  84. package/ts_interfaces/interfaces.ts +1 -1
  85. package/ts_interfaces/requests.tickets.ts +9 -6
  86. package/ts_interfaces/tickets.ts +32 -1
  87. package/ts_web/00_commitinfo_data.ts +1 -1
  88. package/ts_web/elements.harnesscontrollerapp.ts +19 -8
  89. package/ts_web/elements.ticketboard.ts +16 -4
  90. package/ts_web/settings.general.ts +10 -4
@@ -304,6 +304,12 @@ export interface IFleetEvent {
304
304
  /** The native session (`harness:nativeId`) a ticket notice addressed. */
305
305
  sessionId?: string;
306
306
  reportId?: string;
307
+ /**
308
+ * The comment on `ticketKey` that holds this event's whole text, by the id the ticket board returned: a worker's report
309
+ * the fleet commented (`worker.report.mid_turn`, `worker.turn.ended`), the board pump's stall notice, a commented
310
+ * `ticket.changed`. Read it with `ticket_get` and `commentId`. Absent when no comment holds the text.
311
+ */
312
+ commentId?: string;
307
313
  turnId?: string;
308
314
  status?: string;
309
315
  text?: string;
@@ -1,6 +1,6 @@
1
1
  import type { ILiveBrowserDialog, ILiveBrowserDialogResponse, ILiveVideoOffer, ILiveVideoDescription, ILiveVideoStatistics, ILiveVideoAcceleration } from '@push.rocks/smartbrowser/web';
2
2
  import type { IControllerBrowserPaintSource, IControllerBrowserPresentationState, TControllerBrowserPaintAvailability, TControllerBrowserPaintTermination } from './browserpaint.js';
3
- export declare const controllerProtocolVersion: 45;
3
+ export declare const controllerProtocolVersion: 46;
4
4
  export declare const controllerUpgradeManagementVersion: 2;
5
5
  export declare const controllerPackageName: 'agl';
6
6
  /** The systemd user unit `agl service install` writes; a controller it runs reports it in its status. */
@@ -1,4 +1,4 @@
1
- export const controllerProtocolVersion = 45;
1
+ export const controllerProtocolVersion = 46;
2
2
  export const controllerUpgradeManagementVersion = 2;
3
3
  export const controllerPackageName = 'agl';
4
4
  /** The systemd user unit `agl service install` writes; a controller it runs reports it in its status. */
@@ -1,5 +1,5 @@
1
1
  import type * as plugins from './plugins.js';
2
- import type { ITicket, ITicketActivity, ITicketAnswer, ITicketAsk, ITicketBoard, ITicketChanges, ITicketComment, ITicketCreate, ITicketFilters, ITicketMove, ITicketQuestion, TTicketLink, TTicketOperation, TTicketReferenceContent, TTicketRequest, TTicketResponse } from './tickets.js';
2
+ import type { ITicket, ITicketAnswer, ITicketAsk, ITicketBoard, ITicketChanges, ITicketComment, ITicketCreate, ITicketDetail, ITicketFilters, ITicketGet, ITicketMove, ITicketQuestion, TTicketLink, TTicketOperation, TTicketReferenceContent, TTicketRequest, TTicketResponse } from './tickets.js';
3
3
  export declare const controllerMcpTicketMethods: readonly ['agl.mcp.ticket.list', 'agl.mcp.ticket.board', 'agl.mcp.ticket.search', 'agl.mcp.ticket.get', 'agl.mcp.ticket.comments', 'agl.mcp.ticket.create', 'agl.mcp.ticket.update', 'agl.mcp.ticket.move', 'agl.mcp.ticket.comment', 'agl.mcp.ticket.link', 'agl.mcp.ticket.ask', 'agl.mcp.ticket.answer'];
4
4
  export type TControllerMcpTicketMethod = (typeof controllerMcpTicketMethods)[number];
5
5
  export type TControllerTicketRequest<TMethod extends TTicketOperation> = {
@@ -54,22 +54,18 @@ export interface IReq_ControllerMcpTicketSearch extends plugins.typedrequestInte
54
54
  };
55
55
  }
56
56
  /**
57
- * Reads a ticket by its `AGL-<n>` key, with its Markdown comments, source, links, questions and
58
- * their answers, and its complete activity log.
57
+ * Reads a ticket by its `AGL-<n>` key with its source, links, all its questions and their answers,
58
+ * and the newest page of its history (up to `limit` entries, default 50, at most 500, within 256 KiB), oldest first: the
59
+ * activity entries and the Markdown comments they name, a `commented` entry naming its comment by
60
+ * id. `historyBefore` is present while older history exists; pass it as `before` for the next page.
61
+ * `commentId` reads that one comment instead (`comments: [it]`, `activity: []`), without `before` or `limit`.
59
62
  */
60
63
  export interface IReq_ControllerMcpTicketGet extends plugins.typedrequestInterfaces.implementsTR<TControllerMcpTicketRequest<'get'>, IReq_ControllerMcpTicketGet> {
61
64
  method: 'agl.mcp.ticket.get';
62
- request: {
63
- ticketId: string;
64
- } & {
65
+ request: ITicketGet & {
65
66
  ownerToken?: string;
66
67
  };
67
- response: {
68
- ticket: ITicket;
69
- comments: ITicketComment[];
70
- activity: ITicketActivity[];
71
- questions: ITicketQuestion[];
72
- };
68
+ response: ITicketDetail;
73
69
  }
74
70
  /** Reads a ticket's comments. */
75
71
  export interface IReq_ControllerMcpTicketComments extends plugins.typedrequestInterfaces.implementsTR<TControllerMcpTicketRequest<'comments'>, IReq_ControllerMcpTicketComments> {
@@ -218,6 +218,40 @@ export interface ITicketMove {
218
218
  columnId: TTicketColumn;
219
219
  beforeTicketId?: string;
220
220
  }
221
+ /**
222
+ * How many history entries one `get` returns unless it names `limit`, the most it may name, and the bytes a page holds
223
+ * at most (its entries plus the comments they name, serialized; a page holds at least one entry). The budget wins over `limit`.
224
+ */
225
+ export declare const ticketHistoryPage: {
226
+ readonly default: 50;
227
+ readonly maximum: 500;
228
+ readonly bytes: number;
229
+ };
230
+ /** A ticket and one page of its history: the newest entries, or those older than the entry `before` names, within `ticketHistoryPage`. */
231
+ export interface ITicketGet {
232
+ ticketId: string;
233
+ /** An activity id, as `historyBefore` returned it: the page holds only older entries. */
234
+ before?: string;
235
+ /** Entries on the page, 1 to 500 (`ticketHistoryPage.maximum`); 50 (`ticketHistoryPage.default`) when absent. */
236
+ limit?: number;
237
+ /**
238
+ * One comment of this ticket, by the id an activity entry or a fleet event names: the response holds the ticket, its
239
+ * questions and that comment alone (`comments: [it]`, `activity: []`, no `historyBefore`). Excludes `before` and `limit`.
240
+ */
241
+ commentId?: string;
242
+ }
243
+ /**
244
+ * A ticket, all its questions and one page of its history, oldest first. `activity` is the page; `comments` are the
245
+ * comments its `commented` entries name, whose `changes.comment` holds only `{ after: { id } }` here (the stored
246
+ * entry keeps the whole comment). `historyBefore` is present while older entries exist: pass it as `before`.
247
+ */
248
+ export interface ITicketDetail {
249
+ ticket: ITicket;
250
+ comments: ITicketComment[];
251
+ activity: ITicketActivity[];
252
+ questions: ITicketQuestion[];
253
+ historyBefore?: string;
254
+ }
221
255
  export interface ITicketBoard {
222
256
  revision: number;
223
257
  columns: {
@@ -250,15 +284,8 @@ export interface ITicketOperations {
250
284
  };
251
285
  };
252
286
  get: {
253
- request: {
254
- ticketId: string;
255
- };
256
- response: {
257
- ticket: ITicket;
258
- comments: ITicketComment[];
259
- activity: ITicketActivity[];
260
- questions: ITicketQuestion[];
261
- };
287
+ request: ITicketGet;
288
+ response: ITicketDetail;
262
289
  };
263
290
  comments: {
264
291
  request: {
@@ -369,6 +396,7 @@ export declare const ticketErrorMessages: {
369
396
  readonly ticket_ask_forbidden: 'Workers may ask questions only on tickets assigned to their verified session.';
370
397
  readonly ticket_answer_forbidden: 'Only the owner or the driver may answer ticket questions.';
371
398
  readonly ticket_question_not_found: 'The requested question does not exist on this ticket.';
399
+ readonly ticket_comment_not_found: 'The requested comment does not exist on this ticket.';
372
400
  readonly ticket_question_answered: 'The question already has a different answer; a second answer is refused. Ask a new question instead.';
373
401
  readonly ticket_answer_invalid: 'An answer chooses existing option ids (one unless multiSelect) and/or gives free text where the question allows it.';
374
402
  };
@@ -43,6 +43,11 @@ export const ticketAnswerFromCard = (questionArg, answersArg) => {
43
43
  return { choices: questionArg.options.filter((optionArg) => choices.includes(optionArg.id)).map((optionArg) => optionArg.id),
44
44
  ...(texts.length ? { text: texts.join('\n\n') } : {}) };
45
45
  };
46
+ /**
47
+ * How many history entries one `get` returns unless it names `limit`, the most it may name, and the bytes a page holds
48
+ * at most (its entries plus the comments they name, serialized; a page holds at least one entry). The budget wins over `limit`.
49
+ */
50
+ export const ticketHistoryPage = { default: 50, maximum: 500, bytes: 256 * 1024 };
46
51
  export const ticketErrorMessages = {
47
52
  ticket_revision_conflict: 'The ticket changed since editing began. Reload it before editing again.',
48
53
  ticket_identity_required: 'A verified MCP caller is required for this ticket operation. Unidentified callers may only list or get tickets.',
@@ -59,9 +64,10 @@ export const ticketErrorMessages = {
59
64
  ticket_ask_forbidden: 'Workers may ask questions only on tickets assigned to their verified session.',
60
65
  ticket_answer_forbidden: 'Only the owner or the driver may answer ticket questions.',
61
66
  ticket_question_not_found: 'The requested question does not exist on this ticket.',
67
+ ticket_comment_not_found: 'The requested comment does not exist on this ticket.',
62
68
  ticket_question_answered: 'The question already has a different answer; a second answer is refused. Ask a new question instead.',
63
69
  ticket_answer_invalid: 'An answer chooses existing option ids (one unless multiSelect) and/or gives free text where the question allows it.',
64
70
  };
65
71
  export const ticketClientErrorMessages = Object.fromEntries(Object.entries(ticketErrorMessages)
66
72
  .map(([codeArg, messageArg]) => [codeArg.toUpperCase(), messageArg]));
67
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGlja2V0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzX2ludGVyZmFjZXMvdGlja2V0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxNQUFNLENBQUMsTUFBTSxhQUFhLEdBQUc7SUFDM0IsU0FBUyxFQUFFLE9BQU8sRUFBRSxhQUFhLEVBQUUsYUFBYSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsVUFBVTtDQUN4RSxDQUFDO0FBaURYLHNGQUFzRjtBQUN0RixNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBRyxDQUFDLGNBQWMsQ0FBVSxDQUFDO0FBRTFELE1BQU0sQ0FBQyxNQUFNLGlCQUFpQixHQUFHLENBQUMsUUFBZ0IsRUFBZ0MsRUFBRSxDQUFDLENBQ2xGLGdCQUFzQyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FDM0QsQ0FBQztBQUtGLE1BQU0sQ0FBQyxNQUFNLDBCQUEwQixHQUFHLENBQUMsUUFBaUIsRUFBdUMsRUFBRTtJQUNuRyxJQUFJLE9BQU8sUUFBUSxLQUFLLFFBQVEsSUFBSSxRQUFRLEtBQUssSUFBSTtRQUFFLE9BQU8sU0FBUyxDQUFDO0lBQ3hFLE1BQU0sS0FBSyxHQUFHLFFBQTRDLENBQUM7SUFDM0QsT0FBTyxLQUFLLENBQUMsSUFBSSxLQUFLLDBCQUEwQixJQUFJLE1BQU0sQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxJQUFJLEtBQUssQ0FBQyxlQUFnQixJQUFJLENBQUM7UUFDNUgsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLDBCQUEwQixFQUFFLGVBQWUsRUFBRSxLQUFLLENBQUMsZUFBZ0IsRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDaEcsQ0FBQyxDQUFDO0FBMkVGLDhGQUE4RjtBQUM5RixNQUFNLENBQUMsTUFBTSx5QkFBeUIsR0FBRyxDQUFDLFdBQTRCLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDMUUsRUFBRSxFQUFFLFdBQVcsQ0FBQyxFQUFFO0lBQ2xCLElBQUksRUFBRSxVQUFtQjtJQUN6QixRQUFRLEVBQUUsV0FBVyxDQUFDLFFBQVE7SUFDOUIsT0FBTyxFQUFFLFdBQVcsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsR0FBRyxDQUFDLFdBQVcsS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxXQUFXLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNoSSxXQUFXLEVBQUUsV0FBVyxDQUFDLFdBQVc7SUFDcEMsV0FBVyxFQUFFLFdBQVcsQ0FBQyxXQUFXO0lBQ3BDLFNBQVMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUM7SUFDNUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ3ZCLFFBQVEsRUFBRSxDQUFDLEdBQUcsV0FBVyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQUMsU0FBUyxDQUFDLEVBQUUsS0FBSyxTQUFTLENBQUMsRUFBRSxLQUFLLElBQUksU0FBUyxDQUFDO1lBQ2xKLEdBQUcsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDOUUsV0FBVyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUM7S0FDdkQsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0NBQ1IsQ0FBQyxDQUFDO0FBQ0g7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQUcsQ0FBQyxXQUE0QixFQUFFLFVBQTZCLEVBQTJDLEVBQUU7SUFDM0ksTUFBTSxPQUFPLEdBQWEsRUFBRSxDQUFDO0lBQzdCLE1BQU0sS0FBSyxHQUFhLEVBQUUsQ0FBQztJQUMzQixLQUFLLE1BQU0sTUFBTSxJQUFJLFVBQVUsRUFBRSxDQUFDO1FBQ2hDLE1BQU0sTUFBTSxHQUFHLFdBQVcsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxTQUFTLENBQUMsS0FBSyxLQUFLLE1BQU0sQ0FBQyxDQUFDO1FBQ25GLElBQUksTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1lBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7O1lBQy9ELEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDMUIsQ0FBQztJQUNELE9BQU8sRUFBRSxPQUFPLEVBQUUsV0FBVyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxTQUFTLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1FBQzFILEdBQUcsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7QUFDNUQsQ0FBQyxDQUFDO0FBMkVGLE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFHO0lBQ2pDLHdCQUF3QixFQUFFLHlFQUF5RTtJQUNuRyx3QkFBd0IsRUFBRSxpSEFBaUg7SUFDM0ksZ0JBQWdCLEVBQUUsc0NBQXNDO0lBQ3hELG1CQUFtQixFQUFFLDZFQUE2RTtJQUNsRyxvQkFBb0IsRUFBRSw4SEFBOEg7SUFDcEosNEJBQTRCLEVBQUUsK0NBQStDO0lBQzdFLDJCQUEyQixFQUFFLDhDQUE4QztJQUMzRSw2QkFBNkIsRUFBRSwyREFBMkQ7SUFDMUYsc0JBQXNCLEVBQUUsbUNBQW1DO0lBQzNELHFCQUFxQixFQUFFLGtGQUFrRjtJQUN6RywwQkFBMEIsRUFBRSxxRUFBcUU7SUFDakcscUJBQXFCLEVBQUUsZ0ZBQWdGO0lBQ3ZHLG9CQUFvQixFQUFFLCtFQUErRTtJQUNyRyx1QkFBdUIsRUFBRSwyREFBMkQ7SUFDcEYseUJBQXlCLEVBQUUsdURBQXVEO0lBQ2xGLHdCQUF3QixFQUFFLHNHQUFzRztJQUNoSSxxQkFBcUIsRUFBRSxxSEFBcUg7Q0FDcEksQ0FBQztBQUVYLE1BQU0sQ0FBQyxNQUFNLHlCQUF5QixHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsQ0FBQztLQUM1RixHQUFHLENBQUMsQ0FBQyxDQUFDLE9BQU8sRUFBRSxVQUFVLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLEVBQUUsVUFBVSxDQUFDLENBQUMsQ0FBMkMsQ0FBQyJ9
73
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGlja2V0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzX2ludGVyZmFjZXMvdGlja2V0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxNQUFNLENBQUMsTUFBTSxhQUFhLEdBQUc7SUFDM0IsU0FBUyxFQUFFLE9BQU8sRUFBRSxhQUFhLEVBQUUsYUFBYSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsVUFBVTtDQUN4RSxDQUFDO0FBaURYLHNGQUFzRjtBQUN0RixNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBRyxDQUFDLGNBQWMsQ0FBVSxDQUFDO0FBRTFELE1BQU0sQ0FBQyxNQUFNLGlCQUFpQixHQUFHLENBQUMsUUFBZ0IsRUFBZ0MsRUFBRSxDQUFDLENBQ2xGLGdCQUFzQyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FDM0QsQ0FBQztBQUtGLE1BQU0sQ0FBQyxNQUFNLDBCQUEwQixHQUFHLENBQUMsUUFBaUIsRUFBdUMsRUFBRTtJQUNuRyxJQUFJLE9BQU8sUUFBUSxLQUFLLFFBQVEsSUFBSSxRQUFRLEtBQUssSUFBSTtRQUFFLE9BQU8sU0FBUyxDQUFDO0lBQ3hFLE1BQU0sS0FBSyxHQUFHLFFBQTRDLENBQUM7SUFDM0QsT0FBTyxLQUFLLENBQUMsSUFBSSxLQUFLLDBCQUEwQixJQUFJLE1BQU0sQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxJQUFJLEtBQUssQ0FBQyxlQUFnQixJQUFJLENBQUM7UUFDNUgsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLDBCQUEwQixFQUFFLGVBQWUsRUFBRSxLQUFLLENBQUMsZUFBZ0IsRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDaEcsQ0FBQyxDQUFDO0FBMkVGLDhGQUE4RjtBQUM5RixNQUFNLENBQUMsTUFBTSx5QkFBeUIsR0FBRyxDQUFDLFdBQTRCLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDMUUsRUFBRSxFQUFFLFdBQVcsQ0FBQyxFQUFFO0lB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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agl",
3
- "version": "40.6.0",
3
+ "version": "41.0.1",
4
4
  "controllerUpgradeManagementVersion": 2,
5
5
  "private": false,
6
6
  "description": "Agent Gateway Layer for OpenCode, FlexHarness, and Codex sessions",
@@ -24,7 +24,7 @@
24
24
  "@api.global/typedsocket": "8.10.0",
25
25
  "@apiclient.xyz/docker": "10.1.3",
26
26
  "@aws-sdk/client-s3": "^3.1136.0",
27
- "@design.estate/dees-catalog": "^23.1.0",
27
+ "@design.estate/dees-catalog": "^23.4.0",
28
28
  "@design.estate/dees-comms": "^2.1.0",
29
29
  "@design.estate/dees-element": "4.0.2",
30
30
  "@jitl/quickjs-ng-wasmfile-release-sync": "0.32.0",
@@ -32,11 +32,11 @@
32
32
  "@lossless.org/nosqldb": "10.8.0",
33
33
  "@lossless.org/objectstorage": "10.7.1",
34
34
  "@modelcontextprotocol/sdk": "1.30.0",
35
- "@modelprofile.com/catalog": "^1.0.0",
36
- "@modelprofile.com/flexharness": "16.3.0",
37
- "@modelprofile.com/flexharness-agent": "16.3.0",
38
- "@modelprofile.com/flexharness-models": "16.3.0",
39
- "@modelprofile.com/flexharness-providers": "16.3.0",
35
+ "@modelprofile.com/catalog": "^1.1.0",
36
+ "@modelprofile.com/flexharness": "16.4.0",
37
+ "@modelprofile.com/flexharness-agent": "16.4.0",
38
+ "@modelprofile.com/flexharness-models": "16.4.0",
39
+ "@modelprofile.com/flexharness-providers": "16.4.0",
40
40
  "@modelprofile.com/mcp-crossharness": "5.9.0",
41
41
  "@modelprofile.com/mcp-system": "3.1.0",
42
42
  "@opencode-ai/sdk": "1.18.15",
package/readme.md CHANGED
@@ -76,6 +76,8 @@ The browser receives normalized AGL data. It never receives the OpenCode server
76
76
 
77
77
  Controller protocol v28 sends bounded live Assistant text and reasoning deltas when the browser already owns the exact preceding transcript revision. Every delta carries its stream epoch, revision, and UTF-8 coordinates; Flex deltas also carry the harness's authoritative transcript order. The browser applies only contiguous, correctly sized updates to the canonical transcript; a gap, stale owner, invalid coordinate, or queue overflow blocks further deltas from that epoch and requests authoritative session-detail hydration instead. Only adjacent compatible pending deltas may be coalesced, so interleaved updates retain their original order.
78
78
 
79
+ Each browser receives controller events through its own ordered queue, one event in flight at a time, so a tab that acknowledges slowly or not at all delays only itself. A queue that passes 512 events or 16 MiB collapses for that browser alone: it keeps the newest event of each state, drops live text, reasoning and tool content, and ends with a conversation refresh for each harness whose live content it dropped. A streamed Flex reply notifies a conversation change at its parts' starts and ends and its run's lifecycle, not with every delta.
80
+
79
81
  Streaming text is rendered without Markdown parsing. AGL refreshes the affected messages and enables normal Markdown rendering after the harness reports terminal state or authoritative hydration settles the transcript. This keeps long responses responsive without creating a second browser-side message graph.
80
82
 
81
83
  Consecutive Assistant messages containing only reasoning share one header and time range. Each thought keeps its own disclosure and active thinking state; user messages, text, tools and attention requests end the group.
@@ -1274,7 +1276,12 @@ native completion; archive requires a settled worker. A worker whose start was r
1274
1276
  native session, and archiving it touches no harness. Claude archive marks only the AGL
1275
1277
  registry, preserving the transcript and native worktree. Codex archives its native thread.
1276
1278
  Watch retains native `reportId` alongside `workerId` so consumers can correlate reports
1277
- and updates without treating each watch cursor as a new report. A failed observation, a
1279
+ and updates without treating each watch cursor as a new report. An event whose whole text is a
1280
+ ticket comment names it as `commentId`: the fleet comments a ticketed worker's report before it
1281
+ publishes the report's event (`worker.report.mid_turn`, `worker.turn.ended`), the board pump's
1282
+ `ticket.stalled` names its notice, and a commented `ticket.changed` its comment. Read it with
1283
+ `ticket_get` and `commentId` (`agl ticket get AGL-<n> --comment <id>`), however long the
1284
+ ticket's history is. A report whose comment was not written names none. A failed observation, a
1278
1285
  transcript gap for example, is published once as `worker.observation.failed`; the fleet then
1279
1286
  requests a fresh report itself: the worker's next poll starts from a new baseline, and its
1280
1287
  newest report, when it has one, is published as `worker.report.mid_turn` and commented on its
@@ -1594,8 +1601,13 @@ While the board changed within the last hour, the driver keeps its prompt cache
1594
1601
  next turn reads the cached prefix instead of writing it again. Every board change (a ticket
1595
1602
  created, changed, moved, commented, answered or assigned) sets the driver session's warm
1596
1603
  deadline to one hour from then, and Flex runs a warm-up turn before the provider's cache would
1597
- expire. An hour after the last board change, warming stops until the next one. Warm-up turns
1598
- add nothing to the driver's conversation: no message in its transcript, no `working` status,
1604
+ expire. On a Claude model the driver's requests ask Anthropic for one-hour cache breakpoints
1605
+ (`cache: { retention: '1h' }`), so an idle hour costs one warm-up turn, a minute before the hour
1606
+ ends, instead of one every four minutes; writing an hour's breakpoint costs 2× the input price
1607
+ instead of 1.25×. Other sessions keep the five-minute default for their newest breakpoint. On a
1608
+ ChatGPT account the cache lives in memory for about five minutes and takes no retention, so
1609
+ warm-up turns still come every four minutes. An hour after the last board change, warming stops until the next one. Warm-up turns
1610
+ add nothing to the driver's conversation: nothing its model sees on later turns, no message in its transcript, no `working` status,
1599
1611
  no unread turn and no batch of fleet events. They leave the session's state as its last real
1600
1612
  turn left it, so a driver whose last turn failed still shows that error. The controller logs each
1601
1613
  warm-up turn with the tokens it read from the cache. `keepCacheWarm: false` turns warming off
@@ -1615,8 +1627,14 @@ and `driver_notes_update`, the shell and file tools
1615
1627
  every Flex session has, and the [AGL API](#agl-api-for-flex-sessions) without its ticket methods. The controller runs each of these tool calls as the driver: actor
1616
1628
  `driver:<controller id>` with the ticket role `driver`. A tool that changes fleet or ticket
1617
1629
  state first asks for the `agl.driver` permission, which the session can remember. The notes
1618
- are the driver session's scratchpad. They are added to its system prompt on every run, so the
1619
- driver's working state survives compaction and restarts.
1630
+ are the driver session's scratchpad, so the driver's working state survives compaction and
1631
+ restarts. They are not part of the driver's system prompt, which holds its instructions only:
1632
+ they reach the model as Flex's pinned context `driver-notes`, named by the scratchpad's
1633
+ revision. A turn whose context does not show the current revision gets it right before its
1634
+ prompt, and a compaction ends its summary with it, so the driver sees its notes when they change
1635
+ and after a compaction, and a notes update leaves the cached prompt in front of it unchanged.
1636
+ Empty notes are pinned as a note that they are empty, so clearing them replaces the text saved
1637
+ before.
1620
1638
 
1621
1639
  `ticket_question_answer` records the owner's answer to an open ticket question as the driver,
1622
1640
  with the schema of `agl ticket answer`; the MCP server has no such tool, so a worker cannot
@@ -1645,7 +1663,15 @@ finished or failed releases, failed or unknown ticket effects, others' ticket ch
1645
1663
  (`ticket.notification.failed`, naming the session), stalled tickets the board pump found
1646
1664
  (`ticket.stalled`) and Claude Code releases newer than the verified one
1647
1665
  (`harness.release.discovered`). Worker status changes, host-load samples,
1648
- applied ticket effects and delivered ticket notices are not delivered. A batch waits 15
1666
+ applied ticket effects and delivered ticket notices are not delivered. Each event reads as one
1667
+ header line -- `- [event <id>] <time> <kind>` with its ticket, worker, session, report id, turn id,
1668
+ status, repo, version and operation -- then its error and its text, quoted. A text longer than
1669
+ 3 KiB is relayed as a digest: every report marker line (`result:`, `needs input:`, `owner
1670
+ question:` and the others the fleet reads as a report), each at most 1 KiB, then the text's end,
1671
+ in order, with `[… N lines …]` where lines were left out. A note then says where the whole text
1672
+ is: a ticketed worker's report is the fleet comment of that report id on its ticket, and a
1673
+ stalled ticket's notice or another's change is on its ticket, all read with `ticket_get`. A
1674
+ report longer than 32 KiB is kept by the fleet from its end only, which the note says. A batch waits 15
1649
1675
  seconds for further events and is delivered at most once a minute. It waits while the driver runs a turn, including permission waits, using the current session state.
1650
1676
  If a batch is still queued when further events arrive, they merge into that same message,
1651
1677
  keeping its position and sender. The merged text is stored before the merge is acknowledged,
@@ -1698,6 +1724,10 @@ as `ticket.notified` when the answers reached the worker, and reaches the driver
1698
1724
  relay. The pump never starts a worker, never moves a ticket and never answers a question, and its
1699
1725
  comments are not relayed to the assignee as ticket notices.
1700
1726
 
1727
+ Each pass reads the board list once. A ticket's history and questions are read again only when its
1728
+ revision moved since the pass that last read them; every comment, question, answer and other change
1729
+ moves it, so a pass over an unchanged board reads no ticket's history.
1730
+
1701
1731
  The pump is on by default; configure it in the Configuration master:
1702
1732
 
1703
1733
  ```json
@@ -1730,8 +1760,8 @@ has full access; the CLI reuses `agl config`'s short-lived local-owner capabilit
1730
1760
  is no automatic dispatch. Attachment URLs must use HTTP or HTTPS; AGL stores the
1731
1761
  reference and does not fetch its payload.
1732
1762
 
1733
- Unidentified local MCP callers may use `tickets_list` and `ticket_get`, including comments
1734
- and activity returned with the ticket. Their Mine filter is empty and every returned ticket
1763
+ Unidentified local MCP callers may use `tickets_list` and `ticket_get`, including the comments
1764
+ and activity of the history page returned with the ticket. Their Mine filter is empty and every returned ticket
1735
1765
  permission is false. Every mutation refuses with `TICKET_IDENTITY_REQUIRED`; neither a
1736
1766
  claimed name nor a native session id supplies identity. Plain Claude background sessions
1737
1767
  started outside AGL stay unidentified. The web board still requires owner authentication.
@@ -1845,11 +1875,14 @@ that worker, not as the driver or anonymously:
1845
1875
  When the inventory shows the worker's session as another job, or the fleet no longer binds
1846
1876
  the worker to it (archived, moved to another session), the launch is revoked for good.
1847
1877
  An upgrade moves every bridge in place onto the new build (`process.execve`: the same PID and
1848
- start, a new image from the new install's path), and the image it became is proved afresh:
1849
- its command is the one recorded with the launch or the one the restarted controller resolves
1850
- itself from its configured `agl` MCP entry, never one the bridge names, and a new command is
1851
- kept with the binding's next revision. Each reason an enrollment stays unverified is written once to the controller log,
1852
- naming the worker and its session, never the launch ID or a credential.
1878
+ start, a new image `node <new cli.js> mcp --port <port>` from the new install's path), and the
1879
+ image it became is proved afresh: its command is the one recorded with the launch or the one
1880
+ the restarted controller resolves itself from its configured `agl` MCP entry, never one the
1881
+ bridge names, and a new command is kept with the binding's next revision. Its arguments are
1882
+ that command's or exactly `mcp --port <port>` with the port the controller is configured
1883
+ with. Each reason an enrollment stays unverified is written once to the controller log,
1884
+ naming the worker and its session, never the launch ID or a credential; a bridge refused
1885
+ under both commands has both reasons, the recorded command's first.
1853
1886
 
1854
1887
  The bridge exchanges credentials only through the private controller endpoint after Linux
1855
1888
  direct-loopback socket-inode ownership, approved executable/argv and current native
@@ -1865,7 +1898,7 @@ entry. Ambiguous entries, wrapper commands, static caller credentials and secret
1865
1898
  definitions fail closed. Fleet owns spawning, native observations and hook calls.
1866
1899
 
1867
1900
  MCP tools are `tickets_list` (mine/project/status/label/text filters), `ticket_get` (ticket,
1868
- comments, complete activity and questions), `ticket_create`, `ticket_update`, `ticket_move`,
1901
+ questions and one page of history), `ticket_create`, `ticket_update`, `ticket_move`,
1869
1902
  `ticket_comment`, `ticket_link` and `ticket_question_ask`. `ticket_comment.body` accepts markdown text or the
1870
1903
  kanban's text/reference-content array. A Claude worker's assignment uses
1871
1904
  `claude:<agent-session-id>` and a Codex worker's uses `codex:<native-id>`; the same value
@@ -1881,6 +1914,8 @@ agl ticket list --project agl --json
1881
1914
  agl ticket link AGL-1 --repo modelprofile.com/agl --branch feat/tickets --sha <full-sha> --json
1882
1915
  agl ticket move AGL-1 --column review --json
1883
1916
  agl ticket get AGL-1 --json
1917
+ agl ticket get AGL-1 --limit 20 --before <historyBefore> --json
1918
+ agl ticket get AGL-1 --comment <comment-id> --json
1884
1919
  agl ticket comment AGL-1 --body '**Checks passed**' --json
1885
1920
  agl ticket update AGL-1 --expected-revision <revision-from-get> --changes '{"priority":"high","labels":["backend"]}' --json
1886
1921
  agl ticket ask AGL-1 --text 'Which store?' --options '["Memory",{"label":"Database","description":"Durable"}]' --json
@@ -1888,6 +1923,18 @@ agl ticket list --label openQuestion --json
1888
1923
  agl ticket answer AGL-1 --question Q1 --choice 2 --text 'Keep it **small**.' --json
1889
1924
  ```
1890
1925
 
1926
+ `ticket_get` (`agl ticket get`, `agl.mcp.ticket.get`, `controller.ticket.get`) returns the
1927
+ ticket, all its questions and the newest page of its history, oldest first: `activity` holds
1928
+ up to `limit` entries (default 50, at most 500), cut earlier so that the entries and the comments
1929
+ they name stay within 256 KiB (always at least one entry), and `comments` the comments those
1930
+ entries name. A `commented` entry names its comment as `changes.comment: { after: { id } }`, so
1931
+ each comment body appears once (stored activity keeps the whole comment). While older history exists the response
1932
+ carries `historyBefore`; pass it as `before` (`--before`) to read the next older page. To read the
1933
+ one comment an activity entry or a fleet event names, pass its id as `commentId` (`--comment`)
1934
+ instead: the answer holds the ticket, its questions and that comment alone (`activity` empty, no
1935
+ `historyBefore`); it cannot be combined with `before` or `limit`, and an id that is not a comment
1936
+ of the ticket is refused with `ticket_comment_not_found`. The board in the browser reads every page.
1937
+
1891
1938
  All ten CLI actions accept `--port` and `--json`; `agl ticket --help` documents their
1892
1939
  options. The running controller is required. `update` and `assign` require `--expected-revision`
1893
1940
  from the ticket the editor read; neither command fetches a newer revision before saving.
@@ -2370,7 +2417,7 @@ Deleting a managed OpenCode conversation deletes the selected OpenCode conversat
2370
2417
 
2371
2418
  ### Models And Provider Accounts
2372
2419
 
2373
- AGL stores an independent default model for OpenCode, FlexHarness, Codex and Claude Code. A conversation can override its harness default without changing other conversations.
2420
+ AGL stores an independent default model for OpenCode, FlexHarness, Codex and Claude Code. A conversation can override its harness default without changing other conversations. **Settings → General** shows each harness's default as one button that says the model and its effort (`openai/gpt-5.6-sol · max`, without the harness the row already names) and opens both choices in a speech bubble; a saved default the harness no longer offers gives the button the warning tone.
2374
2421
 
2375
2422
  A stored default names a model as the harness offered it then, so AGL resolves it against the harness's live model list whenever a conversation is created or sent without a model of its own. While the harness offers it, it is sent. A stored default the harness no longer offers is never sent: the harness's own default stands in -- OpenCode's or Codex's configured model, or for Flex the catalog default of the account placement takes -- and when the harness offers no default AGL can name, OpenCode, Codex and Claude Code run their own default unnamed, while Flex, which has none of its own, asks for an account and model in the composer. The stored setting stays as the owner wrote it; `models_list` reports it as `unavailableSetting`, and Settings says under the default model that it is no longer offered and what new conversations run on instead.
2376
2423
 
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: 'agl',
6
- version: '40.6.0',
6
+ version: '41.0.1',
7
7
  description: 'Agent Gateway Layer for OpenCode, FlexHarness, and Codex sessions'
8
8
  }
@@ -1408,8 +1408,8 @@ export const AGL_API_SURFACE: plugins.flexTypedRequest.IFlexTypedRequestSurface
1408
1408
  {
1409
1409
  "method": "agl.mcp.ticket.get",
1410
1410
  "path": "agl.agl_mcp_ticket_get",
1411
- "summary": "Reads a ticket by its `AGL-<n>` key, with its Markdown comments, source, links, questions and their answers, and its co…",
1412
- "description": "Reads a ticket by its `AGL-<n>` key, with its Markdown comments, source, links, questions and\ntheir answers, and its complete activity log.",
1411
+ "summary": "Reads a ticket by its `AGL-<n>` key with its source, links, all its questions and their answers, and the newest page of…",
1412
+ "description": "Reads a ticket by its `AGL-<n>` key with its source, links, all its questions and their answers,\nand the newest page of its history (up to `limit` entries, default 50, at most 500, within 256 KiB), oldest first: the\nactivity entries and the Markdown comments they name, a `commented` entry naming its comment by\nid. `historyBefore` is present while older history exists; pass it as `before` for the next page.\n`commentId` reads that one comment instead (`comments: [it]`, `activity: []`), without `before` or `limit`.",
1413
1413
  "omitted": [
1414
1414
  "ownerToken"
1415
1415
  ],
@@ -1419,6 +1419,18 @@ export const AGL_API_SURFACE: plugins.flexTypedRequest.IFlexTypedRequestSurface
1419
1419
  "properties": {
1420
1420
  "ticketId": {
1421
1421
  "type": "string"
1422
+ },
1423
+ "before": {
1424
+ "type": "string",
1425
+ "description": "An activity id, as `historyBefore` returned it: the page holds only older entries."
1426
+ },
1427
+ "limit": {
1428
+ "type": "number",
1429
+ "description": "Entries on the page, 1 to 500 (`ticketHistoryPage.maximum`); 50 (`ticketHistoryPage.default`) when absent."
1430
+ },
1431
+ "commentId": {
1432
+ "type": "string",
1433
+ "description": "One comment of this ticket, by the id an activity entry or a fleet event names: the response holds the ticket, its questions and that comment alone (`comments: [it]`, `activity: []`, no `historyBefore`). Excludes `before` and `limit`."
1422
1434
  }
1423
1435
  },
1424
1436
  "required": [
@@ -1426,39 +1438,9 @@ export const AGL_API_SURFACE: plugins.flexTypedRequest.IFlexTypedRequestSurface
1426
1438
  ]
1427
1439
  },
1428
1440
  "outputSchema": {
1429
- "type": "object",
1430
- "properties": {
1431
- "ticket": {
1432
- "$ref": "#/$defs/ITicket"
1433
- },
1434
- "comments": {
1435
- "type": "array",
1436
- "items": {
1437
- "$ref": "#/$defs/ITicketComment"
1438
- }
1439
- },
1440
- "activity": {
1441
- "type": "array",
1442
- "items": {
1443
- "$ref": "#/$defs/ITicketActivity"
1444
- }
1445
- },
1446
- "questions": {
1447
- "type": "array",
1448
- "items": {
1449
- "$ref": "#/$defs/ITicketQuestion"
1450
- }
1451
- }
1452
- },
1453
- "required": [
1454
- "ticket",
1455
- "comments",
1456
- "activity",
1457
- "questions"
1458
- ],
1459
- "additionalProperties": false
1441
+ "$ref": "#/$defs/ITicketDetail"
1460
1442
  },
1461
- "declaration": "/**\n * Reads a ticket by its `AGL-<n>` key, with its Markdown comments, source, links, questions and\n * their answers, and its complete activity log.\n */\nfunction agl_mcp_ticket_get(params: { ticketId: string }): Promise<{ ticket: ITicket; comments: ITicketComment[]; activity: ITicketActivity[]; questions: ITicketQuestion[] }>;"
1443
+ "declaration": "/**\n * Reads a ticket by its `AGL-<n>` key with its source, links, all its questions and their answers,\n * and the newest page of its history (up to `limit` entries, default 50, at most 500, within 256 KiB), oldest first: the\n * activity entries and the Markdown comments they name, a `commented` entry naming its comment by\n * id. `historyBefore` is present while older history exists; pass it as `before` for the next page.\n * `commentId` reads that one comment instead (`comments: [it]`, `activity: []`), without `before` or `limit`.\n */\nfunction agl_mcp_ticket_get(params: ITicketGet): Promise<ITicketDetail>;"
1462
1444
  },
1463
1445
  {
1464
1446
  "method": "agl.mcp.ticket.link",
@@ -3783,7 +3765,7 @@ export const AGL_API_SURFACE: plugins.flexTypedRequest.IFlexTypedRequestSurface
3783
3765
  },
3784
3766
  "protocolVersion": {
3785
3767
  "type": "number",
3786
- "const": 45
3768
+ "const": 46
3787
3769
  },
3788
3770
  "upgradeManagementVersion": {
3789
3771
  "type": "number"
@@ -3905,7 +3887,7 @@ export const AGL_API_SURFACE: plugins.flexTypedRequest.IFlexTypedRequestSurface
3905
3887
  ],
3906
3888
  "additionalProperties": false
3907
3889
  },
3908
- "declaration": "interface IControllerStatus {\n packageName: string;\n packageVersion: string;\n protocolVersion: 45;\n upgradeManagementVersion: number;\n controllerPid: number;\n processGroupId: number;\n processFingerprint: string;\n processMode: TControllerProcessMode;\n lifecycleState: TControllerLifecycleState;\n startedAt: number;\n setupRequired: boolean;\n /** Present when the controller runs as the systemd user unit (`agl service install`); absent for a detached or foreground one. */\n serviceUnit?: \"agl-controller.service\";\n /** The TLS mode of the runtime configuration the controller runs with; absent until it is resolved. */\n tlsMode?: TControllerTlsMode;\n upgrade?: IControllerUpgradeStatus;\n /** AGL's inference proxy, by state only; details need a signed-in owner (`controller.proxy.status.get`). */\n proxy?: { state: TControllerProxyState };\n harnesses: Array<{\n harnessId: TControllerSessionHarnessId;\n pid?: number;\n state: TControllerHarnessLifecycleState;\n healthy: boolean;\n version?: string;\n supportsLocalAttachments?: boolean;\n connectionMode?: 'local' | 'shared' | 'remote';\n diagnostic?: IControllerCodexDiagnostic;\n /** Codex only: automatic reconnection of this entry's profile to the local shared app-server. */\n rejoin?: IControllerCodexRejoinStatus;\n /**\n * Codex only, on the controller status: every connected or required profile. The entry's\n * `healthy` is then true only when each of them is, apart from a profile on an account Codex\n * cannot run on now, listed `stopped` with an `account_unavailable` diagnostic that says why;\n * its other members describe the default profile.\n */\n profiles?: IControllerCodexProfileStatus[];\n }>;\n}"
3890
+ "declaration": "interface IControllerStatus {\n packageName: string;\n packageVersion: string;\n protocolVersion: 46;\n upgradeManagementVersion: number;\n controllerPid: number;\n processGroupId: number;\n processFingerprint: string;\n processMode: TControllerProcessMode;\n lifecycleState: TControllerLifecycleState;\n startedAt: number;\n setupRequired: boolean;\n /** Present when the controller runs as the systemd user unit (`agl service install`); absent for a detached or foreground one. */\n serviceUnit?: \"agl-controller.service\";\n /** The TLS mode of the runtime configuration the controller runs with; absent until it is resolved. */\n tlsMode?: TControllerTlsMode;\n upgrade?: IControllerUpgradeStatus;\n /** AGL's inference proxy, by state only; details need a signed-in owner (`controller.proxy.status.get`). */\n proxy?: { state: TControllerProxyState };\n harnesses: Array<{\n harnessId: TControllerSessionHarnessId;\n pid?: number;\n state: TControllerHarnessLifecycleState;\n healthy: boolean;\n version?: string;\n supportsLocalAttachments?: boolean;\n connectionMode?: 'local' | 'shared' | 'remote';\n diagnostic?: IControllerCodexDiagnostic;\n /** Codex only: automatic reconnection of this entry's profile to the local shared app-server. */\n rejoin?: IControllerCodexRejoinStatus;\n /**\n * Codex only, on the controller status: every connected or required profile. The entry's\n * `healthy` is then true only when each of them is, apart from a profile on an account Codex\n * cannot run on now, listed `stopped` with an `account_unavailable` diagnostic that says why;\n * its other members describe the default profile.\n */\n profiles?: IControllerCodexProfileStatus[];\n }>;\n}"
3909
3891
  },
3910
3892
  {
3911
3893
  "name": "IControllerTerminalResource",
@@ -4743,10 +4725,55 @@ export const AGL_API_SURFACE: plugins.flexTypedRequest.IFlexTypedRequestSurface
4743
4725
  "name": "ITicketCreate",
4744
4726
  "declaration": "interface ITicketCreate {\n project: string;\n kind?: TTicketKind;\n title: string;\n description?: string;\n columnId?: TTicketColumn;\n parentId?: string;\n priority?: TTicketPriority;\n assignee?: ITicketPerson;\n labels?: string[];\n sourceText?: string;\n attachments?: ITicketAttachment[];\n}"
4745
4727
  },
4728
+ {
4729
+ "name": "ITicketDetail",
4730
+ "schema": {
4731
+ "type": "object",
4732
+ "properties": {
4733
+ "ticket": {
4734
+ "$ref": "#/$defs/ITicket"
4735
+ },
4736
+ "comments": {
4737
+ "type": "array",
4738
+ "items": {
4739
+ "$ref": "#/$defs/ITicketComment"
4740
+ }
4741
+ },
4742
+ "activity": {
4743
+ "type": "array",
4744
+ "items": {
4745
+ "$ref": "#/$defs/ITicketActivity"
4746
+ }
4747
+ },
4748
+ "questions": {
4749
+ "type": "array",
4750
+ "items": {
4751
+ "$ref": "#/$defs/ITicketQuestion"
4752
+ }
4753
+ },
4754
+ "historyBefore": {
4755
+ "type": "string"
4756
+ }
4757
+ },
4758
+ "required": [
4759
+ "ticket",
4760
+ "comments",
4761
+ "activity",
4762
+ "questions"
4763
+ ],
4764
+ "additionalProperties": false,
4765
+ "description": "A ticket, all its questions and one page of its history, oldest first. `activity` is the page; `comments` are the comments its `commented` entries name, whose `changes.comment` holds only `{ after: { id } }` here (the stored entry keeps the whole comment). `historyBefore` is present while older entries exist: pass it as `before`."
4766
+ },
4767
+ "declaration": "/**\n * A ticket, all its questions and one page of its history, oldest first. `activity` is the page; `comments` are the\n * comments its `commented` entries name, whose `changes.comment` holds only `{ after: { id } }` here (the stored\n * entry keeps the whole comment). `historyBefore` is present while older entries exist: pass it as `before`.\n */\ninterface ITicketDetail {\n ticket: ITicket;\n comments: ITicketComment[];\n activity: ITicketActivity[];\n questions: ITicketQuestion[];\n historyBefore?: string;\n}"
4768
+ },
4746
4769
  {
4747
4770
  "name": "ITicketFilters",
4748
4771
  "declaration": "interface ITicketFilters {\n mine?: boolean;\n project?: string;\n status?: TTicketColumn;\n /** Matches a hand label or an AutoLabel. */\n label?: string;\n text?: string;\n}"
4749
4772
  },
4773
+ {
4774
+ "name": "ITicketGet",
4775
+ "declaration": "/** A ticket and one page of its history: the newest entries, or those older than the entry `before` names, within `ticketHistoryPage`. */\ninterface ITicketGet {\n ticketId: string;\n /** An activity id, as `historyBefore` returned it: the page holds only older entries. */\n before?: string;\n /** Entries on the page, 1 to 500 (`ticketHistoryPage.maximum`); 50 (`ticketHistoryPage.default`) when absent. */\n limit?: number;\n /**\n * One comment of this ticket, by the id an activity entry or a fleet event names: the response holds the ticket, its\n * questions and that comment alone (`comments: [it]`, `activity: []`, no `historyBefore`). Excludes `before` and `limit`.\n */\n commentId?: string;\n}"
4776
+ },
4750
4777
  {
4751
4778
  "name": "ITicketMove",
4752
4779
  "declaration": "interface ITicketMove { ticketId: string; columnId: TTicketColumn; beforeTicketId?: string; }"