unity-mcp-cli 0.87.0 → 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.
- package/README.md +10 -2
- package/dist/commands/install-plugin.js +20 -0
- package/dist/commands/install-plugin.js.map +1 -1
- package/dist/commands/login.js +47 -2
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/run-tool-builder.js +19 -3
- package/dist/commands/run-tool-builder.js.map +1 -1
- package/dist/commands/setup-skills.js +1 -1
- package/dist/commands/setup-skills.js.map +1 -1
- package/dist/commands/status.js +1 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/wait-for-ready.js +4 -4
- package/dist/commands/wait-for-ready.js.map +1 -1
- package/dist/lib/run-tool.js +79 -41
- package/dist/lib/run-tool.js.map +1 -1
- package/dist/lib/types.d.ts +13 -4
- package/dist/utils/cloud-credentials.d.ts +43 -0
- package/dist/utils/cloud-credentials.js +84 -0
- package/dist/utils/cloud-credentials.js.map +1 -0
- package/dist/utils/cloud-login.d.ts +29 -13
- package/dist/utils/cloud-login.js +198 -17
- package/dist/utils/cloud-login.js.map +1 -1
- package/dist/utils/config.d.ts +15 -21
- package/dist/utils/config.js +8 -26
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/connection.d.ts +8 -5
- package/dist/utils/connection.js +7 -3
- package/dist/utils/connection.js.map +1 -1
- package/package.json +2 -2
package/dist/lib/types.d.ts
CHANGED
|
@@ -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
|
|
562
|
-
*
|
|
563
|
-
*
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
14
|
-
const serverBaseUrl =
|
|
15
|
-
const login =
|
|
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
|
|
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?.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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,
|
|
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"}
|
package/dist/utils/config.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
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
|
|
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
|
-
*
|
|
83
|
-
*
|
|
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
|
|
86
|
-
* `undefined` when the user is not logged in — the caller surfaces an actionable "not logged in"
|
|
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
|
|
83
|
+
export declare function resolveConnectionFromConfig(config: UnityConnectionConfig, options: ResolveConnectionFromConfigOptions): Promise<{
|
|
90
84
|
url: string | undefined;
|
|
91
85
|
token: string | undefined;
|
|
92
|
-
}
|
|
86
|
+
}>;
|
package/dist/utils/config.js
CHANGED
|
@@ -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
|
-
*
|
|
151
|
-
*
|
|
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
|
|
154
|
-
* `undefined` when the user is not logged in — the caller surfaces an actionable "not logged in"
|
|
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
|
-
|
|
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
|
}
|
package/dist/utils/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAC;AAEtD,MAAM,oBAAoB,GAAG,4CAA4C,CAAC;AAwB1E,SAAS,aAAa,CAAC,WAAmB;IACxC,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC;AACtD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAAmB;IACrD,MAAM,IAAI,GAAG,yBAAyB,CAAC,WAAW,CAAC,CAAC;IACpD,OAAO;QACL,IAAI,EAAE,oBAAoB,IAAI,EAAE;QAChC,aAAa,EAAE,KAAK;QACpB,QAAQ,EAAE,CAAC;QACX,SAAS,EAAE,KAAK;QAChB,iBAAiB,EAAE,KAAK;QACxB,eAAe,EAAE,gBAAgB;QACjC,UAAU,EAAE,MAAM;QAClB,cAAc,EAAE,QAAQ;QACxB,KAAK,EAAE,EAAE;QACT,OAAO,EAAE,EAAE;QACX,SAAS,EAAE,EAAE;KACd,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,WAAmB;IAC5C,MAAM,UAAU,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAC9C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAClD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAA0B,CAAC;IACnD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,WAAW,EAAE,CAAC;YAC/B,MAAM,IAAI,WAAW,CAAC,kCAAkC,UAAU,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACxF,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,WAAmB,EAAE,MAA6B;IAC5E,MAAM,UAAU,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACrC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC;IACD,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AACvE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,WAAmB;IACnD,IAAI,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC;QAC9C,OAAO,UAAU,CAAC,WAAW,CAA0B,CAAC;IAC1D,CAAC;IAED,MAAM,MAAM,GAAG,mBAAmB,CAAC,WAAW,CAAC,CAAC;IAChD,WAAW,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,MAA6B,EAC7B,WAA8C,EAC9C,OAKC;IAED,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAiB,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC;QACvD,CAAC,CAAC,WAAW,CAAC,MAAM,CAChB,CAAC,CAAC,EAAmB,EAAE,CACrB,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,SAAS,CACtG;QACH,CAAC,CAAC,EAAE,CAAC;IAEP,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACtB,KAAK,MAAM,CAAC,IAAI,QAAQ;YAAE,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC;QAC3C,MAAM,CAAC,WAAW,CAAC,GAAG,QAAQ,CAAC;QAC/B,OAAO;IACT,CAAC;IAED,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,IAAI,QAAQ;YAAE,CAAC,CAAC,OAAO,GAAG,KAAK,CAAC;QAC5C,MAAM,CAAC,WAAW,CAAC,GAAG,QAAQ,CAAC;QAC/B,OAAO;IACT,CAAC;IAED,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACvC,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;YACvD,IAAI,QAAQ,EAAE,CAAC;gBACb,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;YAC1B,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACzB,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;YACxC,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;YACvD,IAAI,QAAQ,EAAE,CAAC;gBACb,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC;YAC3B,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,CAAC,WAAW,CAAC,GAAG,QAAQ,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,MAA6B;IACvD,MAAM,IAAI,GAAG,MAAM,CAAC,cAAc,CAAC;IACnC,OAAO,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAG,qBAAqB,CAAC;AAC3D,MAAM,CAAC,MAAM,gBAAgB,GAAG,yBAAyB,CAAC;AAe1D;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,MAA6B,EAC7B,OAA2C;IAK3C,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,GAAG,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;IAC1E,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;AACnD,CAAC"}
|
|
@@ -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
|
|
35
|
-
*
|
|
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
|
+
}>;
|