@danielblomma/cortex-mcp 2.4.0 → 2.4.2

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 (214) hide show
  1. package/CHANGELOG.md +226 -0
  2. package/README.md +24 -3
  3. package/bin/cli/arguments.mjs +60 -0
  4. package/bin/cli/context-passthrough.mjs +129 -0
  5. package/bin/cli/daemon.mjs +157 -0
  6. package/bin/cli/enterprise.mjs +516 -0
  7. package/bin/cli/help.mjs +88 -0
  8. package/bin/cli/hooks.mjs +199 -0
  9. package/bin/cli/mcp-command.mjs +87 -0
  10. package/bin/cli/paths.mjs +14 -0
  11. package/bin/cli/process.mjs +49 -0
  12. package/bin/cli/project-commands.mjs +237 -0
  13. package/bin/cli/project-runtime.mjs +34 -0
  14. package/bin/cli/query-command.mjs +18 -0
  15. package/bin/cli/router.mjs +66 -0
  16. package/bin/cli/run-command.mjs +44 -0
  17. package/bin/cli/scaffold-ownership.mjs +936 -0
  18. package/bin/cli/scaffold.mjs +687 -0
  19. package/bin/cli/stage-command.mjs +9 -0
  20. package/bin/cli/telemetry-command.mjs +18 -0
  21. package/bin/cli/trusted-runtime.mjs +18 -0
  22. package/bin/cortex.mjs +12 -1607
  23. package/bin/daemon-control.mjs +162 -0
  24. package/mcp-registry-submission.json +1 -1
  25. package/package.json +8 -3
  26. package/scaffold/mcp/dist/.cortex-build-hash +1 -0
  27. package/scaffold/mcp/dist/cli/enterprise-setup.js +134 -0
  28. package/scaffold/mcp/dist/cli/govern.js +937 -0
  29. package/scaffold/mcp/dist/cli/query.js +409 -0
  30. package/scaffold/mcp/dist/cli/run.js +295 -0
  31. package/scaffold/mcp/dist/cli/stage.js +308 -0
  32. package/scaffold/mcp/dist/cli/telemetry-test.js +141 -0
  33. package/scaffold/mcp/dist/cli/ungoverned-detector.js +133 -0
  34. package/scaffold/mcp/dist/contextEntities.js +282 -0
  35. package/scaffold/mcp/dist/core/audit/query.js +72 -0
  36. package/scaffold/mcp/dist/core/audit/writer.js +28 -0
  37. package/scaffold/mcp/dist/core/config.js +235 -0
  38. package/scaffold/mcp/dist/core/enterprise-host-identity.js +193 -0
  39. package/scaffold/mcp/dist/core/enterprise-identity.js +18 -0
  40. package/scaffold/mcp/dist/core/enterprise-rotation.js +158 -0
  41. package/scaffold/mcp/dist/core/govern-paths.js +21 -0
  42. package/scaffold/mcp/dist/core/index.js +14 -0
  43. package/scaffold/mcp/dist/core/license.js +278 -0
  44. package/scaffold/mcp/dist/core/policy/enforce.js +66 -0
  45. package/scaffold/mcp/dist/core/policy/injection.js +172 -0
  46. package/scaffold/mcp/dist/core/policy/store.js +179 -0
  47. package/scaffold/mcp/dist/core/rbac/check.js +30 -0
  48. package/scaffold/mcp/dist/core/secure-endpoint.js +25 -0
  49. package/scaffold/mcp/dist/core/telemetry/collector.js +285 -0
  50. package/scaffold/mcp/dist/core/telemetry/state-dir.js +31 -0
  51. package/scaffold/mcp/dist/core/validators/builtins.js +632 -0
  52. package/scaffold/mcp/dist/core/validators/config.js +44 -0
  53. package/scaffold/mcp/dist/core/validators/engine.js +120 -0
  54. package/scaffold/mcp/dist/core/validators/evaluators/code_comments.js +236 -0
  55. package/scaffold/mcp/dist/core/validators/evaluators/regex.js +116 -0
  56. package/scaffold/mcp/dist/core/workflow/artifact-io.js +103 -0
  57. package/scaffold/mcp/dist/core/workflow/capabilities.js +88 -0
  58. package/scaffold/mcp/dist/core/workflow/default-workflows.js +102 -0
  59. package/scaffold/mcp/dist/core/workflow/enforcement.js +164 -0
  60. package/scaffold/mcp/dist/core/workflow/envelope.js +132 -0
  61. package/scaffold/mcp/dist/core/workflow/index.js +11 -0
  62. package/scaffold/mcp/dist/core/workflow/mcp-tools.js +175 -0
  63. package/scaffold/mcp/dist/core/workflow/resolution.js +69 -0
  64. package/scaffold/mcp/dist/core/workflow/run-lifecycle.js +123 -0
  65. package/scaffold/mcp/dist/core/workflow/schemas.js +141 -0
  66. package/scaffold/mcp/dist/core/workflow/synced-capability-registry.js +60 -0
  67. package/scaffold/mcp/dist/core/workflow/synced-registry.js +60 -0
  68. package/scaffold/mcp/dist/daemon/capability-sync-checker.js +242 -0
  69. package/scaffold/mcp/dist/daemon/client.js +130 -0
  70. package/scaffold/mcp/dist/daemon/egress-proxy.js +288 -0
  71. package/scaffold/mcp/dist/daemon/global-host-events.js +222 -0
  72. package/scaffold/mcp/dist/daemon/heartbeat-pusher.js +116 -0
  73. package/scaffold/mcp/dist/daemon/heartbeat-tracker.js +165 -0
  74. package/scaffold/mcp/dist/daemon/host-events-pusher.js +249 -0
  75. package/scaffold/mcp/dist/daemon/main.js +449 -0
  76. package/scaffold/mcp/dist/daemon/paths.js +36 -0
  77. package/scaffold/mcp/dist/daemon/project-service-registry.js +78 -0
  78. package/scaffold/mcp/dist/daemon/protocol.js +8 -0
  79. package/scaffold/mcp/dist/daemon/server.js +180 -0
  80. package/scaffold/mcp/dist/daemon/skill-sync-checker.js +557 -0
  81. package/scaffold/mcp/dist/daemon/sync-checker.js +165 -0
  82. package/scaffold/mcp/dist/daemon/ungoverned-scanner.js +136 -0
  83. package/scaffold/mcp/dist/daemon/workflow-sync-checker.js +249 -0
  84. package/scaffold/mcp/dist/defaults.js +6 -0
  85. package/scaffold/mcp/dist/embed.js +627 -0
  86. package/scaffold/mcp/dist/embedScheduler.js +479 -0
  87. package/scaffold/mcp/dist/embeddings.js +167 -0
  88. package/scaffold/mcp/dist/enterprise/audit/push.js +66 -0
  89. package/scaffold/mcp/dist/enterprise/index.js +327 -0
  90. package/scaffold/mcp/dist/enterprise/model/deploy.js +27 -0
  91. package/scaffold/mcp/dist/enterprise/policy/sync.js +129 -0
  92. package/scaffold/mcp/dist/enterprise/privacy/boundary.js +184 -0
  93. package/scaffold/mcp/dist/enterprise/reviews/changed-files.js +33 -0
  94. package/scaffold/mcp/dist/enterprise/reviews/pattern-context.js +202 -0
  95. package/scaffold/mcp/dist/enterprise/reviews/policy-selection.js +46 -0
  96. package/scaffold/mcp/dist/enterprise/reviews/push.js +102 -0
  97. package/scaffold/mcp/dist/enterprise/reviews/trust-state.js +186 -0
  98. package/scaffold/mcp/dist/enterprise/telemetry/sync.js +57 -0
  99. package/scaffold/mcp/dist/enterprise/tools/enterprise.js +826 -0
  100. package/scaffold/mcp/dist/enterprise/tools/harness.js +40 -0
  101. package/scaffold/mcp/dist/enterprise/tools/walk.js +73 -0
  102. package/scaffold/mcp/dist/enterprise/violations/push.js +77 -0
  103. package/scaffold/mcp/dist/enterprise/workflow/push.js +44 -0
  104. package/scaffold/mcp/dist/enterprise/workflow/state.js +329 -0
  105. package/scaffold/mcp/dist/frontmatter.js +33 -0
  106. package/scaffold/mcp/dist/graph.js +769 -0
  107. package/scaffold/mcp/dist/graphCsv.js +55 -0
  108. package/scaffold/mcp/dist/graphMetrics.js +8 -0
  109. package/scaffold/mcp/dist/hooks/permission-request.js +89 -0
  110. package/scaffold/mcp/dist/hooks/post-tool-use.js +105 -0
  111. package/scaffold/mcp/dist/hooks/pre-compact.js +29 -0
  112. package/scaffold/mcp/dist/hooks/pre-tool-use.js +78 -0
  113. package/scaffold/mcp/dist/hooks/session-end.js +43 -0
  114. package/scaffold/mcp/dist/hooks/session-start.js +41 -0
  115. package/scaffold/mcp/dist/hooks/shared.js +194 -0
  116. package/scaffold/mcp/dist/hooks/stop.js +28 -0
  117. package/scaffold/mcp/dist/hooks/user-prompt-submit.js +33 -0
  118. package/scaffold/mcp/dist/impactPresentation.js +137 -0
  119. package/scaffold/mcp/dist/impactRanking.js +191 -0
  120. package/scaffold/mcp/dist/impactResponse.js +30 -0
  121. package/scaffold/mcp/dist/impactResults.js +105 -0
  122. package/scaffold/mcp/dist/impactSeed.js +20 -0
  123. package/scaffold/mcp/dist/impactTraversal.js +64 -0
  124. package/scaffold/mcp/dist/jsonl.js +77 -0
  125. package/scaffold/mcp/dist/loadGraph.js +759 -0
  126. package/scaffold/mcp/dist/lruCache.js +38 -0
  127. package/scaffold/mcp/dist/paths.js +97 -0
  128. package/scaffold/mcp/dist/patternEvidence.js +272 -0
  129. package/scaffold/mcp/dist/plugin.js +81 -0
  130. package/scaffold/mcp/dist/presets.js +78 -0
  131. package/scaffold/mcp/dist/relatedResponse.js +18 -0
  132. package/scaffold/mcp/dist/relatedTraversal.js +78 -0
  133. package/scaffold/mcp/dist/rules.js +23 -0
  134. package/scaffold/mcp/dist/search.js +212 -0
  135. package/scaffold/mcp/dist/searchCore.js +457 -0
  136. package/scaffold/mcp/dist/searchResults.js +230 -0
  137. package/scaffold/mcp/dist/server.js +317 -0
  138. package/scaffold/mcp/dist/types.js +1 -0
  139. package/scaffold/mcp/package-lock.json +321 -200
  140. package/scaffold/mcp/package.json +15 -6
  141. package/scaffold/mcp/src/cli/enterprise-setup.ts +82 -8
  142. package/scaffold/mcp/src/cli/govern.ts +137 -52
  143. package/scaffold/mcp/src/cli/run.ts +53 -19
  144. package/scaffold/mcp/src/cli/stage.ts +8 -3
  145. package/scaffold/mcp/src/core/config.ts +9 -2
  146. package/scaffold/mcp/src/core/enterprise-host-identity.ts +259 -0
  147. package/scaffold/mcp/src/core/enterprise-identity.ts +20 -0
  148. package/scaffold/mcp/src/core/enterprise-rotation.ts +185 -0
  149. package/scaffold/mcp/src/core/govern-paths.ts +30 -0
  150. package/scaffold/mcp/src/core/license.ts +186 -17
  151. package/scaffold/mcp/src/core/secure-endpoint.ts +23 -0
  152. package/scaffold/mcp/src/core/workflow/enforcement.ts +8 -1
  153. package/scaffold/mcp/src/core/workflow/mcp-tools.ts +3 -0
  154. package/scaffold/mcp/src/core/workflow/resolution.ts +9 -1
  155. package/scaffold/mcp/src/core/workflow/synced-capability-registry.ts +15 -0
  156. package/scaffold/mcp/src/core/workflow/synced-registry.ts +15 -0
  157. package/scaffold/mcp/src/daemon/capability-sync-checker.ts +38 -2
  158. package/scaffold/mcp/src/daemon/egress-proxy.ts +14 -8
  159. package/scaffold/mcp/src/daemon/global-host-events.ts +288 -0
  160. package/scaffold/mcp/src/daemon/heartbeat-pusher.ts +4 -0
  161. package/scaffold/mcp/src/daemon/heartbeat-tracker.ts +2 -0
  162. package/scaffold/mcp/src/daemon/host-events-pusher.ts +5 -0
  163. package/scaffold/mcp/src/daemon/main.ts +99 -25
  164. package/scaffold/mcp/src/daemon/project-service-registry.ts +107 -0
  165. package/scaffold/mcp/src/daemon/skill-sync-checker.ts +368 -31
  166. package/scaffold/mcp/src/daemon/sync-checker.ts +4 -0
  167. package/scaffold/mcp/src/daemon/ungoverned-scanner.ts +57 -25
  168. package/scaffold/mcp/src/daemon/workflow-sync-checker.ts +41 -2
  169. package/scaffold/mcp/src/enterprise/audit/push.ts +8 -0
  170. package/scaffold/mcp/src/enterprise/policy/sync.ts +12 -0
  171. package/scaffold/mcp/src/enterprise/reviews/push.ts +9 -0
  172. package/scaffold/mcp/src/enterprise/reviews/trust-state.ts +3 -1
  173. package/scaffold/mcp/src/enterprise/telemetry/sync.ts +9 -0
  174. package/scaffold/mcp/src/enterprise/violations/push.ts +9 -0
  175. package/scaffold/mcp/src/enterprise/workflow/push.ts +7 -0
  176. package/scaffold/mcp/src/plugin.ts +20 -0
  177. package/scaffold/mcp/tests/copilot-shim.test.mjs +19 -1
  178. package/scaffold/mcp/tests/egress-proxy.test.mjs +37 -0
  179. package/scaffold/mcp/tests/enterprise-identity-sync.test.mjs +401 -0
  180. package/scaffold/mcp/tests/enterprise-setup.test.mjs +189 -0
  181. package/scaffold/mcp/tests/global-host-events.test.mjs +81 -0
  182. package/scaffold/mcp/tests/govern-install.test.mjs +95 -2
  183. package/scaffold/mcp/tests/govern-repair.test.mjs +20 -3
  184. package/scaffold/mcp/tests/heartbeat-tracker.test.mjs +26 -0
  185. package/scaffold/mcp/tests/license.test.mjs +367 -0
  186. package/scaffold/mcp/tests/project-service-registry.test.mjs +172 -0
  187. package/scaffold/mcp/tests/review-trust-contract.test.mjs +18 -0
  188. package/scaffold/mcp/tests/secure-enterprise-endpoint.test.mjs +46 -0
  189. package/scaffold/mcp/tests/skill-sync-checker.test.mjs +446 -2
  190. package/scaffold/mcp/tests/ungoverned-scanner.test.mjs +104 -22
  191. package/scaffold/mcp/tests/workflow-cli.test.mjs +14 -1
  192. package/scaffold/mcp/tests/workflow-synced-capabilities.test.mjs +37 -0
  193. package/scaffold/mcp/tests/workflow-synced-registry.test.mjs +40 -1
  194. package/scaffold/ownership/baseline-v2.4.1.json +22 -0
  195. package/scaffold/ownership/current.json +4 -0
  196. package/scaffold/ownership/v1.json +456 -0
  197. package/scaffold/scripts/ingest-parsers.mjs +1 -387
  198. package/scaffold/scripts/ingest-worker.mjs +4 -1
  199. package/scaffold/scripts/ingest.mjs +5 -3899
  200. package/scaffold/scripts/lib/ingest/arguments.mjs +78 -0
  201. package/scaffold/scripts/lib/ingest/chunks.mjs +212 -0
  202. package/scaffold/scripts/lib/ingest/config.mjs +120 -0
  203. package/scaffold/scripts/lib/ingest/constants.mjs +222 -0
  204. package/scaffold/scripts/lib/ingest/files.mjs +387 -0
  205. package/scaffold/scripts/lib/ingest/incremental-state.mjs +131 -0
  206. package/scaffold/scripts/lib/ingest/io.mjs +78 -0
  207. package/scaffold/scripts/lib/ingest/main.mjs +76 -0
  208. package/scaffold/scripts/lib/ingest/parser-composition.mjs +140 -0
  209. package/scaffold/scripts/lib/ingest/parser-registry.mjs +387 -0
  210. package/scaffold/scripts/lib/ingest/pipeline-stages.mjs +1625 -0
  211. package/scaffold/scripts/lib/ingest/projects.mjs +272 -0
  212. package/scaffold/scripts/lib/ingest/relations.mjs +860 -0
  213. package/scaffold/scripts/lib/ingest/runtime-paths.mjs +11 -0
  214. package/scaffold/scripts/lib/ingest/workers.mjs +264 -0
