@aristanetworks/eos-mcp-server 0.6.1-beta → 0.8.0-beta

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 (105) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +197 -44
  3. package/dist/cli.d.ts +4 -1
  4. package/dist/cli.js +63 -4
  5. package/dist/cli.js.map +1 -1
  6. package/dist/commands/inspectDiagnostics.d.ts +3 -0
  7. package/dist/commands/inspectDiagnostics.js +35 -0
  8. package/dist/commands/inspectDiagnostics.js.map +1 -0
  9. package/dist/commands/releaseDiagnostics.d.ts +9 -0
  10. package/dist/commands/releaseDiagnostics.js +87 -0
  11. package/dist/commands/releaseDiagnostics.js.map +1 -0
  12. package/dist/config/diagnostics.d.ts +60 -0
  13. package/dist/config/diagnostics.js +37 -0
  14. package/dist/config/diagnostics.js.map +1 -0
  15. package/dist/config/loadConfig.js +6 -1
  16. package/dist/config/loadConfig.js.map +1 -1
  17. package/dist/config/schema.d.ts +168 -8
  18. package/dist/config/schema.js +3 -0
  19. package/dist/config/schema.js.map +1 -1
  20. package/dist/diagnostics/concurrency.d.ts +33 -0
  21. package/dist/diagnostics/concurrency.js +157 -0
  22. package/dist/diagnostics/concurrency.js.map +1 -0
  23. package/dist/diagnostics/eapiRunner.d.ts +10 -0
  24. package/dist/diagnostics/eapiRunner.js +46 -0
  25. package/dist/diagnostics/eapiRunner.js.map +1 -0
  26. package/dist/diagnostics/executionError.d.ts +7 -0
  27. package/dist/diagnostics/executionError.js +10 -0
  28. package/dist/diagnostics/executionError.js.map +1 -0
  29. package/dist/diagnostics/executor.d.ts +32 -0
  30. package/dist/diagnostics/executor.js +115 -0
  31. package/dist/diagnostics/executor.js.map +1 -0
  32. package/dist/diagnostics/journal.d.ts +14 -0
  33. package/dist/diagnostics/journal.js +317 -0
  34. package/dist/diagnostics/journal.js.map +1 -0
  35. package/dist/diagnostics/journalTypes.d.ts +8 -0
  36. package/dist/diagnostics/journalTypes.js +2 -0
  37. package/dist/diagnostics/journalTypes.js.map +1 -0
  38. package/dist/diagnostics/ping.d.ts +7 -0
  39. package/dist/diagnostics/ping.js +131 -0
  40. package/dist/diagnostics/ping.js.map +1 -0
  41. package/dist/diagnostics/releaseEvidence.d.ts +502 -0
  42. package/dist/diagnostics/releaseEvidence.js +115 -0
  43. package/dist/diagnostics/releaseEvidence.js.map +1 -0
  44. package/dist/diagnostics/reservationSchema.d.ts +49 -0
  45. package/dist/diagnostics/reservationSchema.js +18 -0
  46. package/dist/diagnostics/reservationSchema.js.map +1 -0
  47. package/dist/diagnostics/statePath.d.ts +4 -0
  48. package/dist/diagnostics/statePath.js +25 -0
  49. package/dist/diagnostics/statePath.js.map +1 -0
  50. package/dist/diagnostics/types.d.ts +82 -0
  51. package/dist/diagnostics/types.js +2 -0
  52. package/dist/diagnostics/types.js.map +1 -0
  53. package/dist/eapi/client.d.ts +3 -1
  54. package/dist/eapi/client.js +17 -6
  55. package/dist/eapi/client.js.map +1 -1
  56. package/dist/eapi/types.d.ts +6 -0
  57. package/dist/eapi/types.js.map +1 -1
  58. package/dist/index.js +10 -0
  59. package/dist/index.js.map +1 -1
  60. package/dist/inventory/buildModel.js +1 -0
  61. package/dist/inventory/buildModel.js.map +1 -1
  62. package/dist/inventory/listInventoryView.d.ts +1 -0
  63. package/dist/inventory/listInventoryView.js +1 -0
  64. package/dist/inventory/listInventoryView.js.map +1 -1
  65. package/dist/inventory/policy.d.ts +1 -0
  66. package/dist/inventory/policy.js +3 -1
  67. package/dist/inventory/policy.js.map +1 -1
  68. package/dist/inventory/types.d.ts +1 -0
  69. package/dist/inventory/varValidation.js +1 -0
  70. package/dist/inventory/varValidation.js.map +1 -1
  71. package/dist/mcp/createServer.js +56 -4
  72. package/dist/mcp/createServer.js.map +1 -1
  73. package/dist/mcp/tools/getServerInfo.d.ts +2 -1
  74. package/dist/mcp/tools/getServerInfo.js +2 -2
  75. package/dist/mcp/tools/getServerInfo.js.map +1 -1
  76. package/dist/mcp/tools/ping.d.ts +38 -0
  77. package/dist/mcp/tools/ping.js +40 -0
  78. package/dist/mcp/tools/ping.js.map +1 -0
  79. package/dist/operations/readExecution.d.ts +3 -1
  80. package/dist/operations/readExecution.js +24 -16
  81. package/dist/operations/readExecution.js.map +1 -1
  82. package/dist/serverInfo/buildServerInfo.d.ts +2 -1
  83. package/dist/serverInfo/buildServerInfo.js +16 -2
  84. package/dist/serverInfo/buildServerInfo.js.map +1 -1
  85. package/dist/serverInfo/types.d.ts +15 -0
  86. package/dist/utils/privateFile.d.ts +3 -0
  87. package/dist/utils/privateFile.js +7 -0
  88. package/dist/utils/privateFile.js.map +1 -0
  89. package/docs/CHECKPOINT.md +11 -1
  90. package/docs/CODE_WALKTHROUGH.md +30 -6
  91. package/docs/DESIGN.md +17 -4
  92. package/docs/DIAGNOSTICS.md +218 -0
  93. package/docs/IMPLEMENTATION_PLAN.md +5 -4
  94. package/docs/QUICKSTART.md +13 -13
  95. package/docs/adr/0001-non-configuring-diagnostics.md +5 -0
  96. package/docs/adr/0002-fail-closed-diagnostic-reservations.md +7 -0
  97. package/docs/adr/0003-durable-diagnostic-ledger.md +9 -0
  98. package/docs/adr/0004-offline-operator-attested-release.md +5 -0
  99. package/docs/adr/0005-multi-destination-ping.md +9 -0
  100. package/docs/examples/diagnostic-release-evidence.template.json +26 -0
  101. package/docs/research/eos-diagnostic-lifecycle.md +84 -0
  102. package/package.json +1 -1
  103. package/dist/inventory/writePolicy.d.ts +0 -2
  104. package/dist/inventory/writePolicy.js +0 -36
  105. package/dist/inventory/writePolicy.js.map +0 -1
