@aeolus-fleet/trierarch 0.33.1 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/README.md +7 -4
  2. package/dist/adapters/claude-code-setup.d.ts +11 -0
  3. package/dist/adapters/claude-code-setup.js +60 -0
  4. package/dist/adapters/claude-code-setup.js.map +1 -1
  5. package/dist/adapters/claude-code.d.ts +21 -18
  6. package/dist/adapters/claude-code.js +46 -36
  7. package/dist/adapters/claude-code.js.map +1 -1
  8. package/dist/adapters/codex-setup.d.ts +2 -0
  9. package/dist/adapters/codex-setup.js +6 -0
  10. package/dist/adapters/codex-setup.js.map +1 -1
  11. package/dist/adapters/codex.d.ts +2 -0
  12. package/dist/adapters/codex.js +31 -3
  13. package/dist/adapters/codex.js.map +1 -1
  14. package/dist/adapters/container.d.ts +36 -15
  15. package/dist/adapters/container.js +72 -93
  16. package/dist/adapters/container.js.map +1 -1
  17. package/dist/adapters/copilot-detector.d.ts +13 -0
  18. package/dist/adapters/copilot-detector.js +62 -0
  19. package/dist/adapters/copilot-detector.js.map +1 -0
  20. package/dist/adapters/copilot.d.ts +79 -0
  21. package/dist/adapters/copilot.js +187 -0
  22. package/dist/adapters/copilot.js.map +1 -0
  23. package/dist/adapters/detectors.js +6 -0
  24. package/dist/adapters/detectors.js.map +1 -1
  25. package/dist/adapters/files.d.ts +16 -0
  26. package/dist/adapters/files.js +5 -0
  27. package/dist/adapters/files.js.map +1 -1
  28. package/dist/adapters/harnesses.d.ts +3 -2
  29. package/dist/adapters/harnesses.js +21 -9
  30. package/dist/adapters/harnesses.js.map +1 -1
  31. package/dist/adapters/hold-runtime.d.ts +19 -5
  32. package/dist/adapters/hold-runtime.js +23 -10
  33. package/dist/adapters/hold-runtime.js.map +1 -1
  34. package/dist/adapters/hold.d.ts +12 -0
  35. package/dist/adapters/hold.js +66 -31
  36. package/dist/adapters/hold.js.map +1 -1
  37. package/dist/adapters/json-state.js +4 -0
  38. package/dist/adapters/json-state.js.map +1 -1
  39. package/dist/adapters/key-files.d.ts +16 -0
  40. package/dist/adapters/key-files.js +28 -0
  41. package/dist/adapters/key-files.js.map +1 -0
  42. package/dist/adapters/key-states.d.ts +21 -0
  43. package/dist/adapters/key-states.js +43 -0
  44. package/dist/adapters/key-states.js.map +1 -0
  45. package/dist/adapters/model-logins.d.ts +21 -0
  46. package/dist/adapters/model-logins.js +48 -0
  47. package/dist/adapters/model-logins.js.map +1 -0
  48. package/dist/adapters/model-proxy.d.ts +32 -0
  49. package/dist/adapters/model-proxy.js +171 -0
  50. package/dist/adapters/model-proxy.js.map +1 -0
  51. package/dist/adapters/paths.d.ts +4 -0
  52. package/dist/adapters/paths.js +2 -0
  53. package/dist/adapters/paths.js.map +1 -1
  54. package/dist/adapters/plugin.d.ts +11 -8
  55. package/dist/adapters/plugin.js +47 -13
  56. package/dist/adapters/plugin.js.map +1 -1
  57. package/dist/adapters/proxy-runtime.d.ts +31 -0
  58. package/dist/adapters/proxy-runtime.js +100 -0
  59. package/dist/adapters/proxy-runtime.js.map +1 -0
  60. package/dist/adapters/proxy-tokens.d.ts +25 -0
  61. package/dist/adapters/proxy-tokens.js +67 -0
  62. package/dist/adapters/proxy-tokens.js.map +1 -0
  63. package/dist/adapters/runtime-adapters.d.ts +11 -6
  64. package/dist/adapters/runtime-adapters.js +25 -11
  65. package/dist/adapters/runtime-adapters.js.map +1 -1
  66. package/dist/adapters/service.d.ts +1 -1
  67. package/dist/adapters/service.js +2 -2
  68. package/dist/adapters/service.js.map +1 -1
  69. package/dist/adapters/trust.d.ts +2 -1
  70. package/dist/adapters/trust.js +4 -1
  71. package/dist/adapters/trust.js.map +1 -1
  72. package/dist/adapters/vendor-answers.d.ts +6 -0
  73. package/dist/adapters/vendor-answers.js +38 -0
  74. package/dist/adapters/vendor-answers.js.map +1 -0
  75. package/dist/adapters/vendor-key-check.d.ts +23 -0
  76. package/dist/adapters/vendor-key-check.js +36 -0
  77. package/dist/adapters/vendor-key-check.js.map +1 -0
  78. package/dist/bin/aeolus-trierarch.js +7 -2
  79. package/dist/bin/aeolus-trierarch.js.map +1 -1
  80. package/dist/cli/add.d.ts +2 -2
  81. package/dist/cli/config-check.js +1 -1
  82. package/dist/cli/config-check.js.map +1 -1
  83. package/dist/cli/hold.js +13 -4
  84. package/dist/cli/hold.js.map +1 -1
  85. package/dist/cli/login.d.ts +72 -0
  86. package/dist/cli/login.js +114 -0
  87. package/dist/cli/login.js.map +1 -0
  88. package/dist/cli/main.js +85 -5
  89. package/dist/cli/main.js.map +1 -1
  90. package/dist/cli/proxy.d.ts +2 -0
  91. package/dist/cli/proxy.js +58 -0
  92. package/dist/cli/proxy.js.map +1 -0
  93. package/dist/cli/run.js +30 -4
  94. package/dist/cli/run.js.map +1 -1
  95. package/dist/cli/upgrade.d.ts +2 -2
  96. package/dist/cli/upgrade.js +2 -2
  97. package/dist/core/argo-reports.d.ts +10 -0
  98. package/dist/core/argo-reports.js +17 -0
  99. package/dist/core/argo-reports.js.map +1 -1
  100. package/dist/core/check-session-runtime.js +3 -1
  101. package/dist/core/check-session-runtime.js.map +1 -1
  102. package/dist/core/check-settings.d.ts +2 -0
  103. package/dist/core/check-settings.js +6 -1
  104. package/dist/core/check-settings.js.map +1 -1
  105. package/dist/core/entry.d.ts +12 -0
  106. package/dist/core/entry.js.map +1 -1
  107. package/dist/core/login.d.ts +28 -0
  108. package/dist/core/login.js +14 -0
  109. package/dist/core/login.js.map +1 -0
  110. package/dist/core/ports.d.ts +33 -1
  111. package/dist/core/reconciler.d.ts +5 -0
  112. package/dist/core/reconciler.js +12 -7
  113. package/dist/core/reconciler.js.map +1 -1
  114. package/dist/core/report-self.js +9 -3
  115. package/dist/core/report-self.js.map +1 -1
  116. package/dist/core/run-pass.d.ts +6 -1
  117. package/dist/core/run-pass.js +81 -13
  118. package/dist/core/run-pass.js.map +1 -1
  119. package/package.json +1 -2
  120. package/dist/adapters/claude-code-screen.d.ts +0 -1
  121. package/dist/adapters/claude-code-screen.js +0 -22
  122. package/dist/adapters/claude-code-screen.js.map +0 -1
  123. package/dist/adapters/held-command.d.ts +0 -13
  124. package/dist/adapters/held-command.js +0 -16
  125. package/dist/adapters/held-command.js.map +0 -1
  126. package/dist/adapters/launch-screen.d.ts +0 -14
  127. package/dist/adapters/launch-screen.js +0 -5
  128. package/dist/adapters/launch-screen.js.map +0 -1
  129. package/dist/adapters/stop-turn.d.ts +0 -13
  130. package/dist/adapters/stop-turn.js +0 -26
  131. package/dist/adapters/stop-turn.js.map +0 -1
  132. package/dist/adapters/tmux.d.ts +0 -13
  133. package/dist/adapters/tmux.js +0 -33
  134. package/dist/adapters/tmux.js.map +0 -1
