@moderniser/plugin 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -2,3 +2,7 @@ export declare const API: () => string;
2
2
  export declare function setStoredKey(key: string): void;
3
3
  export declare function storedKey(): string | undefined;
4
4
  export declare function resolveKey(): string | undefined;
5
+ export declare const COMPANY_HEADER = "x-moderniser-company";
6
+ export declare function setStoredCompany(companyId: string): void;
7
+ export declare function resolveCompany(): string | undefined;
8
+ export declare function companyHeaders(): Record<string, string>;
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import { createRequire } from "node:module";
2
2
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
3
 
4
4
  // packages/plugin/src/client.ts
5
- import { readFileSync } from "node:fs";
5
+ import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
6
6
  import { homedir } from "node:os";
7
7
  import { join } from "node:path";
8
8
  var API = () => (process.env.MODERNISER_API_URL ?? "https://v2.moderniser.ai/api").replace(/\/+$/, "");
@@ -10,9 +10,6 @@ var stored;
10
10
  function setStoredKey(key) {
11
11
  stored = key;
12
12
  }
13
- function storedKey() {
14
- return stored;
15
- }
16
13
  function authFilePath() {
17
14
  const data = process.env.XDG_DATA_HOME || join(homedir(), ".local", "share");
18
15
  return join(data, "moderniser", "auth.json");
@@ -34,6 +31,44 @@ function fromAuthFile() {
34
31
  function resolveKey() {
35
32
  return process.env.MODERNISER_API_KEY ?? stored ?? fromAuthFile();
36
33
  }
34
+ var COMPANY_HEADER = "x-moderniser-company";
35
+ function companyFilePath() {
36
+ const data = process.env.XDG_DATA_HOME || join(homedir(), ".local", "share");
37
+ return join(data, "moderniser", "company.json");
38
+ }
39
+ var storedCompany;
40
+ function setStoredCompany(companyId) {
41
+ storedCompany = companyId;
42
+ fileCompany = companyId;
43
+ try {
44
+ const path = companyFilePath();
45
+ mkdirSync(join(path, ".."), { recursive: true });
46
+ const temp = `${path}.${process.pid}.tmp`;
47
+ writeFileSync(temp, JSON.stringify({ companyId }, null, 2) + `
48
+ `, { mode: 384 });
49
+ renameSync(temp, path);
50
+ } catch {}
51
+ }
52
+ var fileCompany;
53
+ function companyFromFile() {
54
+ if (fileCompany !== undefined)
55
+ return fileCompany ?? undefined;
56
+ fileCompany = null;
57
+ try {
58
+ const parsed = JSON.parse(readFileSync(companyFilePath(), "utf8"));
59
+ if (typeof parsed?.companyId === "string" && parsed.companyId.length > 0) {
60
+ fileCompany = parsed.companyId;
61
+ }
62
+ } catch {}
63
+ return fileCompany ?? undefined;
64
+ }
65
+ function resolveCompany() {
66
+ return process.env.MODERNISER_COMPANY ?? storedCompany ?? companyFromFile();
67
+ }
68
+ function companyHeaders() {
69
+ const company = resolveCompany();
70
+ return company ? { [COMPANY_HEADER]: company } : {};
71
+ }
37
72
 
38
73
  // packages/plugin/src/auth.ts
39
74
  async function start() {
@@ -67,7 +102,7 @@ async function poll(deviceCode, expiresIn, intervalSeconds) {
67
102
  continue;
68
103
  }
69
104
  if (body.token)
70
- return body.token;
105
+ return { token: body.token, companyId: body.companyId };
71
106
  if (body.error === "authorization_pending")
72
107
  continue;
73
108
  if (body.error === "slow_down") {
@@ -92,11 +127,13 @@ function moderniserAuth() {
92
127
  instructions: `Check that your browser shows this code: ${started.userCode}. After signing in for the first time, restart to pick up the Moderniser tools.`,
93
128
  method: "auto",
94
129
  async callback() {
95
- const token = await poll(started.deviceCode, started.expiresIn, started.interval);
96
- if (!token)
130
+ const collected = await poll(started.deviceCode, started.expiresIn, started.interval);
131
+ if (!collected)
97
132
  return { type: "failed" };
98
- setStoredKey(token);
99
- return { type: "success", key: token };
133
+ setStoredKey(collected.token);
134
+ if (collected.companyId)
135
+ setStoredCompany(collected.companyId);
136
+ return { type: "success", key: collected.token };
100
137
  }
101
138
  };
102
139
  }
@@ -152,13 +189,13 @@ var GATEWAY = () => {
152
189
  var PROVIDER_ID = "moderniser";
153
190
  var DEFAULT_MODEL = `${PROVIDER_ID}/emm`;
154
191
  async function call(path, body) {
155
- const key = KEY() ?? storedKey();
192
+ const key = resolveKey();
156
193
  if (!key)
157
194
  return null;
158
195
  try {
159
196
  return await fetch(`${API2()}${path}`, {
160
197
  method: "POST",
161
- headers: { "Content-Type": "application/json", Authorization: `Bearer ${key}` },
198
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${key}`, ...companyHeaders() },
162
199
  body: JSON.stringify(body),
163
200
  signal: AbortSignal.timeout(1e4)
164
201
  });
@@ -169,13 +206,40 @@ async function call(path, body) {
169
206
  function positiveInt(value) {
170
207
  return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : undefined;
171
208
  }
209
+ function price(value) {
210
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined;
211
+ }
212
+ async function companyPrices() {
213
+ const key = resolveKey();
214
+ if (!key)
215
+ return;
216
+ try {
217
+ const res = await fetch(`${API2()}/billing/prices`, {
218
+ headers: { Authorization: `Bearer ${key}`, ...companyHeaders() },
219
+ signal: AbortSignal.timeout(5000)
220
+ });
221
+ if (!res.ok)
222
+ return;
223
+ const body = await res.json();
224
+ const input = price(body.inputUsdPerMtok);
225
+ const output = price(body.outputUsdPerMtok);
226
+ const cache_read = price(body.cachedInputUsdPerMtok);
227
+ const cache_write = price(body.cacheWriteUsdPerMtok);
228
+ if (input === undefined || output === undefined || cache_read === undefined || cache_write === undefined) {
229
+ return;
230
+ }
231
+ return { input, output, cache_read, cache_write };
232
+ } catch {
233
+ return;
234
+ }
235
+ }
172
236
  async function gatewayProduct() {
173
- const key = KEY() ?? storedKey();
237
+ const key = resolveKey();
174
238
  if (!key)
175
239
  return {};
176
240
  try {
177
241
  const res = await fetch(`${GATEWAY()}/models`, {
178
- headers: { Authorization: `Bearer ${key}` },
242
+ headers: { Authorization: `Bearer ${key}`, ...companyHeaders() },
179
243
  signal: AbortSignal.timeout(5000)
180
244
  });
181
245
  if (!res.ok)
@@ -199,8 +263,12 @@ var ModerniserPlugin = async () => {
199
263
  return {
200
264
  config: async (config) => {
201
265
  const modalities = { input: ["text", "image"], output: ["text"] };
202
- const product = await gatewayProduct();
266
+ const [product, prices] = await Promise.all([gatewayProduct(), companyPrices()]);
203
267
  const efforts = (product.efforts ?? ["high"]).filter((effort) => effort !== "default");
268
+ const limit = {
269
+ ...product.contextWindow ? { context: product.contextWindow } : {},
270
+ ...product.maxOutputTokens ? { output: product.maxOutputTokens } : {}
271
+ };
204
272
  const models = {
205
273
  emm: {
206
274
  name: "Enterprise Modernisation Model",
@@ -208,15 +276,21 @@ var ModerniserPlugin = async () => {
208
276
  reasoning: true,
209
277
  modalities,
210
278
  variants: Object.fromEntries(efforts.map((effort) => [effort, { reasoning_effort: effort }])),
211
- ...product.contextWindow && product.maxOutputTokens ? { limit: { context: product.contextWindow, output: product.maxOutputTokens } } : {}
279
+ ...Object.keys(limit).length ? { limit } : {},
280
+ ...prices ? { cost: prices } : {}
212
281
  }
213
282
  };
214
283
  const key = KEY();
284
+ const company = companyHeaders();
215
285
  config.provider ??= {};
216
286
  config.provider[PROVIDER_ID] ??= {
217
287
  name: "Moderniser",
218
288
  npm: "@ai-sdk/openai-compatible",
219
- options: { baseURL: GATEWAY(), ...key ? { apiKey: key } : {} },
289
+ options: {
290
+ baseURL: GATEWAY(),
291
+ ...key ? { apiKey: key } : {},
292
+ ...Object.keys(company).length ? { headers: company } : {}
293
+ },
220
294
  models
221
295
  };
222
296
  config.enabled_providers ??= [PROVIDER_ID];
@@ -231,7 +305,7 @@ var ModerniserPlugin = async () => {
231
305
  config.mcp[PROVIDER_ID] ??= {
232
306
  type: "remote",
233
307
  url: `${API2()}/mcp`,
234
- headers: { Authorization: `Bearer ${mcpKey}` },
308
+ headers: { Authorization: `Bearer ${mcpKey}`, ...companyHeaders() },
235
309
  oauth: false
236
310
  };
237
311
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moderniser/plugin",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "type": "module",
5
5
  "description": "Moderniser plugin for opencode: points inference at the gateway, declares the Moderniser remote MCP server, and reports session telemetry",
6
6
  "license": "MIT",