@@ -0,0 +1,157 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { AppError } from "../core/errors.js";
3
+ /** One instance per server; uncertain remote execution never expires into free capacity. */
4
+ export class DiagnosticConcurrency {
5
+ limit;
6
+ journal;
7
+ reservations = new Set();
8
+ waiting = [];
9
+ storageError;
10
+ closed = false;
11
+ constructor(limit, journal) {
12
+ this.limit = limit;
13
+ this.journal = journal;
14
+ for (const reservation of journal?.load() ?? []) {
15
+ this.reservations.add({ ...reservation });
16
+ }
17
+ }
18
+ close() {
19
+ if (this.closed)
20
+ return;
21
+ this.closed = true;
22
+ this.rejectWaiters(new AppError("diagnostic_state_closed", "Diagnostic execution is shutting down"));
23
+ this.journal?.close();
24
+ }
25
+ snapshot() {
26
+ const reservations = [...this.reservations].map((reservation) => ({ ...reservation }));
27
+ const uncertain = reservations.filter((reservation) => reservation.state === "uncertain").length;
28
+ return {
29
+ scope: this.journal === undefined ? "server-instance" : "state-file",
30
+ ...(this.storageError === undefined ? {} : { storage_error_code: this.storageError.code }),
31
+ limit: this.limit,
32
+ available_count: this.closed || this.storageError !== undefined ? 0 : Math.max(0, this.limit - reservations.length),
33
+ active_count: reservations.length - uncertain,
34
+ uncertain_count: uncertain,
35
+ queued_count: this.waiting.length,
36
+ reservations
37
+ };
38
+ }
39
+ assertUsableCapacity() {
40
+ if (this.closed)
41
+ throw new AppError("diagnostic_state_closed", "Diagnostic execution is closed");
42
+ if (this.storageError !== undefined)
43
+ throw this.storageError;
44
+ if (this.isUncertainExhausted()) {
45
+ throw this.capacityError();
46
+ }
47
+ }
48
+ acquire(signal, intent) {
49
+ return new Promise((resolve, reject) => {
50
+ if (signal.aborted) {
51
+ reject(new AppError("operation_aborted", "Diagnostic was cancelled while waiting for capacity"));
52
+ return;
53
+ }
54
+ this.assertUsableCapacity();
55
+ const cancelled = () => {
56
+ const index = this.waiting.indexOf(waiter);
57
+ if (index >= 0)
58
+ this.waiting.splice(index, 1);
59
+ waiter.reject(new AppError("operation_aborted", "Diagnostic was cancelled while waiting for capacity"));
60
+ };
61
+ const waiter = {
62
+ reject: (error) => {
63
+ signal.removeEventListener("abort", cancelled);
64
+ reject(error);
65
+ },
66
+ grant: () => {
67
+ signal.removeEventListener("abort", cancelled);
68
+ try {
69
+ resolve(this.reserve(intent));
70
+ }
71
+ catch (error) {
72
+ reject(error);
73
+ }
74
+ }
75
+ };
76
+ if (this.reservations.size < this.limit) {
77
+ waiter.grant();
78
+ }
79
+ else {
80
+ this.waiting.push(waiter);
81
+ signal.addEventListener("abort", cancelled, { once: true });
82
+ }
83
+ });
84
+ }
85
+ reserve(intent) {
86
+ const requestId = randomUUID();
87
+ const state = {
88
+ reservation_id: requestId,
89
+ rpc_request_id: requestId,
90
+ inventory_hostname: intent.inventoryHostname,
91
+ diagnostic: intent.diagnostic,
92
+ state: "active",
93
+ reserved_at: new Date().toISOString()
94
+ };
95
+ try {
96
+ this.journal?.save(state);
97
+ }
98
+ catch {
99
+ throw this.failStorage();
100
+ }
101
+ this.reservations.add(state);
102
+ return {
103
+ requestId,
104
+ complete: () => this.complete(state),
105
+ markUncertain: (reasonCode) => this.markUncertain(state, reasonCode)
106
+ };
107
+ }
108
+ complete(state) {
109
+ if (!this.reservations.has(state))
110
+ return;
111
+ try {
112
+ this.journal?.remove(state.reservation_id);
113
+ }
114
+ catch {
115
+ state.state = "uncertain";
116
+ state.uncertain_since = new Date().toISOString();
117
+ state.reason_code = "diagnostic_state_write_failed";
118
+ throw this.failStorage();
119
+ }
120
+ this.reservations.delete(state);
121
+ this.waiting.shift()?.grant();
122
+ }
123
+ markUncertain(state, reasonCode) {
124
+ if (!this.reservations.has(state) || state.state === "uncertain")
125
+ return;
126
+ state.state = "uncertain";
127
+ state.uncertain_since = new Date().toISOString();
128
+ state.reason_code = reasonCode;
129
+ try {
130
+ this.journal?.save(state);
131
+ }
132
+ catch {
133
+ // Abort listeners must not throw. The committed active record
134
+ // still prevents fresh capacity on restart; stop all new work.
135
+ this.failStorage();
136
+ }
137
+ if (this.isUncertainExhausted())
138
+ this.rejectWaiters(this.capacityError());
139
+ }
140
+ isUncertainExhausted() {
141
+ return this.reservations.size >= this.limit && [...this.reservations].every((reservation) => reservation.state === "uncertain");
142
+ }
143
+ failStorage() {
144
+ const error = new AppError("diagnostic_state_write_failed", "Diagnostic state could not be committed; all new diagnostics are blocked until operator investigation");
145
+ this.storageError = error;
146
+ this.rejectWaiters(error);
147
+ return error;
148
+ }
149
+ rejectWaiters(error) {
150
+ for (const waiter of this.waiting.splice(0))
151
+ waiter.reject(error);
152
+ }
153
+ capacityError() {
154
+ return new AppError("diagnostic_capacity_uncertain", "Diagnostic capacity is reserved for executions with unknown remote completion. Inspect eos_get_server_info.diagnostics.capacity and contact an operator; reservations do not expire. Do not retry or restart merely to clear them.");
155
+ }
156
+ }
157
+ //# sourceMappingURL=concurrency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrency.js","sourceRoot":"","sources":["../../src/diagnostics/concurrency.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAoB7C,4FAA4F;AAC5F,MAAM,OAAO,qBAAqB;IAOH;IAAgC;IAN5C,YAAY,GAAG,IAAI,GAAG,EAA6B,CAAC;IACpD,OAAO,GAAa,EAAE,CAAC;IAEhC,YAAY,CAAuB;IACnC,MAAM,GAAG,KAAK,CAAC;IAEvB,YAA6B,KAAa,EAAmB,OAA2B;QAA3D,UAAK,GAAL,KAAK,CAAQ;QAAmB,YAAO,GAAP,OAAO,CAAoB;QACtF,KAAK,MAAM,WAAW,IAAI,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;YAChD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,GAAG,WAAW,EAAE,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QACxB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,aAAa,CAAC,IAAI,QAAQ,CAAC,yBAAyB,EAAE,uCAAuC,CAAC,CAAC,CAAC;QACrG,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;IACxB,CAAC;IAED,QAAQ;QACN,MAAM,YAAY,GAAG,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,WAAW,EAAE,CAAC,CAAC,CAAC;QACvF,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,KAAK,WAAW,CAAC,CAAC,MAAM,CAAC;QACjG,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,YAAY;YACpE,GAAG,CAAC,IAAI,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;YAC1F,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,eAAe,EAAE,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC;YACnH,YAAY,EAAE,YAAY,CAAC,MAAM,GAAG,SAAS;YAC7C,eAAe,EAAE,SAAS;YAC1B,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM;YACjC,YAAY;SACb,CAAC;IACJ,CAAC;IAED,oBAAoB;QAClB,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,QAAQ,CAAC,yBAAyB,EAAE,gCAAgC,CAAC,CAAC;QACjG,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS;YAAE,MAAM,IAAI,CAAC,YAAY,CAAC;QAC7D,IAAI,IAAI,CAAC,oBAAoB,EAAE,EAAE,CAAC;YAChC,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,CAAC,MAAmB,EAAE,MAAmC;QAC9D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,MAAM,CAAC,IAAI,QAAQ,CAAC,mBAAmB,EAAE,qDAAqD,CAAC,CAAC,CAAC;gBACjG,OAAO;YACT,CAAC;YACD,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC5B,MAAM,SAAS,GAAG,GAAS,EAAE;gBAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;gBAC3C,IAAI,KAAK,IAAI,CAAC;oBAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gBAC9C,MAAM,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,mBAAmB,EAAE,qDAAqD,CAAC,CAAC,CAAC;YAC1G,CAAC,CAAC;YACF,MAAM,MAAM,GAAW;gBACrB,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;oBAChB,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;oBAC/C,MAAM,CAAC,KAAK,CAAC,CAAC;gBAChB,CAAC;gBACD,KAAK,EAAE,GAAG,EAAE;oBACV,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;oBAC/C,IAAI,CAAC;wBACH,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;oBAChC,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,MAAM,CAAC,KAAK,CAAC,CAAC;oBAChB,CAAC;gBACH,CAAC;aACF,CAAC;YACF,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;gBACxC,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC1B,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,OAAO,CAAC,MAAmC;QACjD,MAAM,SAAS,GAAG,UAAU,EAAE,CAAC;QAC/B,MAAM,KAAK,GAA8B;YACvC,cAAc,EAAE,SAAS;YACzB,cAAc,EAAE,SAAS;YACzB,kBAAkB,EAAE,MAAM,CAAC,iBAAiB;YAC5C,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,KAAK,EAAE,QAAQ;YACf,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACtC,CAAC;QACF,IAAI,CAAC;YACH,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAC3B,CAAC;QACD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC7B,OAAO;YACL,SAAS;YACT,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YACpC,aAAa,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,UAAU,CAAC;SACrE,CAAC;IACJ,CAAC;IAEO,QAAQ,CAAC,KAAgC;QAC/C,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,OAAO;QAC1C,IAAI,CAAC;YACH,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,KAAK,CAAC,KAAK,GAAG,WAAW,CAAC;YAC1B,KAAK,CAAC,eAAe,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACjD,KAAK,CAAC,WAAW,GAAG,+BAA+B,CAAC;YACpD,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAC3B,CAAC;QACD,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC;IAChC,CAAC;IAEO,aAAa,CAAC,KAAgC,EAAE,UAAkB;QACxE,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,KAAK,WAAW;YAAE,OAAO;QACzE,KAAK,CAAC,KAAK,GAAG,WAAW,CAAC;QAC1B,KAAK,CAAC,eAAe,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACjD,KAAK,CAAC,WAAW,GAAG,UAAU,CAAC;QAC/B,IAAI,CAAC;YACH,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,8DAA8D;YAC9D,+DAA+D;YAC/D,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,CAAC;QACD,IAAI,IAAI,CAAC,oBAAoB,EAAE;YAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;IAC5E,CAAC;IAEO,oBAAoB;QAC1B,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,KAAK,WAAW,CAAC,CAAC;IAClI,CAAC;IAEO,WAAW;QACjB,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,+BAA+B,EAAE,uGAAuG,CAAC,CAAC;QACrK,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC1B,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,aAAa,CAAC,KAAe;QACnC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACpE,CAAC;IAEO,aAAa;QACnB,OAAO,IAAI,QAAQ,CACjB,+BAA+B,EAC/B,oOAAoO,CACrO,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ import type { ResolvedServerConfig } from "../config/schema.js";
2
+ import type { EosTextCommandRunner } from "../eapi/types.js";
3
+ import type { InventoryHostModel } from "../inventory/types.js";
4
+ import type { DiagnosticDeviceRunner, DiagnosticExecutionContext, DiagnosticObservation, PreparedDiagnostic } from "./types.js";
5
+ export declare class EapiDiagnosticRunner implements DiagnosticDeviceRunner {
6
+ private readonly config;
7
+ private readonly runner;
8
+ constructor(config: ResolvedServerConfig, runner: EosTextCommandRunner);
9
+ execute(host: InventoryHostModel, request: PreparedDiagnostic, context: DiagnosticExecutionContext): Promise<DiagnosticObservation>;
10
+ }
@@ -0,0 +1,46 @@
1
+ import { resolveEapiConnection } from "../connection/resolveConnection.js";
2
+ import { AppError, toErrorCode, toErrorMessage } from "../core/errors.js";
3
+ import { isObject } from "../utils/value.js";
4
+ import { DiagnosticExecutionError } from "./executionError.js";
5
+ import { buildPingCommand } from "./ping.js";
6
+ export class EapiDiagnosticRunner {
7
+ config;
8
+ runner;
9
+ constructor(config, runner) {
10
+ this.config = config;
11
+ this.runner = runner;
12
+ }
13
+ async execute(host, request, context) {
14
+ let connection;
15
+ try {
16
+ connection = { ...resolveEapiConnection(this.config, host), timeoutMs: this.config.diagnostics.httpTimeoutMs };
17
+ }
18
+ catch (error) {
19
+ throw new DiagnosticExecutionError(toErrorCode(error, "diagnostic_execution_failed"), toErrorMessage(error), "not_dispatched");
20
+ }
21
+ try {
22
+ const results = await this.runner.runTextCommands(connection, [buildPingCommand(request)], { enable: true, signal: context.signal, requestId: context.requestId });
23
+ const output = results[0]?.output;
24
+ if (results.length !== 1 || typeof output !== "string") {
25
+ throw new DiagnosticExecutionError("diagnostic_output_unrecognized", "Expected one text result from EOS", "unknown");
26
+ }
27
+ return { kind: request.kind, output };
28
+ }
29
+ catch (error) {
30
+ // After dispatch, an error is never proof that remote work has stopped.
31
+ const code = toErrorCode(error, "diagnostic_execution_failed");
32
+ if (!["eapi_json_rpc_error", "json_output_unavailable", "eapi_http_error", "eapi_response_invalid_json"].includes(code))
33
+ throw error;
34
+ const data = error instanceof AppError ? error.details?.data : undefined;
35
+ const text = Array.isArray(data)
36
+ ? data.filter(isObject).map((entry) => entry.output).filter((entry) => typeof entry === "string").join("")
37
+ : undefined;
38
+ // Preserve EOS error evidence internally; only the executor's explicit
39
+ // includeRaw path may expose it. RPC error messages contain raw data.
40
+ throw new DiagnosticExecutionError(code, `EOS diagnostic request failed (${code})`, "unknown", {
41
+ raw_output: text || toErrorMessage(error)
42
+ });
43
+ }
44
+ }
45
+ }
46
+ //# sourceMappingURL=eapiRunner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eapiRunner.js","sourceRoot":"","sources":["../../src/diagnostics/eapiRunner.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAG1E,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAG7C,MAAM,OAAO,oBAAoB;IACF;IAA+C;IAA5E,YAA6B,MAA4B,EAAmB,MAA4B;QAA3E,WAAM,GAAN,MAAM,CAAsB;QAAmB,WAAM,GAAN,MAAM,CAAsB;IAAG,CAAC;IAE5G,KAAK,CAAC,OAAO,CAAC,IAAwB,EAAE,OAA2B,EAAE,OAAmC;QACtG,IAAI,UAAgC,CAAC;QACrC,IAAI,CAAC;YACH,UAAU,GAAG,EAAE,GAAG,qBAAqB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,aAAa,EAAE,CAAC;QACjH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,wBAAwB,CAAC,WAAW,CAAC,KAAK,EAAE,6BAA6B,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC,CAAC;QACjI,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,UAAU,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;YACnK,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;YAClC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACvD,MAAM,IAAI,wBAAwB,CAAC,gCAAgC,EAAE,mCAAmC,EAAE,SAAS,CAAC,CAAC;YACvH,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QACxC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,wEAAwE;YACxE,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,6BAA6B,CAAC,CAAC;YAC/D,IAAI,CAAC,CAAC,qBAAqB,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,4BAA4B,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,MAAM,KAAK,CAAC;YACrI,MAAM,IAAI,GAAG,KAAK,YAAY,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;YACzE,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;gBAC9B,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC3H,CAAC,CAAC,SAAS,CAAC;YACd,uEAAuE;YACvE,sEAAsE;YACtE,MAAM,IAAI,wBAAwB,CAAC,IAAI,EAAE,kCAAkC,IAAI,GAAG,EAAE,SAAS,EAAE;gBAC7F,UAAU,EAAE,IAAI,IAAI,cAAc,CAAC,KAAK,CAAC;aAC1C,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ import { AppError } from "../core/errors.js";
2
+ export type DiagnosticExecutionState = "not_dispatched" | "completed" | "unknown";
3
+ /** Explicit adapter classification; ordinary errors leave execution state unknown. */
4
+ export declare class DiagnosticExecutionError extends AppError {
5
+ readonly executionState: DiagnosticExecutionState;
6
+ constructor(code: string, message: string, executionState: DiagnosticExecutionState, details?: Record<string, unknown>);
7
+ }
@@ -0,0 +1,10 @@
1
+ import { AppError } from "../core/errors.js";
2
+ /** Explicit adapter classification; ordinary errors leave execution state unknown. */
3
+ export class DiagnosticExecutionError extends AppError {
4
+ executionState;
5
+ constructor(code, message, executionState, details) {
6
+ super(code, message, details);
7
+ this.executionState = executionState;
8
+ }
9
+ }
10
+ //# sourceMappingURL=executionError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executionError.js","sourceRoot":"","sources":["../../src/diagnostics/executionError.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAI7C,sFAAsF;AACtF,MAAM,OAAO,wBAAyB,SAAQ,QAAQ;IAIzC;IAHX,YACE,IAAY,EACZ,OAAe,EACN,cAAwC,EACjD,OAAiC;QAEjC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAHrB,mBAAc,GAAd,cAAc,CAA0B;IAInD,CAAC;CACF"}
@@ -0,0 +1,32 @@
1
+ import type { ResolvedServerConfig } from "../config/schema.js";
2
+ import type { InventoryModel } from "../inventory/types.js";
3
+ import { type ReadDeviceResultBase, type ReadOperationResultEnvelope } from "../operations/readExecution.js";
4
+ import type { DiagnosticJournal } from "./journalTypes.js";
5
+ import type { DiagnosticCapacitySnapshot, DiagnosticDeviceRunner, DiagnosticFinding, DiagnosticRequest, ResolvedDiagnosticRequest } from "./types.js";
6
+ export interface DiagnosticDeviceResult extends ReadDeviceResultBase {
7
+ destination: string;
8
+ finding?: DiagnosticFinding;
9
+ raw_output?: string;
10
+ }
11
+ export type DiagnosticResult = ReadOperationResultEnvelope<DiagnosticDeviceResult> & {
12
+ request: ResolvedDiagnosticRequest;
13
+ };
14
+ /** Owns policy, budgets, fan-out, global admission, cancellation, and result normalization. */
15
+ export declare class DiagnosticExecutor {
16
+ private readonly model;
17
+ private readonly config;
18
+ private readonly runner;
19
+ private readonly concurrency;
20
+ private readonly shutdown;
21
+ constructor(model: InventoryModel, config: ResolvedServerConfig, runner: DiagnosticDeviceRunner, journal?: DiagnosticJournal);
22
+ close(): void;
23
+ getCapacity(): DiagnosticCapacitySnapshot;
24
+ execute(options: {
25
+ target: string;
26
+ request: DiagnosticRequest;
27
+ includeRaw?: boolean;
28
+ signal?: AbortSignal;
29
+ }): Promise<DiagnosticResult>;
30
+ private runExecution;
31
+ private executeOnDevice;
32
+ }
@@ -0,0 +1,115 @@
1
+ import { AppError, toErrorCode } from "../core/errors.js";
2
+ import { resolveInventoryTarget } from "../inventory/resolveTarget.js";
3
+ import { buildDeviceResultSummary, buildReadDeviceFailure, buildReadDeviceSuccess, buildReadOperationResultEnvelope, enforceReadTargetLimit, mapWithConcurrency, runWithOperationTimeout } from "../operations/readExecution.js";
4
+ import { DiagnosticConcurrency } from "./concurrency.js";
5
+ import { DiagnosticExecutionError } from "./executionError.js";
6
+ import { pingDiagnostic } from "./ping.js";
7
+ const diagnosticDefinitions = {
8
+ ping: pingDiagnostic
9
+ };
10
+ /** Owns policy, budgets, fan-out, global admission, cancellation, and result normalization. */
11
+ export class DiagnosticExecutor {
12
+ model;
13
+ config;
14
+ runner;
15
+ concurrency;
16
+ shutdown = new AbortController();
17
+ constructor(model, config, runner, journal) {
18
+ this.model = model;
19
+ this.config = config;
20
+ this.runner = runner;
21
+ this.concurrency = new DiagnosticConcurrency(config.diagnostics.deviceConcurrency, journal);
22
+ }
23
+ close() {
24
+ this.shutdown.abort(new AppError("diagnostic_server_stopping", "Diagnostic executor is stopping"));
25
+ this.concurrency.close();
26
+ }
27
+ getCapacity() {
28
+ return this.concurrency.snapshot();
29
+ }
30
+ async execute(options) {
31
+ const signal = options.signal === undefined ? this.shutdown.signal : AbortSignal.any([options.signal, this.shutdown.signal]);
32
+ const definition = diagnosticDefinitions[options.request.kind];
33
+ const prepared = definition.prepare(options.request, this.config.diagnostics);
34
+ const operationName = `eos_${options.request.kind}`;
35
+ const operationConfig = {
36
+ ...this.config,
37
+ deviceConcurrency: this.config.diagnostics.deviceConcurrency,
38
+ overallOperationTimeoutMs: this.config.diagnostics.overallOperationTimeoutMs
39
+ };
40
+ const resolvedTarget = resolveInventoryTarget(this.model, { target: options.target });
41
+ enforceReadTargetLimit(operationConfig, resolvedTarget.resolvedHosts.length);
42
+ const denied = resolvedTarget.resolvedHosts.filter((host) => !host.diagnosticsAllowed);
43
+ if (denied.length > 0) {
44
+ throw new AppError("diagnostic_policy_denied", `Diagnostic permission denied for: ${denied.map((host) => host.inventoryHostname).join(", ")}`);
45
+ }
46
+ const probesPerHost = prepared.executions.reduce((total, execution) => total + definition.probeCount(execution), 0);
47
+ if (resolvedTarget.resolvedHosts.length * probesPerHost > this.config.diagnostics.maxProbesPerRequest) {
48
+ throw new AppError("diagnostic_probe_limit_exceeded", `Request exceeds maxProbesPerRequest ${this.config.diagnostics.maxProbesPerRequest}`);
49
+ }
50
+ this.concurrency.assertUsableCapacity();
51
+ // Each host/execution pair takes its own reservation; results stay in host-then-execution order.
52
+ const hostExecutions = resolvedTarget.resolvedHosts.flatMap((host) => prepared.executions.map((execution) => ({ host, execution })));
53
+ const results = await runWithOperationTimeout(operationConfig, operationName, (operationSignal) => mapWithConcurrency(hostExecutions, operationConfig.deviceConcurrency, async ({ host, execution }) => {
54
+ try {
55
+ return await this.runExecution(definition, host, execution, operationSignal, options.includeRaw === true);
56
+ }
57
+ catch (error) {
58
+ return {
59
+ ...buildReadDeviceFailure(host, "diagnostic_execution_failed", error),
60
+ destination: execution.destination,
61
+ ...(options.includeRaw === true && error instanceof AppError && typeof error.details?.raw_output === "string"
62
+ ? { raw_output: error.details.raw_output }
63
+ : {})
64
+ };
65
+ }
66
+ }, operationSignal), signal);
67
+ return buildReadOperationResultEnvelope(options.target, { resolvedTarget, results, summary: buildDeviceResultSummary(results) }, {
68
+ extra: { request: prepared.request },
69
+ responseSizeLimit: { config: this.config, operationName }
70
+ });
71
+ }
72
+ async runExecution(definition, host, execution, signal, includeRaw) {
73
+ const observation = await this.executeOnDevice(host, execution, signal);
74
+ try {
75
+ return buildReadDeviceSuccess(host, {
76
+ destination: execution.destination,
77
+ finding: definition.interpret(observation.output, execution),
78
+ ...(includeRaw ? { raw_output: observation.output } : {})
79
+ });
80
+ }
81
+ catch (error) {
82
+ if (error instanceof AppError && includeRaw) {
83
+ throw new AppError(error.code, error.message, { raw_output: observation.output });
84
+ }
85
+ throw error;
86
+ }
87
+ }
88
+ async executeOnDevice(host, request, signal) {
89
+ const reservation = await this.concurrency.acquire(signal, { inventoryHostname: host.inventoryHostname, diagnostic: request.kind });
90
+ if (signal.aborted) {
91
+ reservation.complete();
92
+ throw new AppError("operation_aborted", "Diagnostic was cancelled before dispatch");
93
+ }
94
+ const onAbort = () => reservation.markUncertain(toErrorCode(signal.reason, "operation_aborted"));
95
+ signal.addEventListener("abort", onAbort, { once: true });
96
+ try {
97
+ const observation = await this.runner.execute(host, request, { signal, requestId: reservation.requestId });
98
+ reservation.complete();
99
+ return observation;
100
+ }
101
+ catch (error) {
102
+ if (error instanceof DiagnosticExecutionError && (error.executionState === "not_dispatched" || error.executionState === "completed")) {
103
+ reservation.complete();
104
+ }
105
+ else {
106
+ reservation.markUncertain(toErrorCode(error, "diagnostic_execution_failed"));
107
+ }
108
+ throw error;
109
+ }
110
+ finally {
111
+ signal.removeEventListener("abort", onAbort);
112
+ }
113
+ }
114
+ }
115
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/diagnostics/executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { DiagnosticJournal } from "./journalTypes.js";
2
+ import type { DiagnosticReservationInfo } from "./types.js";
3
+ import { type DiagnosticReleaseAudit, type DiagnosticReleaseRequest, type DiagnosticReleaseResult } from "./releaseEvidence.js";
4
+ export declare function openDiagnosticJournal(stateFile: string, inventoryIdentity: string): DiagnosticJournal;
5
+ /** No API device calls: release is explicitly authorized operator authority, not observed completion. */
6
+ export declare function releaseDiagnosticReservations(stateFile: string, request: DiagnosticReleaseRequest): DiagnosticReleaseResult;
7
+ export interface DiagnosticJournalInspection {
8
+ schema_version: 1 | 2;
9
+ inventory_identity: string;
10
+ reservations: DiagnosticReservationInfo[];
11
+ release_audit: DiagnosticReleaseAudit[];
12
+ }
13
+ /** Read-only inspection never acquires ownership, clears reservations, or normalizes state. */
14
+ export declare function inspectDiagnosticJournal(stateFile: string): DiagnosticJournalInspection;