@@ -0,0 +1,48 @@
1
+ import { PLUGIN_HARNESSES } from './plugin.js';
2
+ /**
3
+ * Whether a session can start on its login now (api keys K9): on an API key,
4
+ * only once its harness holds one, so a session never starts to be refused by
5
+ * the proxy, nor on its subscription instead (K2). On the subscription,
6
+ * only when nothing the harness reads itself would put a key in reach (K6).
7
+ */
8
+ export function createModelLogins(at) {
9
+ return {
10
+ startProblem: async ({ harness, login, options, folder }) => {
11
+ if (login === 'subscription') {
12
+ return subscriptionProblem(at, { harness, options, ...(folder !== undefined && { folder }) });
13
+ }
14
+ if (harness === 'copilot') {
15
+ return "copilot signs in with this computer's own login and runs on no API key: run the ship on its subscription";
16
+ }
17
+ const { state, at: since = '' } = await keyStateOf(at, harness);
18
+ switch (state) {
19
+ case 'ready':
20
+ return undefined;
21
+ case 'none':
22
+ return `${harness} has no API key on this computer: aeolus-trierarch login ${harness} --api-key`;
23
+ case 'refused':
24
+ return `${harness}'s API key was refused by its vendor since ${since}: give it a new one with aeolus-trierarch login ${harness} --api-key`;
25
+ case 'outOfCredit':
26
+ return `${harness}'s API key is out of credit since ${since}: it is checked every 15 minutes, or at once with aeolus-trierarch login ${harness} --check`;
27
+ }
28
+ },
29
+ keyState: (harness) => keyStateOf(at, harness),
30
+ };
31
+ }
32
+ /** The harness's key state; none for a harness this trierarch keeps no key for. */
33
+ function keyStateOf(at, harness) {
34
+ const known = PLUGIN_HARNESSES.find((name) => name === harness);
35
+ return known === undefined ? Promise.resolve({ state: 'none' }) : at.keyStates.stateOf(known);
36
+ }
37
+ /** Why a session of the harness would not run on its subscription alone; none when it would. */
38
+ async function subscriptionProblem(at, session) {
39
+ if (session.harness === 'claude-code') {
40
+ const found = await at.claudeCode.keyInReach({ options: session.options, ...(session.folder !== undefined && { folder: session.folder }) });
41
+ return found === undefined ? undefined : `claude-code would reach an API key on its subscription (${found}): remove it, or run the ship on its API key`;
42
+ }
43
+ if (session.harness === 'codex' && (await at.codex.loginKind()) === 'apiKey') {
44
+ return 'codex is logged in with an API key, not ChatGPT: log Codex in with ChatGPT (codex logout, then codex login), or run the ship on its API key';
45
+ }
46
+ return undefined;
47
+ }
48
+ //# sourceMappingURL=model-logins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-logins.js","sourceRoot":"","sources":["../../src/adapters/model-logins.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAsB,MAAM,aAAa,CAAC;AAEnE;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAMjC;IACC,OAAO;QACL,YAAY,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE;YAC1D,IAAI,KAAK,KAAK,cAAc,EAAE,CAAC;gBAC7B,OAAO,mBAAmB,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;YAChG,CAAC;YACD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC1B,OAAO,0GAA0G,CAAC;YACpH,CAAC;YACD,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,GAAG,EAAE,EAAE,GAAG,MAAM,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAChE,QAAQ,KAAK,EAAE,CAAC;gBACd,KAAK,OAAO;oBACV,OAAO,SAAS,CAAC;gBACnB,KAAK,MAAM;oBACT,OAAO,GAAG,OAAO,4DAA4D,OAAO,YAAY,CAAC;gBACnG,KAAK,SAAS;oBACZ,OAAO,GAAG,OAAO,8CAA8C,KAAK,mDAAmD,OAAO,YAAY,CAAC;gBAC7I,KAAK,aAAa;oBAChB,OAAO,GAAG,OAAO,qCAAqC,KAAK,4EAA4E,OAAO,UAAU,CAAC;YAC7J,CAAC;QACH,CAAC;QACD,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC;KAC/C,CAAC;AACJ,CAAC;AAED,mFAAmF;AACnF,SAAS,UAAU,CAAC,EAA6C,EAAE,OAAe;IAChF,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAyB,EAAE,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;IACvF,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAChG,CAAC;AAED,gGAAgG;AAChG,KAAK,UAAU,mBAAmB,CAAC,EAA2C,EAAE,OAAwF;IACtK,IAAI,OAAO,CAAC,OAAO,KAAK,aAAa,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QAC5I,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,2DAA2D,KAAK,8CAA8C,CAAC;IAC1J,CAAC;IACD,IAAI,OAAO,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC7E,OAAO,6IAA6I,CAAC;IACvJ,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { type IncomingMessage, type ServerResponse } from 'node:http';
2
+ import { type PluginHarness } from './plugin.js';
3
+ /**
4
+ * The model proxy (headless H16, api keys K7): the one process that reads a
5
+ * harness's API key. A session reaches its vendor through it with a token of
6
+ * its own; the proxy takes the token only from a running session of that
7
+ * harness, swaps it for the key, and forwards the request to that harness's
8
+ * vendor alone: `/anthropic/...` to Anthropic for Claude Code, `/openai/...`
9
+ * to OpenAI for Codex. Its refusals name neither a key nor a token. It reads
10
+ * every vendor answer to the key and records what it says of the key (api
11
+ * keys K9): a success as it streams, an error once whole, before it is sent
12
+ * on unchanged.
13
+ */
14
+ export interface ModelProxy {
15
+ readonly handle: (request: IncomingMessage, response: ServerResponse) => void;
16
+ /** Checks each key out of credit once (api keys K10), as the proxy does every 15 minutes. */
17
+ readonly checkOutOfCredit: () => Promise<void>;
18
+ }
19
+ /** The proxy's own path, which answers its version. */
20
+ export declare const STATE_PATH = "/aeolus/state";
21
+ /** The proxy's own path that checks a harness's key at once, `<path>/<harness>` (login --check, K10). */
22
+ export declare const CHECK_PATH = "/aeolus/check/";
23
+ /** How often a key out of credit is checked (K10). */
24
+ export declare const CHECK_INTERVAL_MS: number;
25
+ export declare function createModelProxy(at: {
26
+ sessions: string;
27
+ keys: string;
28
+ keyStates: string;
29
+ version: string;
30
+ vendors?: Partial<Record<PluginHarness, string>>;
31
+ now?: () => Date;
32
+ }): ModelProxy;
@@ -0,0 +1,171 @@
1
+ import { request as httpRequest } from 'node:http';
2
+ import { request as httpsRequest } from 'node:https';
3
+ import { z } from 'zod';
4
+ import { readKey } from './key-files.js';
5
+ import { createKeyStates } from './key-states.js';
6
+ import { PLUGIN_HARNESSES } from './plugin.js';
7
+ import { sessionOfToken } from './proxy-tokens.js';
8
+ import { keyStateOfAnswer } from './vendor-answers.js';
9
+ const VENDOR_URLS = { 'claude-code': 'https://api.anthropic.com', codex: 'https://api.openai.com' };
10
+ /** The path each harness's base URL ends in, which names its vendor. */
11
+ const PREFIXES = { anthropic: 'claude-code', openai: 'codex' };
12
+ /** The proxy's own path, which answers its version. */
13
+ export const STATE_PATH = '/aeolus/state';
14
+ /** The proxy's own path that checks a harness's key at once, `<path>/<harness>` (login --check, K10). */
15
+ export const CHECK_PATH = '/aeolus/check/';
16
+ /** How often a key out of credit is checked (K10). */
17
+ export const CHECK_INTERVAL_MS = 15 * 60 * 1000;
18
+ /** Each vendor's cheapest models, by a word in their ids, cheapest first: the check spends as little as the vendor bills. */
19
+ const CHEAPEST = { 'claude-code': ['haiku'], codex: ['nano', 'mini'] };
20
+ const ANTHROPIC_VERSION = '2023-06-01';
21
+ /** The fewest output tokens the Responses API takes. */
22
+ const OPENAI_FEWEST_OUTPUT_TOKENS = 16;
23
+ const modelListSchema = z.object({ data: z.array(z.object({ id: z.string() })) });
24
+ /** What the session sent that never goes on: its own credentials, and what belongs to its connection to the proxy. */
25
+ const DROPPED_HEADERS = new Set(['authorization', 'x-api-key', 'host', 'connection', 'keep-alive', 'proxy-authorization', 'proxy-connection', 'transfer-encoding', 'upgrade']);
26
+ const BEARER = /^Bearer (?<token>\S+)$/u;
27
+ const HTTP_UNAUTHORIZED = 401;
28
+ const HTTP_NOT_FOUND = 404;
29
+ const HTTP_BAD_GATEWAY = 502;
30
+ /** An answer from this status on is an error, read whole before it is sent on. */
31
+ const HTTP_ERRORS_FROM = 300;
32
+ /** How much of an error's body is read for what it says of the key: a vendor's error is a short JSON object. */
33
+ const ERROR_BODY_READ_BYTES = 64 * 1024;
34
+ function refuse(response, refusal) {
35
+ const { status, message } = refusal;
36
+ response.writeHead(status, { 'content-type': 'application/json' });
37
+ response.end(JSON.stringify({ type: 'error', error: { type: status === HTTP_UNAUTHORIZED ? 'authentication_error' : 'not_found_error', message: `aeolus model proxy: ${message}` } }));
38
+ }
39
+ export function createModelProxy(at) {
40
+ const keyStates = createKeyStates({ keys: at.keys, file: at.keyStates });
41
+ const now = at.now ?? (() => new Date());
42
+ /** Kept before the answer goes on, so the trierarch knows the key's state by the time the session does; a failed write is tried again on the next answer. */
43
+ const recordAnswer = async (harness, answer) => {
44
+ const state = keyStateOfAnswer({ harness, ...answer });
45
+ if (state !== undefined) {
46
+ await keyStates.record(harness, { state, at: now() }).catch(() => undefined);
47
+ }
48
+ };
49
+ const vendorOf = (harness) => at.vendors?.[harness] ?? VENDOR_URLS[harness];
50
+ const headersOf = (harness, key) => (harness === 'claude-code' ? { 'x-api-key': key, 'anthropic-version': ANTHROPIC_VERSION } : { authorization: `Bearer ${key}` });
51
+ /** One request the vendor bills, on its cheapest model it lists for the key, and what its answer says of the key recorded. */
52
+ const checkKey = async (harness) => {
53
+ const key = await readKey(at.keys, harness);
54
+ if (key === undefined) {
55
+ return;
56
+ }
57
+ const vendor = vendorOf(harness);
58
+ const listed = modelListSchema.safeParse(await (await fetch(`${vendor}/v1/models`, { headers: headersOf(harness, key) }).catch(() => undefined))?.json().catch(() => undefined));
59
+ const ids = listed.success ? listed.data.data.map((model) => model.id) : [];
60
+ const model = CHEAPEST[harness].flatMap((word) => ids.filter((id) => id.includes(word))).at(0);
61
+ if (model === undefined) {
62
+ return;
63
+ }
64
+ const [path, body] = harness === 'claude-code' ? ['/v1/messages', { model, max_tokens: 1, messages: [{ role: 'user', content: 'Hi' }] }] : ['/v1/responses', { model, input: 'Hi', max_output_tokens: OPENAI_FEWEST_OUTPUT_TOKENS }];
65
+ const answer = await fetch(`${vendor}${path}`, { method: 'POST', headers: { ...headersOf(harness, key), 'content-type': 'application/json' }, body: JSON.stringify(body) }).catch(() => undefined);
66
+ if (answer !== undefined) {
67
+ await recordAnswer(harness, { status: answer.status, body: await answer.text().catch(() => '') });
68
+ }
69
+ };
70
+ const routeOf = (path) => {
71
+ const [, prefix = '', ...rest] = path.split('/');
72
+ const harness = PREFIXES[prefix];
73
+ if (harness === undefined) {
74
+ return undefined;
75
+ }
76
+ const vendor = at.vendors?.[harness] ?? VENDOR_URLS[harness];
77
+ const keyHeaders = harness === 'claude-code' ? (key) => ({ 'x-api-key': key }) : (key) => ({ authorization: `Bearer ${key}` });
78
+ return { route: { harness, vendor, keyHeaders }, rest: `/${rest.join('/')}` };
79
+ };
80
+ const forward = async (request, response) => {
81
+ const path = request.url ?? '/';
82
+ const checked = PLUGIN_HARNESSES.find((harness) => path === `${CHECK_PATH}${harness}`);
83
+ if (checked !== undefined && request.method === 'POST') {
84
+ if ((await keyStates.stateOf(checked)).state === 'outOfCredit') {
85
+ await checkKey(checked);
86
+ }
87
+ response.writeHead(200, { 'content-type': 'application/json' });
88
+ response.end(JSON.stringify(await keyStates.stateOf(checked)));
89
+ return;
90
+ }
91
+ if (path === STATE_PATH) {
92
+ response.writeHead(200, { 'content-type': 'application/json' });
93
+ response.end(JSON.stringify({ version: at.version }));
94
+ return;
95
+ }
96
+ const routed = routeOf(path);
97
+ if (routed === undefined) {
98
+ refuse(response, { status: HTTP_NOT_FOUND, message: 'it forwards only to the harnesses\' vendors' });
99
+ return;
100
+ }
101
+ const { route, rest } = routed;
102
+ const token = BEARER.exec(request.headers.authorization ?? '')?.groups?.token ?? (typeof request.headers['x-api-key'] === 'string' ? request.headers['x-api-key'] : undefined);
103
+ const shipId = token === undefined ? undefined : await sessionOfToken(at.sessions, { harness: route.harness, token });
104
+ if (shipId === undefined) {
105
+ refuse(response, { status: HTTP_UNAUTHORIZED, message: 'not the token of a running session of this harness' });
106
+ return;
107
+ }
108
+ const key = await readKey(at.keys, route.harness);
109
+ if (key === undefined) {
110
+ refuse(response, { status: HTTP_UNAUTHORIZED, message: `this computer holds no API key for ${route.harness}` });
111
+ return;
112
+ }
113
+ // The vendor's origin is fixed, and the path only ever set on it: a path is never resolved as a URL, which could name another host.
114
+ const vendorOrigin = new URL(route.vendor).origin;
115
+ const target = new URL(vendorOrigin);
116
+ const queryAt = rest.indexOf('?');
117
+ target.pathname = queryAt === -1 ? rest : rest.slice(0, queryAt);
118
+ target.search = queryAt === -1 ? '' : rest.slice(queryAt);
119
+ if (target.origin !== vendorOrigin) {
120
+ refuse(response, { status: HTTP_NOT_FOUND, message: 'it forwards only to the harnesses\' vendors' });
121
+ return;
122
+ }
123
+ const headers = { ...Object.fromEntries(Object.entries(request.headers).filter(([name]) => !DROPPED_HEADERS.has(name))), ...route.keyHeaders(key) };
124
+ const send = target.protocol === 'https:' ? httpsRequest : httpRequest;
125
+ const outgoing = send(target, { method: request.method, headers }, (answer) => {
126
+ const status = answer.statusCode ?? HTTP_BAD_GATEWAY;
127
+ const answerHeaders = Object.fromEntries(Object.entries(answer.headers).filter(([name]) => name !== 'connection' && name !== 'transfer-encoding'));
128
+ if (status < HTTP_ERRORS_FROM) {
129
+ answer.pause();
130
+ void recordAnswer(route.harness, { status, body: '' }).then(() => {
131
+ response.writeHead(status, answerHeaders);
132
+ answer.pipe(response);
133
+ });
134
+ return;
135
+ }
136
+ const chunks = [];
137
+ answer.on('data', (chunk) => chunks.push(chunk));
138
+ answer.on('end', () => {
139
+ const body = Buffer.concat(chunks);
140
+ void recordAnswer(route.harness, { status, body: body.subarray(0, ERROR_BODY_READ_BYTES).toString('utf8') }).then(() => {
141
+ response.writeHead(status, answerHeaders);
142
+ response.end(body);
143
+ });
144
+ });
145
+ });
146
+ outgoing.on('error', () => {
147
+ if (!response.headersSent) {
148
+ refuse(response, { status: HTTP_BAD_GATEWAY, message: `${target.host} could not be reached` });
149
+ }
150
+ else {
151
+ response.destroy();
152
+ }
153
+ });
154
+ request.pipe(outgoing);
155
+ };
156
+ return {
157
+ handle: (request, response) => {
158
+ forward(request, response).catch(() => {
159
+ response.destroy();
160
+ });
161
+ },
162
+ checkOutOfCredit: async () => {
163
+ for (const harness of PLUGIN_HARNESSES) {
164
+ if ((await keyStates.stateOf(harness)).state === 'outOfCredit') {
165
+ await checkKey(harness);
166
+ }
167
+ }
168
+ },
169
+ };
170
+ }
171
+ //# sourceMappingURL=model-proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-proxy.js","sourceRoot":"","sources":["../../src/adapters/model-proxy.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,10 @@ export interface TrierarchPaths {
12
12
  readonly crewToken: string;