@@ -0,0 +1,186 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { setWorkflowReviewTrust } from "../workflow/state.js";
4
+ import { resolveWorkflowDefinition } from "../../core/workflow/resolution.js";
5
+ function trustStatePath(contextDir) {
6
+ return join(contextDir, "review-trust.json");
7
+ }
8
+ function nowIso() {
9
+ return new Date().toISOString();
10
+ }
11
+ function initialTrustState() {
12
+ return {
13
+ version: 1,
14
+ repo: null,
15
+ instance_id: null,
16
+ session_id: null,
17
+ workflow: {
18
+ id: null,
19
+ source: "unknown",
20
+ task_id: null,
21
+ },
22
+ last_review_at: null,
23
+ review_summary: null,
24
+ skipped_policies: [],
25
+ delivery: {
26
+ status: "never_attempted",
27
+ review_count: 0,
28
+ queued_at: null,
29
+ last_attempted_at: null,
30
+ last_pushed_at: null,
31
+ last_accepted_at: null,
32
+ last_error: null,
33
+ },
34
+ trust_warnings: [],
35
+ };
36
+ }
37
+ function ensureContextDir(contextDir) {
38
+ mkdirSync(contextDir, { recursive: true });
39
+ }
40
+ function inferWorkflow(projectRoot, taskId) {
41
+ const normalizedTaskId = taskId?.trim();
42
+ if (!normalizedTaskId) {
43
+ return { id: null, source: "unknown", task_id: null };
44
+ }
45
+ const statePath = join(projectRoot, ".agents", normalizedTaskId, "state.json");
46
+ if (!existsSync(statePath)) {
47
+ return { id: null, source: "unknown", task_id: normalizedTaskId };
48
+ }
49
+ try {
50
+ const raw = JSON.parse(readFileSync(statePath, "utf8"));
51
+ const workflowId = typeof raw.workflow_id === "string" ? raw.workflow_id : null;
52
+ if (!workflowId) {
53
+ return { id: null, source: "unknown", task_id: normalizedTaskId };
54
+ }
55
+ const resolved = resolveWorkflowDefinition(workflowId, {
56
+ cwd: projectRoot,
57
+ });
58
+ return {
59
+ id: workflowId,
60
+ source: resolved.source,
61
+ task_id: normalizedTaskId,
62
+ };
63
+ }
64
+ catch {
65
+ return {
66
+ id: null,
67
+ source: "unknown",
68
+ task_id: normalizedTaskId,
69
+ };
70
+ }
71
+ }
72
+ function computeWarnings(state) {
73
+ const warnings = [];
74
+ if (!state.workflow.id) {
75
+ warnings.push({
76
+ code: "workflow-unresolved",
77
+ message: "No active local workflow could be resolved for this review session, so workflow/review correlation is unproven.",
78
+ });
79
+ }
80
+ else if (state.workflow.source !== "synced") {
81
+ warnings.push({
82
+ code: "workflow-source-unverified",
83
+ message: `Workflow "${state.workflow.id}" is not proven to come from the synced org registry for this session.`,
84
+ });
85
+ }
86
+ if (state.delivery.status === "queued" || state.delivery.status === "pushed") {
87
+ warnings.push({
88
+ code: "review-delivery-pending",
89
+ message: "Local review results exist for this session, but Cortex has not yet confirmed acceptance by the control plane.",
90
+ });
91
+ }
92
+ if (state.delivery.status === "failed") {
93
+ warnings.push({
94
+ code: "review-delivery-failed",
95
+ message: `Review delivery failed${state.delivery.last_error ? `: ${state.delivery.last_error}` : ""}`,
96
+ });
97
+ }
98
+ if (state.skipped_policies.length > 0) {
99
+ warnings.push({
100
+ code: "policy-not-enforceable",
101
+ message: `${state.skipped_policies.length} configured policy` +
102
+ `${state.skipped_policies.length === 1 ? " was" : "ies were"} not enforceable locally.`,
103
+ });
104
+ }
105
+ return warnings;
106
+ }
107
+ export function loadReviewTrustState(contextDir) {
108
+ ensureContextDir(contextDir);
109
+ const filePath = trustStatePath(contextDir);
110
+ if (!existsSync(filePath)) {
111
+ const initial = initialTrustState();
112
+ writeReviewTrustState(contextDir, initial);
113
+ return initial;
114
+ }
115
+ try {
116
+ const parsed = JSON.parse(readFileSync(filePath, "utf8"));
117
+ parsed.trust_warnings = computeWarnings(parsed);
118
+ return parsed;
119
+ }
120
+ catch {
121
+ const initial = initialTrustState();
122
+ writeReviewTrustState(contextDir, initial);
123
+ return initial;
124
+ }
125
+ }
126
+ export function writeReviewTrustState(contextDir, state) {
127
+ ensureContextDir(contextDir);
128
+ state.trust_warnings = computeWarnings(state);
129
+ writeFileSync(trustStatePath(contextDir), `${JSON.stringify(state, null, 2)}\n`, "utf8");
130
+ setWorkflowReviewTrust(contextDir, state);
131
+ return state;
132
+ }
133
+ export function recordQueuedReviewTrustState(context, input) {
134
+ const state = loadReviewTrustState(context.contextDir);
135
+ const workflow = inferWorkflow(context.projectRoot, context.task_id);
136
+ state.repo = context.repo ?? state.repo;
137
+ state.instance_id = context.instance_id ?? state.instance_id;
138
+ state.session_id = context.session_id ?? state.session_id;
139
+ state.workflow = workflow;
140
+ state.last_review_at = input.reviewedAt;
141
+ state.review_summary = {
142
+ total: input.summary.total,
143
+ passed: input.summary.passed,
144
+ failed: input.summary.failed,
145
+ warnings: input.summary.warnings,
146
+ skipped: input.summary.skipped,
147
+ };
148
+ state.skipped_policies = input.skippedPolicies;
149
+ const hasQueuedReviews = input.summary.total > 0;
150
+ state.delivery = {
151
+ status: hasQueuedReviews ? "queued" : "never_attempted",
152
+ review_count: input.summary.total,
153
+ queued_at: hasQueuedReviews ? input.reviewedAt : null,
154
+ last_attempted_at: null,
155
+ last_pushed_at: null,
156
+ last_accepted_at: null,
157
+ last_error: null,
158
+ };
159
+ return writeReviewTrustState(context.contextDir, state);
160
+ }
161
+ export function recordReviewDeliveryStatus(contextDir, status, input = {}) {
162
+ const state = loadReviewTrustState(contextDir);
163
+ const at = input.attemptedAt ?? nowIso();
164
+ state.delivery.review_count = input.reviewCount ?? state.delivery.review_count;
165
+ state.delivery.last_attempted_at = at;
166
+ if (status === "pushed") {
167
+ state.delivery.status = "pushed";
168
+ state.delivery.last_pushed_at = at;
169
+ state.delivery.last_error = null;
170
+ }
171
+ else if (status === "accepted") {
172
+ state.delivery.status = "accepted";
173
+ state.delivery.last_pushed_at = at;
174
+ state.delivery.last_accepted_at = at;
175
+ state.delivery.last_error = null;
176
+ }
177
+ else if (status === "failed") {
178
+ state.delivery.status = "failed";
179
+ state.delivery.last_pushed_at = at;
180
+ state.delivery.last_error = input.error ?? "unknown error";
181
+ }
182
+ else {
183
+ state.delivery.status = status;
184
+ }
185
+ return writeReviewTrustState(contextDir, state);
186
+ }
@@ -0,0 +1,57 @@
1
+ import { isAllowedEnterpriseEndpoint } from "../../core/secure-endpoint.js";
2
+ import { buildTelemetryPushPayload } from "../privacy/boundary.js";
3
+ let lastPush = null;
4
+ export function getLastPush() {
5
+ return lastPush;
6
+ }
7
+ /**
8
+ * Push aggregated metrics to the Cortex Cloud API.
9
+ * Connected edition only. Returns success/failure.
10
+ *
11
+ * The actual cloud API is built in Phase 4 — this sends a POST
12
+ * with JSON body and expects a 2xx response.
13
+ */
14
+ export async function pushMetrics(metrics, endpoint, apiKey, context = {}) {
15
+ if (!endpoint || !apiKey) {
16
+ const result = { success: false, error: "endpoint or api_key not configured" };
17
+ lastPush = result;
18
+ return result;
19
+ }
20
+ if (!isAllowedEnterpriseEndpoint(endpoint)) {
21
+ const result = {
22
+ success: false,
23
+ error: "insecure or invalid enterprise endpoint",
24
+ };
25
+ lastPush = result;
26
+ return result;
27
+ }
28
+ try {
29
+ const response = await fetch(endpoint, {
30
+ method: "POST",
31
+ headers: {
32
+ "Content-Type": "application/json",
33
+ "Authorization": `Bearer ${apiKey}`,
34
+ },
35
+ body: JSON.stringify(buildTelemetryPushPayload(metrics, context)),
36
+ signal: AbortSignal.timeout(10000),
37
+ });
38
+ const result = {
39
+ success: response.ok,
40
+ status: response.status,
41
+ pushed_at: new Date().toISOString(),
42
+ };
43
+ if (!response.ok) {
44
+ result.error = `HTTP ${response.status}`;
45
+ }
46
+ lastPush = result;
47
+ return result;
48
+ }
49
+ catch (err) {
50
+ const result = {
51
+ success: false,
52
+ error: err instanceof Error ? err.message : "unknown error",
53
+ };
54
+ lastPush = result;
55
+ return result;
56
+ }
57
+ }