unity-mcp-cli 0.86.3 → 0.88.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.
@@ -558,11 +558,20 @@ export interface RunToolOptions {
558
558
  fetchImpl?: typeof fetch;
559
559
  /**
560
560
  * Optional injection point for the Cloud-mode Bearer credential read from the shared machine
561
- * credential store (`~/.ai-game-dev/credentials.json`). Only consulted when the resolved project
562
- * config is in Cloud mode and neither `url` nor `token` was supplied. Defaults to reading the real
563
- * per-machine store; tests inject a deterministic value.
561
+ * credential store. Only consulted when the resolved project config is in Cloud mode and neither
562
+ * `url` nor `token` was supplied. Defaults to cli-core's `MachineCredentialProvider` (proactive
563
+ * refresh under the cross-process lock — never a raw on-disk read); tests inject a deterministic
564
+ * value. Sync or async both work.
564
565
  */
565
- readCloudToken?: () => string | undefined;
566
+ readCloudToken?: () => Promise<string | undefined> | string | undefined;
567
+ /**
568
+ * Optional injection point for the REACTIVE Cloud-mode refresh: invoked at most once per call
569
+ * when the server answers 401 to a machine-store Bearer (revocation / clock skew). Returns the
570
+ * rotated access token, or `undefined` when the credential family is dead (the call then fails
571
+ * with the original 401). Defaults to cli-core's `MachineCredentialProvider.refresh`. Never
572
+ * consulted for an explicit `token` / `url` override.
573
+ */
574
+ refreshCloudToken?: () => Promise<string | undefined> | string | undefined;
566
575
  }
567
576
  /** Successful `runTool` / `runSystemTool` outcome. Narrow with `kind === 'success'`. */