13
13
  /** The machine's long-lived model token, handed to each container session (decision 0039); never in the configuration. */
14
14
  readonly modelToken: string;
15
+ /** Each harness's API key, one file per harness (api keys K5); only login writes it, never the configuration. */
16
+ readonly keys: string;
17
+ /** The model proxy's files, its pid and its port (headless H16). */
18
+ readonly proxy: string;
15
19
  readonly state: string;
16
20
  /** What detection found per harness (#365), apart from the configuration. */
17
21
  readonly detected: string;
@@ -7,6 +7,8 @@ export function trierarchPaths(at) {
7
7
  configSchema: join(home, 'config.schema.json'),
8
8
  crewToken: join(home, 'crew-token'),
9
9
  modelToken: join(home, 'model-token'),
10
+ keys: join(home, 'keys'),
11
+ proxy: join(home, 'proxy'),
10
12
  state: join(home, 'state.json'),
11
13
  detected: join(home, 'detected.json'),
12
14
  running: join(home, 'running.json'),
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/adapters/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAqCjC,MAAM,UAAU,cAAc,CAAC,EAA8C;IAC3E,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,aAAa,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IAC5D,OAAO;QACL,IAAI;QACJ,MAAM,EAAE,EAAE,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC;QAC9C,YAAY,EAAE,IAAI,CAAC,IAAI,EAAE,oBAAoB,CAAC;QAC9C,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC;QACnC,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC;QACrC,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC;QAC/B,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC;QACrC,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC;QACnC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;QACxB,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC;QAClC,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC;QAC1B,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC;QAChC,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC;QAC9B,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC;QAClC,mBAAmB,EAAE,IAAI,CAAC,IAAI,EAAE,2BAA2B,CAAC;QAC5D,YAAY,EAAE,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC;KACzC,CAAC;AACJ,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,QAAQ,CAAC,KAAa,EAAE,MAAc;IACpD,OAAO,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;AAC7B,CAAC"}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/adapters/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAyCjC,MAAM,UAAU,cAAc,CAAC,EAA8C;IAC3E,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,aAAa,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IAC5D,OAAO;QACL,IAAI;QACJ,MAAM,EAAE,EAAE,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC;QAC9C,YAAY,EAAE,IAAI,CAAC,IAAI,EAAE,oBAAoB,CAAC;QAC9C,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC;QACnC,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC;QACrC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;QACxB,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC;QAC1B,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC;QAC/B,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC;QACrC,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC;QACnC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;QACxB,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC;QAClC,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC;QAC1B,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC;QAChC,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC;QAC9B,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC;QAClC,mBAAmB,EAAE,IAAI,CAAC,IAAI,EAAE,2BAA2B,CAAC;QAC5D,YAAY,EAAE,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC;KACzC,CAAC;AACJ,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,QAAQ,CAAC,KAAa,EAAE,MAAc;IACpD,OAAO,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;AAC7B,CAAC"}
@@ -2,23 +2,26 @@ import type { AeolusPlugin } from './plugin-identity.js';
2
2
  /** The harnesses that install the aeolus-fleet plugin, each in its own plugin folders. */