568
577
  export interface RunToolSuccess {
@@ -0,0 +1,43 @@
1
+ import { MachineCredentialProvider, MachineCredentialStore } from '@baizor/gamedev-cli-core';
2
+ /**
3
+ * The CLI's single seam onto cli-core's `MachineCredentialProvider` (unified-machine-auth 02/04,
4
+ * task d2 / W2). Every Cloud-mode Bearer the CLI presents comes through here — the provider owns
5
+ * proactive refresh (inside the 60 s expiry skew), reactive refresh (driven by a hub 401), the
6
+ * cross-process credential lock, and the family-aware machine-store view. The CLI never reads
7
+ * `accessToken` raw off disk: a raw read returns a token that may be seconds from expiry (or past
8
+ * it) with nobody refreshing, which is exactly the defect this module replaces
9
+ * (the pre-d2 `readMachineStoreCloudToken`).
10
+ */
11
+ /** Injectable construction options — tests point the provider at a temp store + a fake AS. */
12
+ export interface CloudCredentialProviderOptions {
13
+ /** The credential store to serve from; defaults to the shared per-machine store. */
14
+ store?: MachineCredentialStore;
15
+ /** Authorization-server base for the refresh endpoint; defaults to the hosted cloud. */
16
+ serverBaseUrl?: string;
17
+ /** Injectable `fetch` for the refresher (tests). */
18
+ fetchImpl?: typeof fetch;
19
+ }
20
+ /**
21
+ * Build a `MachineCredentialProvider` wired the way this CLI consumes it:
22
+ * `HttpTokenRefresher` against the AS root, and `unity-mcp-cli` as the component-default client
23
+ * id — used ONLY for `families.legacy` (a stored family's own `clientId` always wins, 04 §3).
24
+ */
25
+ export declare function createCloudCredentialProvider(options?: CloudCredentialProviderOptions): MachineCredentialProvider;
26
+ /** TEST-ONLY: drop the cached default provider (e.g. after re-pointing HOME). */
27
+ export declare function resetCloudCredentialProviderForTests(): void;
28
+ /**
29
+ * Read a valid plugin-plane access token for a Cloud-mode call, PROACTIVELY refreshing under the
30
+ * cross-process lock when the stored token is within the expiry skew. Returns `undefined` when the
31
+ * machine is effectively not signed in — no credential, a dead family, an unreadable store, or a
32
+ * lock that stayed contended — so callers surface their actionable "not logged in" error instead
33
+ * of issuing a silent unauthenticated request (defect E / D11). The precise reason is logged via
34
+ * `verbose()` (never token bytes).
35
+ */
36
+ export declare function readCloudAccessToken(options?: CloudCredentialProviderOptions): Promise<string | undefined>;
37
+ /**
38
+ * REACTIVELY refresh the plugin-plane family now — the hub answered 401 while the local expiry
39
+ * still looked fine (revocation, clock skew). Runs the same locked critical section as the
40
+ * proactive path. Returns the fresh access token, or `undefined` when the family is dead /
41
+ * signed out (the caller falls back to its "not logged in" error).
42
+ */
43
+ export declare function refreshCloudAccessToken(options?: CloudCredentialProviderOptions): Promise<string | undefined>;
@@ -0,0 +1,84 @@
1
+ // Copyright (c) 2024 Ivan Murzak. All rights reserved.
2
+ // Licensed under the Apache License, Version 2.0.
3
+ import { MachineCredentialProvider, MachineCredentialStore, MachineCredentialStoreUnreadableError, CredentialLockBusyError, HttpTokenRefresher, LoginRequiredError, unityAdapter, } from '@baizor/gamedev-cli-core';
4
+ import { verbose } from './ui.js';
5
+ import { CLOUD_SERVER_BASE_URL } from './config.js';
6
+ /**
7
+ * Build a `MachineCredentialProvider` wired the way this CLI consumes it:
8
+ * `HttpTokenRefresher` against the AS root, and `unity-mcp-cli` as the component-default client
9
+ * id — used ONLY for `families.legacy` (a stored family's own `clientId` always wins, 04 §3).
10
+ */
11
+ export function createCloudCredentialProvider(options = {}) {
12
+ const store = options.store ?? new MachineCredentialStore();
13
+ const refresher = new HttpTokenRefresher({
14
+ defaultServerBaseUrl: options.serverBaseUrl ?? CLOUD_SERVER_BASE_URL,
15
+ ...(options.fetchImpl ? { fetchImpl: options.fetchImpl } : {}),
16
+ });
17
+ return new MachineCredentialProvider(store, refresher, {
18
+ defaultClientId: unityAdapter.clientId, // unity-mcp-cli
19
+ onWarning: (message) => verbose(`[credential-provider] ${message}`),
20
+ onTelemetry: (event) => verbose(`[credential-provider] ${event.type}: ${event.family} (${event.reason})`),
21
+ });
22
+ }
23
+ /** Lazy singleton for the default (real per-machine) store — one provider per CLI process. */
24
+ let defaultProvider;
25
+ function resolveProvider(options) {
26
+ if (options?.store || options?.serverBaseUrl || options?.fetchImpl) {
27
+ return createCloudCredentialProvider(options);
28
+ }
29
+ defaultProvider ?? (defaultProvider = createCloudCredentialProvider());
30
+ return defaultProvider;
31
+ }
32
+ /** TEST-ONLY: drop the cached default provider (e.g. after re-pointing HOME). */
33
+ export function resetCloudCredentialProviderForTests() {
34
+ defaultProvider = undefined;
35
+ }
36
+ /**
37
+ * Read a valid plugin-plane access token for a Cloud-mode call, PROACTIVELY refreshing under the
38
+ * cross-process lock when the stored token is within the expiry skew. Returns `undefined` when the
39
+ * machine is effectively not signed in — no credential, a dead family, an unreadable store, or a
40
+ * lock that stayed contended — so callers surface their actionable "not logged in" error instead
41
+ * of issuing a silent unauthenticated request (defect E / D11). The precise reason is logged via
42
+ * `verbose()` (never token bytes).
43
+ */
44
+ export async function readCloudAccessToken(options) {
45
+ const provider = resolveProvider(options);
46
+ try {
47
+ return await provider.getAccessToken({ family: 'plugin' });
48
+ }
49
+ catch (err) {
50
+ return degradeToSignedOut(err, 'read');
51
+ }
52
+ }
53
+ /**
54
+ * REACTIVELY refresh the plugin-plane family now — the hub answered 401 while the local expiry
55
+ * still looked fine (revocation, clock skew). Runs the same locked critical section as the
56
+ * proactive path. Returns the fresh access token, or `undefined` when the family is dead /
57
+ * signed out (the caller falls back to its "not logged in" error).
58
+ */
59
+ export async function refreshCloudAccessToken(options) {
60
+ const provider = resolveProvider(options);
61
+ try {
62
+ const document = await provider.refresh({ family: 'plugin' });
63
+ return document.accessToken ?? document.families?.plugin?.accessToken ?? undefined;
64
+ }
65
+ catch (err) {
66
+ return degradeToSignedOut(err, 'refresh');
67
+ }
68
+ }
69
+ function degradeToSignedOut(err, operation) {
70
+ if (err instanceof LoginRequiredError) {
71
+ verbose(`Cloud credential ${operation}: login required (${err.message})`);
72
+ return undefined;
73
+ }
74
+ if (err instanceof MachineCredentialStoreUnreadableError) {
75
+ verbose(`Cloud credential ${operation}: store unreadable — sign in again to replace it (${err.message})`);
76
+ return undefined;
77
+ }
78
+ if (err instanceof CredentialLockBusyError) {
79
+ verbose(`Cloud credential ${operation}: credential store busy — retry shortly (${err.message})`);
80
+ return undefined;
81
+ }
82
+ throw err;
83
+ }
84
+ //# sourceMappingURL=cloud-credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-credentials.js","sourceRoot":"","sources":["../../src/utils/cloud-credentials.ts"],"names":[],"mappings":"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"}
@@ -1,23 +1,39 @@
1
1
  import { MachineCredentialStore } from './machine-credentials.js';
2
- import { type DeviceLoginResult, type DeviceLoginOptions } from '@baizor/gamedev-cli-core';
3
- /**
4
- * The device-flow login now runs on `@baizor/gamedev-cli-core`'s OAuth 2.1 Device Authorization
5
- * Grant (RFC 8628) — client_id `unity-mcp-cli`, scope `mcp:plugin` — which mints an ES256 hub JWT
6
- * plus a rotating refresh token and NEVER mints a PAT (auth-fixes T1, closing B2/B3). The FULL
7
- * credential set (accessToken, refreshToken, expiresAt, serverTarget, subject) is persisted to the
8
- * shared machine credential store — the legacy flow dropped refresh/expiry/subject on the floor.
9
- */
10
- /** Injection seam so the login flow can be exercised offline in tests without the network. */
11
- export interface RunCloudLoginDeps {
2
+ import { type DeviceLoginResult, type DeviceLoginOptions, type RevokeTokenFn, type TokenExchangeClient } from '@baizor/gamedev-cli-core';
3
+ /** Injection seams so the login flow can be exercised offline in tests without the network. */
4
+ export interface RunCloudLoginOptions {
5
+ /** O10/F10: mint `scope=mcp:plugin` and commit a plugin-only store (no agent family). */
6
+ toolsOnly?: boolean;
7
+ /** F7: auto-confirm the account-switch prompt (the `--yes` flag). */
8
+ assumeYes?: boolean;
12
9
  /** Authorization-server base; defaults to the hosted `CLOUD_SERVER_BASE_URL`. */
13
10
  serverBaseUrl?: string;
14
11
  /** The device-login implementation; defaults to cli-core's `deviceLogin`. */
15
12
  login?: (options: DeviceLoginOptions) => Promise<DeviceLoginResult>;
13
+ /** The RFC 8693 exchange client; defaults to cli-core's `HttpTokenExchangeClient`. */
14
+ exchangeClient?: TokenExchangeClient;
15
+ /** The D6/F7 confirmation; defaults to an interactive prompt (auto-confirmed by `assumeYes`). */
16
+ confirmAccountSwitch?: (info: {
17
+ storedSubject: string;
18
+ newSubject: string;
19
+ }) => boolean | Promise<boolean>;
20
+ /** Injectable best-effort RFC 7009 revoker (tests). */
21
+ revokeToken?: RevokeTokenFn;
22
+ /** Injectable backoff sleep (tests make it a no-op). */
23
+ sleep?: (ms: number) => Promise<void>;
16
24
  }
25
+ /**
26
+ * Finish a previously interrupted agent login (F1 `partial`: agent family committed, plugin
27
+ * derivation missing) using a FRESH agent access token supplied by the caller. Returns true when
28
+ * the plugin family is committed.
29
+ */
30
+ export declare function completePluginDerivation(store: MachineCredentialStore, agentAccessToken: string, options?: Pick<RunCloudLoginOptions, 'serverBaseUrl' | 'exchangeClient' | 'revokeToken' | 'sleep'>): Promise<boolean>;
17
31
  /**
18
32
  * Run the cloud device-auth flow: initiate, display the user code + verification URL, open the
19
- * browser, poll, and persist the FULL credential to the shared machine credential store.
33
+ * browser, poll, then commit through cli-core's login-commit machinery (two-lock-hold agent
34
+ * commit + exchange-derived plugin family, or the tools-only plugin commit — never a raw
35
+ * `store.write`).
20
36
  *
21
- * Returns the access token on success, or null on failure (errors are printed).
37
+ * Returns the plugin-plane access token on success, or null on failure (errors are printed).
22
38
  */
23
- export declare function runCloudLogin(store: MachineCredentialStore, deps?: RunCloudLoginDeps): Promise<string | null>;
39
+ export declare function runCloudLogin(store: MachineCredentialStore, options?: RunCloudLoginOptions): Promise<string | null>;
@@ -1,24 +1,151 @@
1
1
  // Copyright (c) 2024 Ivan Murzak. All rights reserved.
2
2
  // Licensed under the Apache License, Version 2.0.
3
+ import * as readline from 'readline/promises';
3
4
  import * as ui from './ui.js';
4
5
  import { CLOUD_SERVER_BASE_URL } from './config.js';
5
6
  import { openBrowser } from './browser.js';
6
- import { deviceLogin, unityAdapter, DEFAULT_PLUGIN_SCOPE, } from '@baizor/gamedev-cli-core';
7
+ import { deviceLogin, unityAdapter, commitAgentLogin, commitToolsOnlyLogin, derivePluginFamily, HttpTokenExchangeClient, DEFAULT_PLUGIN_SCOPE, MCP_AGENT_SCOPE, } from '@baizor/gamedev-cli-core';
8
+ /**
9
+ * The cloud sign-in flow (unified-machine-auth 03 F1/F7/F10, task d2). The device grant
10
+ * (RFC 8628, client_id `unity-mcp-cli`) now mints at **agent scope** (`mcp:agent`) by default and
11
+ * the commit goes through cli-core's login-commit machinery — the two-lock-hold sequence: agent
12
+ * family under the first hold, RFC 8693 token exchange with the lock released, derived plugin
13
+ * family (+ v1 mirror) under the second hold. A failed exchange leaves a valid committed agent
14
+ * family (`partial`) and the derivation alone is retried.
15
+ *
16
+ * `--tools-only` (O10/F10) mints at `mcp:plugin` scope and commits a plugin family ONLY — the
17
+ * store then holds no agent family, so App pickup is impossible by design and the runner appears
18
+ * as its own revocable device group.
19
+ *
20
+ * The D6/F7 account-switch guard runs before ANY write: a subject mismatch prompts
21
+ * (`--yes`-gated); decline revokes the just-minted family (best effort, RFC 7009) and aborts with
22
+ * the store untouched.
23
+ */
24
+ /** How many times the F1 `partial` state retries the derivation leg within one login run. */
25
+ const DERIVE_RETRY_ATTEMPTS = 3;
26
+ /** Base backoff between derivation retries (doubles per attempt). */
27
+ const DERIVE_RETRY_BASE_MS = 500;
28
+ const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
29
+ /**
30
+ * The D6/F7 account-switch confirmation used when no callback is injected:
31
+ * - `--yes` ⇒ confirmed without prompting (F7 "`--yes`-gated");
32
+ * - interactive TTY ⇒ y/N prompt (default No);
33
+ * - non-interactive without `--yes` ⇒ DECLINED (fail closed) with an actionable hint.
34
+ */
35
+ function buildAccountSwitchConfirm(assumeYes) {
36
+ return async (info) => {
37
+ ui.warn(`This machine is currently signed in as "${info.storedSubject}"; you are signing in as "${info.newSubject}".`);
38
+ ui.info('Switching replaces the stored credential and signs the previous account out on this machine.');
39
+ if (assumeYes) {
40
+ ui.info('--yes given: switching accounts.');
41
+ return true;
42
+ }
43
+ if (!process.stdin.isTTY) {
44
+ ui.error('Account switch requires confirmation. Re-run with --yes to switch accounts.');
45
+ return false;
46
+ }
47
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
48
+ try {
49
+ const answer = (await rl.question('Switch this machine to the new account? [y/N] ')).trim();
50
+ return answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes';
51
+ }
52
+ finally {
53
+ rl.close();
54
+ }
55
+ };
56
+ }
57
+ /** The v2 document's plugin-plane access token (v1 mirror first — it IS the plugin family's). */
58
+ function pluginPlaneToken(document) {
59
+ return (document.accessToken ??
60
+ document.families?.plugin?.accessToken ??
61
+ document.families?.legacy?.accessToken ??
62
+ null);
63
+ }
64
+ /**
65
+ * Retry the F1.4 derivation leg alone (the `partial` state): RFC 8693 exchange → plugin family +
66
+ * v1 mirror under one lock hold. Returns the committed document, or null when every attempt
67
+ * failed or the store changed underneath (aborts are terminal — retrying cannot help).
68
+ */
69
+ async function retryDerivePluginFamily(params) {
70
+ const attempts = params.attempts ?? DERIVE_RETRY_ATTEMPTS;
71
+ for (let attempt = 1; attempt <= attempts; attempt++) {
72
+ const result = await derivePluginFamily({
73
+ store: params.store,
74
+ exchangeClient: params.exchangeClient,
75
+ clientId: unityAdapter.clientId,
76
+ agentAccessToken: params.agentAccessToken,
77
+ ...(params.expectedSubject !== undefined ? { expectedSubject: params.expectedSubject } : {}),
78
+ ...(params.serverTarget !== undefined ? { serverTarget: params.serverTarget } : {}),
79
+ ...(params.revokeToken ? { revokeToken: params.revokeToken } : {}),
80
+ onWarning: ui.warn,
81
+ });
82
+ if (result.status === 'derived') {
83
+ return result.document;
84
+ }
85
+ if (result.status === 'aborted') {
86
+ // Store-missing / subject-changed / store-unreadable: a concurrent flow changed the world;
87
+ // the orphaned derived family was already revoked best-effort by cli-core. Terminal.
88
+ ui.error(`Could not finish authorization: ${result.reason}. Run \`unity-mcp-cli login\` again.`);
89
+ return null;
90
+ }
91
+ ui.warn(`Deriving the tools credential failed (${result.reason}) — attempt ${attempt}/${attempts}.`);
92
+ if (attempt < attempts) {
93
+ await params.sleep(DERIVE_RETRY_BASE_MS * 2 ** (attempt - 1));
94
+ }
95
+ }
96
+ return null;
97
+ }
98
+ /**
99
+ * Finish a previously interrupted agent login (F1 `partial`: agent family committed, plugin
100
+ * derivation missing) using a FRESH agent access token supplied by the caller. Returns true when
101
+ * the plugin family is committed.
102
+ */
103
+ export async function completePluginDerivation(store, agentAccessToken, options = {}) {
104
+ const serverBaseUrl = options.serverBaseUrl ?? CLOUD_SERVER_BASE_URL;
105
+ const exchangeClient = options.exchangeClient ?? new HttpTokenExchangeClient({ defaultServerBaseUrl: serverBaseUrl });
106
+ const stored = safeRead(store);
107
+ const document = await retryDerivePluginFamily({
108
+ store,
109
+ exchangeClient,
110
+ agentAccessToken,
111
+ expectedSubject: stored?.subject,
112
+ serverTarget: stored?.serverTarget,
113
+ revokeToken: options.revokeToken,
114
+ sleep: options.sleep ?? defaultSleep,
115
+ });
116
+ if (document) {
117
+ ui.success('Authorization completed: tools credential derived.');
118
+ return true;
119
+ }
120
+ return false;
121
+ }
122
+ function safeRead(store) {
123
+ try {
124
+ return store.read();
125
+ }
126
+ catch {
127
+ return null;
128
+ }
129
+ }
7
130
  /**
8
131
  * Run the cloud device-auth flow: initiate, display the user code + verification URL, open the
9
- * browser, poll, and persist the FULL credential to the shared machine credential store.
132
+ * browser, poll, then commit through cli-core's login-commit machinery (two-lock-hold agent
133
+ * commit + exchange-derived plugin family, or the tools-only plugin commit — never a raw
134
+ * `store.write`).
10
135
  *
11
- * Returns the access token on success, or null on failure (errors are printed).
136
+ * Returns the plugin-plane access token on success, or null on failure (errors are printed).
12
137
  */
13
- export async function runCloudLogin(store, deps = {}) {
14
- const serverBaseUrl = deps.serverBaseUrl ?? CLOUD_SERVER_BASE_URL;
15
- const login = deps.login ?? deviceLogin;
138
+ export async function runCloudLogin(store, options = {}) {
139
+ const serverBaseUrl = options.serverBaseUrl ?? CLOUD_SERVER_BASE_URL;
140
+ const login = options.login ?? deviceLogin;
141
+ const sleep = options.sleep ?? defaultSleep;
16
142
  let spinner;
17
143
  try {
18
144
  const result = await login({
19
145
  serverBaseUrl,
20
146
  clientId: unityAdapter.clientId, // unity-mcp-cli
21
- scope: DEFAULT_PLUGIN_SCOPE, // mcp:plugin
147
+ // Agent scope by default (03 §F1); plugin scope only for --tools-only (O10/F10).
148
+ scope: options.toolsOnly ? DEFAULT_PLUGIN_SCOPE : MCP_AGENT_SCOPE,
22
149
  onUserCode: (userCode, verificationUri) => {
23
150
  ui.info('Open this URL to authorize:');
24
151
  console.log();
@@ -31,17 +158,71 @@ export async function runCloudLogin(store, deps = {}) {
31
158
  },
32
159
  openBrowser,
33
160
  });
34
- if (result.ok) {
35
- spinner?.success('Authorized');
36
- // Persist the FULL credential set (accessToken + refreshToken + expiresAt + serverTarget +
37
- // subject) — never a project config file. This closes B3 (the legacy flow stored only
38
- // accessToken + serverTarget, losing the refresh/expiry needed for proactive refresh).
39
- store.write(result.credentials);
40
- return result.credentials.accessToken ?? null;
161
+ if (!result.ok) {
162
+ spinner?.stop();
163
+ ui.error(result.message);
164
+ return null;
165
+ }
166
+ spinner?.success('Authorized');
167
+ const confirmAccountSwitch = options.confirmAccountSwitch ?? buildAccountSwitchConfirm(options.assumeYes ?? false);
168
+ if (options.toolsOnly) {
169
+ const commit = await commitToolsOnlyLogin({
170
+ store,
171
+ clientId: unityAdapter.clientId,
172
+ credentials: result.credentials,
173
+ confirmAccountSwitch,
174
+ ...(options.revokeToken ? { revokeToken: options.revokeToken } : {}),
175
+ onWarning: ui.warn,
176
+ });
177
+ switch (commit.status) {
178
+ case 'committed':
179
+ return pluginPlaneToken(commit.document);
180
+ case 'switch-declined':
181
+ ui.error('Account switch declined — nothing was changed. The new sign-in was revoked.');
182
+ return null;
183
+ case 'aborted':
184
+ ui.error('The credential store changed while signing in. Run `unity-mcp-cli login` again.');
185
+ return null;
186
+ }
187
+ }
188
+ const exchangeClient = options.exchangeClient ?? new HttpTokenExchangeClient({ defaultServerBaseUrl: serverBaseUrl });
189
+ const commit = await commitAgentLogin({
190
+ store,
191
+ exchangeClient,
192
+ clientId: unityAdapter.clientId,
193
+ credentials: result.credentials,
194
+ confirmAccountSwitch,
195
+ ...(options.revokeToken ? { revokeToken: options.revokeToken } : {}),
196
+ onWarning: ui.warn,
197
+ });
198
+ switch (commit.status) {
199
+ case 'committed':
200
+ return pluginPlaneToken(commit.document);
201
+ case 'partial': {
202
+ // F1 failure path: the agent family IS committed; retry the derivation leg alone.
203
+ ui.warn(`Partially authorized (${commit.exchangeFailure}). Retrying the tools credential...`);
204
+ const document = await retryDerivePluginFamily({
205
+ store,
206
+ exchangeClient,
207
+ agentAccessToken: result.credentials.accessToken ?? '',
208
+ expectedSubject: result.credentials.subject,
209
+ serverTarget: result.credentials.serverTarget,
210
+ revokeToken: options.revokeToken,
211
+ sleep,
212
+ });
213
+ if (document) {
214
+ return pluginPlaneToken(document);
215
+ }
216
+ ui.error('Signed in, but deriving the tools credential failed. Run `unity-mcp-cli login` again to finish authorization.');
217
+ return null;
218
+ }
219
+ case 'switch-declined':
220
+ ui.error('Account switch declined — nothing was changed. The new sign-in was revoked.');
221
+ return null;
222
+ case 'aborted':
223
+ ui.error('The credential store changed while signing in. Run `unity-mcp-cli login` again.');
224
+ return null;
41
225
  }
42
- spinner?.stop();
43
- ui.error(result.message);
44
- return null;
45
226
  }
46
227
  catch (err) {
47
228
  spinner?.stop();
@@ -1 +1 @@
1
- {"version":3,"file":"cloud-login.js","sourceRoot":"","sources":["../../src/utils/cloud-login.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,kDAAkD;AAElD,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EACL,WAAW,EACX,YAAY,EACZ,oBAAoB,GAGrB,MAAM,0BAA0B,CAAC;AAkBlC;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAA6B,EAC7B,OAA0B,EAAE;IAE5B,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,qBAAqB,CAAC;IAClE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,WAAW,CAAC;IACxC,IAAI,OAAuD,CAAC;IAE5D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC;YACzB,aAAa;YACb,QAAQ,EAAE,YAAY,CAAC,QAAQ,EAAE,gBAAgB;YACjD,KAAK,EAAE,oBAAoB,EAAE,aAAa;YAC1C,UAAU,EAAE,CAAC,QAAQ,EAAE,eAAe,EAAE,EAAE;gBACxC,EAAE,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;gBACvC,OAAO,CAAC,GAAG,EAAE,CAAC;gBACd,OAAO,CAAC,GAAG,CAAC,KAAK,eAAe,EAAE,CAAC,CAAC;gBACpC,OAAO,CAAC,GAAG,EAAE,CAAC;gBACd,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YAC7B,CAAC;YACD,SAAS,EAAE,GAAG,EAAE;gBACd,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,8BAA8B,CAAC,CAAC;YAC5D,CAAC;YACD,WAAW;SACZ,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;YACd,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;YAE/B,2FAA2F;YAC3F,sFAAsF;YACtF,uFAAuF;YACvF,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAEhC,OAAO,MAAM,CAAC,WAAW,CAAC,WAAW,IAAI,IAAI,CAAC;QAChD,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,CAAC;QAChB,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,IAAI,EAAE,CAAC;QAChB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YACzE,EAAE,CAAC,KAAK,CAAC,gCAAgC,aAAa,EAAE,CAAC,CAAC;QAC5D,CAAC;aAAM,CAAC;YACN,EAAE,CAAC,KAAK,CAAC,0BAA0B,OAAO,EAAE,CAAC,CAAC;QAChD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"cloud-login.js","sourceRoot":"","sources":["../../src/utils/cloud-login.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,kDAAkD;AAElD,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EACL,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,EACvB,oBAAoB,EACpB,eAAe,GAMhB,MAAM,0BAA0B,CAAC;AAElC;;;;;;;;;;;;;;;GAeG;AAEH,6FAA6F;AAC7F,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAChC,qEAAqE;AACrE,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAyBjC,MAAM,YAAY,GAAG,CAAC,EAAU,EAAiB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAEtG;;;;;GAKG;AACH,SAAS,yBAAyB,CAChC,SAAkB;IAElB,OAAO,KAAK,EAAE,IAAI,EAAE,EAAE;QACpB,EAAE,CAAC,IAAI,CACL,2CAA2C,IAAI,CAAC,aAAa,6BAA6B,IAAI,CAAC,UAAU,IAAI,CAC9G,CAAC;QACF,EAAE,CAAC,IAAI,CAAC,8FAA8F,CAAC,CAAC;QACxG,IAAI,SAAS,EAAE,CAAC;YACd,EAAE,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;YAC5C,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACzB,EAAE,CAAC,KAAK,CAAC,6EAA6E,CAAC,CAAC;YACxF,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACtF,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gDAAgD,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC5F,OAAO,MAAM,CAAC,WAAW,EAAE,KAAK,GAAG,IAAI,MAAM,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC;QACxE,CAAC;gBAAS,CAAC;YACT,EAAE,CAAC,KAAK,EAAE,CAAC;QACb,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,iGAAiG;AACjG,SAAS,gBAAgB,CAAC,QAA4B;IACpD,OAAO,CACL,QAAQ,CAAC,WAAW;QACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW;QACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW;QACtC,IAAI,CACL,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,uBAAuB,CAAC,MAStC;IACC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,qBAAqB,CAAC;IAC1D,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC;YACtC,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,cAAc,EAAE,MAAM,CAAC,cAAc;YACrC,QAAQ,EAAE,YAAY,CAAC,QAAQ;YAC/B,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;YACzC,GAAG,CAAC,MAAM,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5F,GAAG,CAAC,MAAM,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnF,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClE,SAAS,EAAE,EAAE,CAAC,IAAI;SACnB,CAAC,CAAC;QACH,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,OAAO,MAAM,CAAC,QAAQ,CAAC;QACzB,CAAC;QACD,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,2FAA2F;YAC3F,qFAAqF;YACrF,EAAE,CAAC,KAAK,CAAC,mCAAmC,MAAM,CAAC,MAAM,sCAAsC,CAAC,CAAC;YACjG,OAAO,IAAI,CAAC;QACd,CAAC;QACD,EAAE,CAAC,IAAI,CAAC,yCAAyC,MAAM,CAAC,MAAM,eAAe,OAAO,IAAI,QAAQ,GAAG,CAAC,CAAC;QACrG,IAAI,OAAO,GAAG,QAAQ,EAAE,CAAC;YACvB,MAAM,MAAM,CAAC,KAAK,CAAC,oBAAoB,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,KAA6B,EAC7B,gBAAwB,EACxB,UAAoG,EAAE;IAEtG,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,qBAAqB,CAAC;IACrE,MAAM,cAAc,GAClB,OAAO,CAAC,cAAc,IAAI,IAAI,uBAAuB,CAAC,EAAE,oBAAoB,EAAE,aAAa,EAAE,CAAC,CAAC;IACjG,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,MAAM,uBAAuB,CAAC;QAC7C,KAAK;QACL,cAAc;QACd,gBAAgB;QAChB,eAAe,EAAE,MAAM,EAAE,OAAO;QAChC,YAAY,EAAE,MAAM,EAAE,YAAY;QAClC,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,YAAY;KACrC,CAAC,CAAC;IACH,IAAI,QAAQ,EAAE,CAAC;QACb,EAAE,CAAC,OAAO,CAAC,oDAAoD,CAAC,CAAC;QACjE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,QAAQ,CAAC,KAA6B;IAC7C,IAAI,CAAC;QACH,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAA6B,EAC7B,UAAgC,EAAE;IAElC,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,qBAAqB,CAAC;IACrE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,WAAW,CAAC;IAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,YAAY,CAAC;IAC5C,IAAI,OAAuD,CAAC;IAE5D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC;YACzB,aAAa;YACb,QAAQ,EAAE,YAAY,CAAC,QAAQ,EAAE,gBAAgB;YACjD,iFAAiF;YACjF,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,eAAe;YACjE,UAAU,EAAE,CAAC,QAAQ,EAAE,eAAe,EAAE,EAAE;gBACxC,EAAE,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;gBACvC,OAAO,CAAC,GAAG,EAAE,CAAC;gBACd,OAAO,CAAC,GAAG,CAAC,KAAK,eAAe,EAAE,CAAC,CAAC;gBACpC,OAAO,CAAC,GAAG,EAAE,CAAC;gBACd,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YAC7B,CAAC;YACD,SAAS,EAAE,GAAG,EAAE;gBACd,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,8BAA8B,CAAC,CAAC;YAC5D,CAAC;YACD,WAAW;SACZ,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,OAAO,EAAE,IAAI,EAAE,CAAC;YAChB,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;QAE/B,MAAM,oBAAoB,GACxB,OAAO,CAAC,oBAAoB,IAAI,yBAAyB,CAAC,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC;QAExF,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACtB,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC;gBACxC,KAAK;gBACL,QAAQ,EAAE,YAAY,CAAC,QAAQ;gBAC/B,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,oBAAoB;gBACpB,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpE,SAAS,EAAE,EAAE,CAAC,IAAI;aACnB,CAAC,CAAC;YACH,QAAQ,MAAM,CAAC,MAAM,EAAE,CAAC;gBACtB,KAAK,WAAW;oBACd,OAAO,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBAC3C,KAAK,iBAAiB;oBACpB,EAAE,CAAC,KAAK,CAAC,6EAA6E,CAAC,CAAC;oBACxF,OAAO,IAAI,CAAC;gBACd,KAAK,SAAS;oBACZ,EAAE,CAAC,KAAK,CAAC,iFAAiF,CAAC,CAAC;oBAC5F,OAAO,IAAI,CAAC;YAChB,CAAC;QACH,CAAC;QAED,MAAM,cAAc,GAClB,OAAO,CAAC,cAAc,IAAI,IAAI,uBAAuB,CAAC,EAAE,oBAAoB,EAAE,aAAa,EAAE,CAAC,CAAC;QAEjG,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC;YACpC,KAAK;YACL,cAAc;YACd,QAAQ,EAAE,YAAY,CAAC,QAAQ;YAC/B,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,oBAAoB;YACpB,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpE,SAAS,EAAE,EAAE,CAAC,IAAI;SACnB,CAAC,CAAC;QAEH,QAAQ,MAAM,CAAC,MAAM,EAAE,CAAC;YACtB,KAAK,WAAW;gBACd,OAAO,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC3C,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,kFAAkF;gBAClF,EAAE,CAAC,IAAI,CAAC,yBAAyB,MAAM,CAAC,eAAe,qCAAqC,CAAC,CAAC;gBAC9F,MAAM,QAAQ,GAAG,MAAM,uBAAuB,CAAC;oBAC7C,KAAK;oBACL,cAAc;oBACd,gBAAgB,EAAE,MAAM,CAAC,WAAW,CAAC,WAAW,IAAI,EAAE;oBACtD,eAAe,EAAE,MAAM,CAAC,WAAW,CAAC,OAAO;oBAC3C,YAAY,EAAE,MAAM,CAAC,WAAW,CAAC,YAAY;oBAC7C,WAAW,EAAE,OAAO,CAAC,WAAW;oBAChC,KAAK;iBACN,CAAC,CAAC;gBACH,IAAI,QAAQ,EAAE,CAAC;oBACb,OAAO,gBAAgB,CAAC,QAAQ,CAAC,CAAC;gBACpC,CAAC;gBACD,EAAE,CAAC,KAAK,CACN,+GAA+G,CAChH,CAAC;gBACF,OAAO,IAAI,CAAC;YACd,CAAC;YACD,KAAK,iBAAiB;gBACpB,EAAE,CAAC,KAAK,CAAC,6EAA6E,CAAC,CAAC;gBACxF,OAAO,IAAI,CAAC;YACd,KAAK,SAAS;gBACZ,EAAE,CAAC,KAAK,CAAC,iFAAiF,CAAC,CAAC;gBAC5F,OAAO,IAAI,CAAC;QAChB,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,IAAI,EAAE,CAAC;QAChB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YACzE,EAAE,CAAC,KAAK,CAAC,gCAAgC,aAAa,EAAE,CAAC,CAAC;QAC5D,CAAC;aAAM,CAAC;YACN,EAAE,CAAC,KAAK,CAAC,0BAA0B,OAAO,EAAE,CAAC,CAAC;QAChD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -56,37 +56,31 @@ export declare function updateFeatures(config: UnityConnectionConfig, featureTyp
56
56
  export declare function isCloudMode(config: UnityConnectionConfig): boolean;
57
57
  export declare const CLOUD_SERVER_BASE_URL = "https://ai-game.dev";
58
58
  export declare const CLOUD_SERVER_URL = "https://ai-game.dev/mcp";
59
- /**
60
- * Read the Cloud-mode Bearer credential from the shared machine credential store
61
- * (`~/.ai-game-dev/credentials.json`, managed by `@baizor/gamedev-cli-core`).
62
- *
63
- * Post-T9 the Unity plugin no longer writes `cloudToken` into the project config — the cloud auth
64
- * token now lives once per machine in the shared store (written by `unity-mcp-cli login`). Returns the
65
- * stored `accessToken`, or `undefined` when the user is not logged in OR the store is unreadable — a
66
- * corrupt/undecryptable store must degrade to "not logged in", never crash a tool call.
67
- */
68
- export declare function readMachineStoreCloudToken(): string | undefined;
69
59
  /** Options for {@link resolveConnectionFromConfig}. */
70
60
  export interface ResolveConnectionFromConfigOptions {
71
61
  /**
72
- * Reads the Cloud-mode Bearer credential from the shared machine credential store. Injectable so
73
- * tests (and advanced callers) can supply a deterministic value without touching the real
74
- * per-machine store. Defaults to {@link readMachineStoreCloudToken}.
62
+ * Supplies the Cloud-mode Bearer credential. REQUIRED (no built-in default): the production
63
+ * value is `readCloudAccessToken` from `cloud-credentials.ts` — cli-core's
64
+ * `MachineCredentialProvider`, which proactively refreshes an expiring token under the
65
+ * cross-process lock (unified-machine-auth 04 §3). A raw on-disk `accessToken` read must never
66
+ * reappear here: it returns a token nobody refreshes (the pre-d2 defect). Tests inject a
67
+ * deterministic value; sync or async both work.
75
68
  */
76
- readCloudToken?: () => string | undefined;
69
+ readCloudToken: () => Promise<string | undefined> | string | undefined;
77
70
  }
78
71
  /**
79
72
  * Resolve the server URL and auth token from a project config based on connectionMode.
80
73
  * - Custom mode (string "Custom" or integer 0): uses `host` and `token` (self-host / derived-port).
81
74
  * - Cloud mode (string "Cloud" or integer 1): uses the hardcoded cloud URL and the Bearer credential
82
- * from the shared machine credential store (`~/.ai-game-dev/credentials.json`) — NOT the on-disk
83
- * `cloudToken`, which the plugin stopped writing post-T9 (defect E / D11).
75
+ * supplied by `options.readCloudToken` (production: the shared machine credential store via
76
+ * cli-core's refreshing `MachineCredentialProvider`) — NOT the on-disk `cloudToken`, which the
77
+ * plugin stopped writing post-T9 (defect E / D11).
84
78
  * In Custom mode, `url` and `token` may be undefined if the corresponding config fields are not set.
85
- * In Cloud mode, `url` is always the hardcoded cloud URL, while `token` is the stored credential and is
86
- * `undefined` when the user is not logged in — the caller surfaces an actionable "not logged in" error
87
- * rather than issuing a silent unauthenticated request.
79
+ * In Cloud mode, `url` is always the hardcoded cloud URL, while `token` is the provided credential and
80
+ * is `undefined` when the user is not logged in — the caller surfaces an actionable "not logged in"
81
+ * error rather than issuing a silent unauthenticated request.
88
82
  */
89
- export declare function resolveConnectionFromConfig(config: UnityConnectionConfig, options?: ResolveConnectionFromConfigOptions): {
83
+ export declare function resolveConnectionFromConfig(config: UnityConnectionConfig, options: ResolveConnectionFromConfigOptions): Promise<{
90
84
  url: string | undefined;
91
85
  token: string | undefined;
92
- };
86
+ }>;
@@ -1,7 +1,6 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import { generatePortFromDirectory } from './port.js';
4
- import { MachineCredentialStore } from './machine-credentials.js';
5
4
  const CONFIG_RELATIVE_PATH = 'UserSettings/AI-Game-Developer-Config.json';
6
5
  function getConfigPath(projectPath) {
7
6
  return path.join(projectPath, CONFIG_RELATIVE_PATH);
@@ -126,38 +125,21 @@ export function isCloudMode(config) {
126
125
  }
127
126
  export const CLOUD_SERVER_BASE_URL = 'https://ai-game.dev';
128
127
  export const CLOUD_SERVER_URL = 'https://ai-game.dev/mcp';
129
- /**
130
- * Read the Cloud-mode Bearer credential from the shared machine credential store
131
- * (`~/.ai-game-dev/credentials.json`, managed by `@baizor/gamedev-cli-core`).
132
- *
133
- * Post-T9 the Unity plugin no longer writes `cloudToken` into the project config — the cloud auth
134
- * token now lives once per machine in the shared store (written by `unity-mcp-cli login`). Returns the
135
- * stored `accessToken`, or `undefined` when the user is not logged in OR the store is unreadable — a
136
- * corrupt/undecryptable store must degrade to "not logged in", never crash a tool call.
137
- */
138
- export function readMachineStoreCloudToken() {
139
- try {
140
- return new MachineCredentialStore().read()?.accessToken ?? undefined;
141
- }
142
- catch {
143
- return undefined;
144
- }
145
- }
146
128
  /**
147
129
  * Resolve the server URL and auth token from a project config based on connectionMode.
148
130
  * - Custom mode (string "Custom" or integer 0): uses `host` and `token` (self-host / derived-port).
149
131
  * - Cloud mode (string "Cloud" or integer 1): uses the hardcoded cloud URL and the Bearer credential
150
- * from the shared machine credential store (`~/.ai-game-dev/credentials.json`) — NOT the on-disk
151
- * `cloudToken`, which the plugin stopped writing post-T9 (defect E / D11).
132
+ * supplied by `options.readCloudToken` (production: the shared machine credential store via
133
+ * cli-core's refreshing `MachineCredentialProvider`) — NOT the on-disk `cloudToken`, which the
134
+ * plugin stopped writing post-T9 (defect E / D11).
152
135
  * In Custom mode, `url` and `token` may be undefined if the corresponding config fields are not set.
153
- * In Cloud mode, `url` is always the hardcoded cloud URL, while `token` is the stored credential and is
154
- * `undefined` when the user is not logged in — the caller surfaces an actionable "not logged in" error
155
- * rather than issuing a silent unauthenticated request.
136
+ * In Cloud mode, `url` is always the hardcoded cloud URL, while `token` is the provided credential and
137
+ * is `undefined` when the user is not logged in — the caller surfaces an actionable "not logged in"
138
+ * error rather than issuing a silent unauthenticated request.
156
139
  */
157
- export function resolveConnectionFromConfig(config, options = {}) {
140
+ export async function resolveConnectionFromConfig(config, options) {
158
141
  if (isCloudMode(config)) {
159
- const readCloudToken = options.readCloudToken ?? readMachineStoreCloudToken;
160
- return { url: CLOUD_SERVER_URL, token: readCloudToken() };
142
+ return { url: CLOUD_SERVER_URL, token: await options.readCloudToken() };
161
143
  }
162
144
  return { url: config.host, token: config.token };
163
145
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"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"}
@@ -31,13 +31,16 @@ export declare function resolveAndValidateProjectPath(positionalPath: string | u
31
31
  export interface ResolveConnectionDeps {
32
32
  /**
33
33
  * Injection point for the Cloud-mode machine-store credential read. Forwarded to
34
- * `resolveConnectionFromConfig`; defaults to the real per-machine store. Tests inject a
35
- * deterministic value.
34
+ * `resolveConnectionFromConfig`; defaults to `readCloudAccessToken` — cli-core's
35
+ * `MachineCredentialProvider` (proactive refresh under the cross-process lock, never a raw
36
+ * on-disk read). Tests inject a deterministic value.
36
37
  */
37
- readCloudToken?: () => string | undefined;
38
+ readCloudToken?: () => Promise<string | undefined> | string | undefined;
38
39
  }
39
- export declare function resolveConnection(projectPath: string, options: ConnectionOptions, deps?: ResolveConnectionDeps): {
40
+ export declare function resolveConnection(projectPath: string, options: ConnectionOptions, deps?: ResolveConnectionDeps): Promise<{
40
41
  url: string;
41
42
  token: string | undefined;
42
43
  cloudAuthMissing: boolean;
43
- };
44
+ /** True when the Bearer came from the shared machine store (Cloud mode, no --token override). */
45
+ tokenFromCloudStore: boolean;
46
+ }>;