3
3
  export type PluginHarness = 'claude-code' | 'codex';
4
4
  export declare const PLUGIN_HARNESSES: readonly PluginHarness[];
5
+ /** Every harness the aeolus-fleet plugin crews a ship from: Claude Code and Codex, and Copilot, whose plugin the trierarch neither upgrades nor gives an API key. */
6
+ export type CrewHarness = PluginHarness | 'copilot';
5
7
  /** The aeolus-fleet plugin's data folder in a harness's plugin folders, as both harnesses name it. */
6
8
  export declare const PLUGIN_DATA_FOLDER = "aeolus-fleet-aeolus-fleet";
7
9
  /**
8
- * Where a harness installed the aeolus-fleet plugin: the newest version in its
9
- * plugin cache, looked up again at each use so a plugin upgrade without a
10
- * service restart moves along (#828), and the plugin's data folder, unless
11
- * variables name others
10
+ * Where a harness installed the aeolus-fleet plugin: for Claude Code and
11
+ * Codex the newest version in its plugin cache, looked up again at each use
12
+ * so a plugin upgrade without a service restart moves along (#828), and the
13
+ * plugin's data folder, unless variables name others
12
14
  * (AEOLUS_PLUGIN_ROOT and AEOLUS_PLUGIN_DATA for Claude Code,
13
15
  * AEOLUS_CODEX_PLUGIN_ROOT and AEOLUS_CODEX_PLUGIN_DATA for Codex). The
14
- * folders follow CLAUDE_CONFIG_DIR and CODEX_HOME as the harnesses do. The
15
- * identities of the harness's sessions live in ~/.aeolus/crews/<harness>, as
16
- * the plugin keeps them (decision 0015).
16
+ * folders follow CLAUDE_CONFIG_DIR and CODEX_HOME as the harnesses do. For
17
+ * Copilot, as findCopilotPlugin says. The identities of the harness's
18
+ * sessions live in ~/.aeolus/crews/<harness>, as the plugin keeps them
19
+ * (decision 0015).
17
20
  */
18
21
  export declare function findAeolusPlugin(at: {
19
22
  homeDirectory: string;
20
23
  env: Readonly<Record<string, string | undefined>>;
21
- harness?: PluginHarness;
24
+ harness?: CrewHarness;
22
25
  }): Promise<AeolusPlugin>;
23
26
  /**
24
27
  * The version of the aeolus-fleet plugin a harness uses, as the manifest that
@@ -1,10 +1,12 @@
1
- import { readdir, readFile } from 'node:fs/promises';
1
+ import { readdir, readFile, stat } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
3
  import { z } from 'zod';
4
4
  export const PLUGIN_HARNESSES = ['claude-code', 'codex'];
5
+ /** The manifest each harness reads the plugin's version from. */
6
+ const MANIFESTS = { 'claude-code': '.claude-plugin', codex: '.codex-plugin', copilot: join('.github', 'plugin') };
5
7
  /** The aeolus-fleet plugin's data folder in a harness's plugin folders, as both harnesses name it. */
6
8
  export const PLUGIN_DATA_FOLDER = 'aeolus-fleet-aeolus-fleet';
7
- /** Where each harness keeps its plugins, and the variables that point elsewhere. */
9
+ /** Where Claude Code and Codex keep their plugins, and the variables that point elsewhere. */
8
10
  function placesOf(at) {
9
11
  const { homeDirectory, env } = at;
10
12
  if (at.harness === 'codex') {
@@ -13,21 +15,52 @@ function placesOf(at) {
13
15
  return { name: 'Claude Code', plugins: join(env.CLAUDE_CONFIG_DIR ?? join(homeDirectory, '.claude'), 'plugins'), root: env.AEOLUS_PLUGIN_ROOT, data: env.AEOLUS_PLUGIN_DATA, rootVariable: 'AEOLUS_PLUGIN_ROOT' };
14
16
  }
15
17
  /**
16
- * Where a harness installed the aeolus-fleet plugin: the newest version in its
17
- * plugin cache, looked up again at each use so a plugin upgrade without a
18
- * service restart moves along (#828), and the plugin's data folder, unless
19
- * variables name others
18
+ * Where Copilot installed the aeolus-fleet plugin: one folder per plugin in its
19
+ * installed-plugins folder, with no version in the path, and the data folder
20
+ * Copilot gives its hooks (`COPILOT_PLUGIN_DATA`, as Copilot CLI 1.0.105 sets
21
+ * it), both in COPILOT_HOME when it is set, unless AEOLUS_COPILOT_PLUGIN_ROOT
22
+ * and AEOLUS_COPILOT_PLUGIN_DATA name others, as for a plugin Copilot loads
23
+ * live from a local marketplace. Unlike Claude Code's and Codex's, a missing
24
+ * one does not stop the trierarch at start: the machine does not offer
25
+ * Copilot until it is installed.
26
+ */
27
+ function findCopilotPlugin(at) {
28
+ const { env } = at;
29
+ const copilotHome = env.COPILOT_HOME ?? join(at.homeDirectory, '.copilot');
30
+ const data = env.AEOLUS_COPILOT_PLUGIN_DATA ?? join(copilotHome, 'plugin-data', 'aeolus-fleet', 'aeolus-fleet');
31
+ const root = env.AEOLUS_COPILOT_PLUGIN_ROOT ?? join(copilotHome, 'installed-plugins', 'aeolus-fleet', 'aeolus-fleet');
32
+ if (env.AEOLUS_COPILOT_PLUGIN_ROOT !== undefined) {
33
+ return Promise.resolve({ root: () => Promise.resolve(root), data, crews: at.crews });
34
+ }
35
+ // Looked for at each use, never at start: the trierarch starts without it, names Copilot as not offered, and finds it once installed (#1212).
36
+ const installed = async () => {
37
+ if ((await stat(root).catch(() => undefined)) === undefined) {
38
+ throw new Error(`The aeolus-fleet plugin is not installed for Copilot (nothing in ${root}): install it, or set AEOLUS_COPILOT_PLUGIN_ROOT`);
39
+ }
40
+ return root;
41
+ };
42
+ return Promise.resolve({ root: installed, data, crews: at.crews });
43
+ }
44
+ /**
45
+ * Where a harness installed the aeolus-fleet plugin: for Claude Code and
46
+ * Codex the newest version in its plugin cache, looked up again at each use
47
+ * so a plugin upgrade without a service restart moves along (#828), and the
48
+ * plugin's data folder, unless variables name others
20
49
  * (AEOLUS_PLUGIN_ROOT and AEOLUS_PLUGIN_DATA for Claude Code,
21
50
  * AEOLUS_CODEX_PLUGIN_ROOT and AEOLUS_CODEX_PLUGIN_DATA for Codex). The
22
- * folders follow CLAUDE_CONFIG_DIR and CODEX_HOME as the harnesses do. The
23
- * identities of the harness's sessions live in ~/.aeolus/crews/<harness>, as
24
- * the plugin keeps them (decision 0015).
51
+ * folders follow CLAUDE_CONFIG_DIR and CODEX_HOME as the harnesses do. For
52
+ * Copilot, as findCopilotPlugin says. The identities of the harness's
53
+ * sessions live in ~/.aeolus/crews/<harness>, as the plugin keeps them
54
+ * (decision 0015).
25
55
  */
26
56
  export async function findAeolusPlugin(at) {
27
57
  const harness = at.harness ?? 'claude-code';
58
+ const crews = join(at.homeDirectory, '.aeolus', 'crews', harness);
59
+ if (harness === 'copilot') {
60
+ return findCopilotPlugin({ ...at, crews });
61
+ }
28
62
  const places = placesOf({ ...at, harness });
29
63
  const data = places.data ?? join(places.plugins, 'data', PLUGIN_DATA_FOLDER);
30
- const crews = join(at.homeDirectory, '.aeolus', 'crews', harness);
31
64
  const { root } = places;
32
65
  if (root !== undefined) {
33
66
  return { root: () => Promise.resolve(root), data, crews };
@@ -58,16 +91,17 @@ const manifestSchema = z.object({ version: z.string() });
58
91
  * its manifest says no version.
59
92
  */
60
93
  export async function aeolusPluginVersion(at) {
61
- if (at.harness !== 'claude-code' && at.harness !== 'codex') {
94
+ const harness = [...PLUGIN_HARNESSES, 'copilot'].find((name) => name === at.harness);
95
+ if (harness === undefined) {
62
96
  return undefined;
63
97
  }
64
- const root = await findAeolusPlugin({ ...at, harness: at.harness })
98
+ const root = await findAeolusPlugin({ ...at, harness })
65
99
  .then((plugin) => plugin.root())
66
100
  .catch(() => undefined);
67
101
  if (root === undefined) {
68
102
  return undefined;
69
103
  }
70
- const manifest = join(root, at.harness === 'codex' ? '.codex-plugin' : '.claude-plugin', 'plugin.json');
104
+ const manifest = join(root, MANIFESTS[harness], 'plugin.json');
71
105
  const text = await readFile(manifest, 'utf8').catch(() => undefined);
72
106
  if (text === undefined) {
73
107
  return undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/adapters/plugin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/adapters/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Keeps the model proxy running while a harness needs it (headless H16): one
3
+ * per machine, started like a hold, nobody's child and under a systemd unit
4
+ * in a scope of its own, so a restart of the service ends no session's way to
5
+ * its vendor. A proxy that is gone is started again on its port; one another
6
+ * version started is replaced; one no harness needs is stopped.
7
+ */
8
+ export interface ProxyRuntime {
9
+ keep(at: {
10
+ isNeeded: boolean;
11
+ }): Promise<void>;
12
+ /** Where sessions reach the proxy; none before it first listened. */
13
+ url(): Promise<string | undefined>;
14
+ }
15
+ export interface ProxyFiles {
16
+ readonly pid: string;
17
+ readonly port: string;
18
+ }
19
+ /** Where the proxy records each harness's key state (api keys K8), which the trierarch reads. */
20
+ export declare function keyStatesFileOf(folder: string): string;
21
+ export declare function proxyFilesOf(folder: string): ProxyFiles;
22
+ export declare function createProxyRuntime(options: {
23
+ folder: string;
24
+ sessions: string;
25
+ keys: string;
26
+ /** The trierarch program, which `proxy` and its words follow. */
27
+ program: readonly string[];
28
+ version: string;
29
+ /** What the proxy's start goes through: a systemd scope of its own under a systemd unit (see sessionsLaunch). */
30
+ launch?: readonly string[];
31
+ }): ProxyRuntime;
@@ -0,0 +1,100 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { readFile, rm } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { setTimeout as wait } from 'node:timers/promises';
5
+ import { z } from 'zod';
6
+ import { STATE_PATH } from './model-proxy.js';
7
+ /** Where the proxy records each harness's key state (api keys K8), which the trierarch reads. */
8
+ export function keyStatesFileOf(folder) {
9
+ return join(folder, 'key-states.json');
10
+ }
11
+ export function proxyFilesOf(folder) {
12
+ return { pid: join(folder, 'proxy.pid'), port: join(folder, 'port') };
13
+ }
14
+ const STATE_TIMEOUT_MS = 2000;
15
+ const START_WAIT_MS = 10_000;
16
+ const POLL_MS = 50;
17
+ const STOP_WAIT_MS = 5000;
18
+ /** Runs the command in the background and returns at once, as a hold's start does. */
19
+ const DETACHED = '"$@" < /dev/null > /dev/null 2>&1 &';
20
+ const stateSchema = z.object({ version: z.string() });
21
+ export function createProxyRuntime(options) {
22
+ const files = proxyFilesOf(options.folder);
23
+ const url = async () => {
24
+ const port = Number(await readFile(files.port, 'utf8').catch(() => ''));
25
+ return Number.isInteger(port) && port > 0 ? `http://127.0.0.1:${String(port)}` : undefined;
26
+ };
27
+ /** The version the proxy at its address answers; none when nothing answers. */
28
+ const answeredVersion = async () => {
29
+ const at = await url();
30
+ if (at === undefined) {
31
+ return undefined;
32
+ }
33
+ const answer = await fetch(`${at}${STATE_PATH}`, { signal: AbortSignal.timeout(STATE_TIMEOUT_MS) }).catch(() => undefined);
34
+ const state = stateSchema.safeParse(answer?.ok === true ? await answer.json().catch(() => undefined) : undefined);
35
+ return state.success ? state.data.version : undefined;
36
+ };
37
+ const runningPid = async () => {
38
+ const pid = Number(await readFile(files.pid, 'utf8').catch(() => ''));
39
+ if (!Number.isInteger(pid) || pid <= 1) {
40
+ return undefined;
41
+ }
42
+ try {
43
+ process.kill(pid, 0);
44
+ return pid;
45
+ }
46
+ catch {
47
+ return undefined;
48
+ }
49
+ };
50
+ const stop = async () => {
51
+ const pid = await runningPid();
52
+ if (pid !== undefined) {
53
+ process.kill(pid, 'SIGTERM');
54
+ const until = Date.now() + STOP_WAIT_MS;
55
+ while ((await runningPid()) !== undefined && Date.now() < until) {
56
+ await wait(POLL_MS);
57
+ }
58
+ if ((await runningPid()) !== undefined) {
59
+ process.kill(pid, 'SIGKILL');
60
+ }
61
+ }
62
+ await rm(files.pid, { force: true });
63
+ };
64
+ const start = async () => {
65
+ const proxy = [...options.program, 'proxy', '--folder', options.folder, '--sessions', options.sessions, '--keys', options.keys];
66
+ const [program = 'sh', ...args] = [...(options.launch ?? []), 'sh', '-c', DETACHED, 'sh', ...proxy];
67
+ const starter = spawn(program, args, { stdio: 'ignore', detached: true });
68
+ await new Promise((resolve, reject) => {
69
+ starter.on('error', reject);
70
+ starter.on('exit', () => {
71
+ resolve();
72
+ });
73
+ });
74
+ const until = Date.now() + START_WAIT_MS;
75
+ while (Date.now() < until) {
76
+ if ((await runningPid()) !== undefined && (await answeredVersion()) !== undefined) {
77
+ return;
78
+ }
79
+ await wait(POLL_MS);
80
+ }
81
+ throw new Error(`the model proxy did not answer within ${String(START_WAIT_MS)} ms of its start`);
82
+ };
83
+ return {
84
+ keep: async ({ isNeeded }) => {
85
+ if (!isNeeded) {
86
+ await stop();
87
+ return;
88
+ }
89
+ const version = await answeredVersion();
90
+ if (version === options.version) {
91
+ return;
92
+ }
93
+ // Its pid file goes before the start, so the wait sees the new proxy's.
94
+ await stop();
95
+ await start();
96
+ },
97
+ url,
98
+ };
99
+ }
100
+ //# sourceMappingURL=proxy-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-runtime.js","sourceRoot":"","sources":["../../src/adapters/proxy-runtime.ts"],"names":[],"mappings":"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"}