@amerged/ohmyhost-mcp 0.1.18 → 0.1.20
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 +1 -1
- package/dist/{chunk-X6IS5LX7.js → chunk-NESQZ3BS.js} +7 -7
- package/dist/index.js +1 -1
- package/dist/stdio-main.js +1316 -165
- package/package.json +1 -1
- package/src/apps/mcp/local-client.ts +86 -17
- package/src/apps/mcp/local-server.ts +280 -86
- package/src/apps/mcp/stdio-main.ts +11 -2
- package/src/apps/product-cli/cli.ts +337 -92
- package/src/apps/product-cli/command.ts +111 -6
- package/src/apps/product-cli/composition.ts +748 -120
- package/src/apps/product-cli/credential-store.ts +5 -3
- package/src/apps/product-cli/index.ts +2 -0
- package/src/apps/product-cli/product-api.ts +4 -4
- package/src/apps/product-cli/profile-store.ts +609 -0
- package/src/apps/product-cli/project-link-store.ts +169 -20
- package/src/apps/product-cli/runtime-contract.ts +15 -4
- package/src/apps/product-cli/workspace.ts +75 -13
- package/src/packages/agent-skills/generated-skill-resources.ts +6 -6
- package/src/packages/sdk-ts/generated/sdk.gen.ts +1 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ManagedMailCommand } from "@ohmyhost/sdk-ts";
|
|
2
2
|
import { USER_API_KEY_ID } from "@ohmyhost/contracts/user-api-keys";
|
|
3
|
+
import { WORKOS_USER_API_KEY_PATTERN } from "@ohmyhost/workos-auth-contracts/user-api-keys";
|
|
4
|
+
import { isProfileName, isProfileUserId } from "./profile-store.js";
|
|
3
5
|
export type ProductCliCommand =
|
|
4
6
|
| {
|
|
5
7
|
readonly kind: "github-connect";
|
|
@@ -182,8 +184,11 @@ export type ProductCliCommand =
|
|
|
182
184
|
| {
|
|
183
185
|
readonly kind: "login";
|
|
184
186
|
readonly organizationId?: string;
|
|
187
|
+
/** The user the browser must sign in as; a different account stores nothing. */
|
|
188
|
+
readonly userId?: string;
|
|
185
189
|
readonly credentialStore: "native";
|
|
186
190
|
}
|
|
191
|
+
| { readonly kind: "profile-list" }
|
|
187
192
|
| {
|
|
188
193
|
readonly kind: "logout";
|
|
189
194
|
readonly revoke: boolean;
|
|
@@ -421,6 +426,10 @@ export type ProductCliCommand =
|
|
|
421
426
|
readonly idempotencyKey: string;
|
|
422
427
|
readonly stdin: true;
|
|
423
428
|
readonly wait: boolean;
|
|
429
|
+
/** Handed over from an OHMYHOST_TOKEN process: only a key of this account may run it. */
|
|
430
|
+
readonly environmentToken?: HandedAccount;
|
|
431
|
+
/** Handed over for a saved login: the login that runs it must belong to this account. */
|
|
432
|
+
readonly profileAccount?: HandedAccount;
|
|
424
433
|
readonly credentialStore: "native";
|
|
425
434
|
}
|
|
426
435
|
| {
|
|
@@ -497,6 +506,25 @@ export type ProductCliCommand =
|
|
|
497
506
|
readonly credentialStore: "native";
|
|
498
507
|
};
|
|
499
508
|
|
|
509
|
+
/**
|
|
510
|
+
* Remove the global login selector from argv. Every authenticated command accepts it; `login` uses
|
|
511
|
+
* the same flag to name the login it adds. The value is an alias, never a credential.
|
|
512
|
+
*/
|
|
513
|
+
export const extractProfileName = (
|
|
514
|
+
argv: readonly string[],
|
|
515
|
+
): { readonly argv: readonly string[]; readonly profileName?: string } => {
|
|
516
|
+
const index = argv.indexOf("--profile-name");
|
|
517
|
+
if (index < 0) return { argv };
|
|
518
|
+
const value = argv[index + 1];
|
|
519
|
+
if (
|
|
520
|
+
value === undefined ||
|
|
521
|
+
!isProfileName(value) ||
|
|
522
|
+
argv.indexOf("--profile-name", index + 1) >= 0
|
|
523
|
+
)
|
|
524
|
+
throw new InvalidCommandError();
|
|
525
|
+
return { argv: [...argv.slice(0, index), ...argv.slice(index + 2)], profileName: value };
|
|
526
|
+
};
|
|
527
|
+
|
|
500
528
|
export class InvalidCommandError extends Error {
|
|
501
529
|
public constructor() {
|
|
502
530
|
super("The command arguments are invalid.");
|
|
@@ -528,6 +556,7 @@ export type RecognizedCommandLabel =
|
|
|
528
556
|
| "init"
|
|
529
557
|
| "login"
|
|
530
558
|
| "logout"
|
|
559
|
+
| "profile list"
|
|
531
560
|
| "operation get"
|
|
532
561
|
| "operation reconcile"
|
|
533
562
|
| "token create"
|
|
@@ -598,6 +627,10 @@ export const recognizedCommandLabel = (argv: readonly string[]): RecognizedComma
|
|
|
598
627
|
if (values.includes("--version")) return "version";
|
|
599
628
|
while (values.length > 0) {
|
|
600
629
|
const value = values.shift();
|
|
630
|
+
if (value === "--profile-name") {
|
|
631
|
+
values.shift();
|
|
632
|
+
continue;
|
|
633
|
+
}
|
|
601
634
|
if (
|
|
602
635
|
value === "--json" ||
|
|
603
636
|
value === "--dry-run" ||
|
|
@@ -618,6 +651,7 @@ export const recognizedCommandLabel = (argv: readonly string[]): RecognizedComma
|
|
|
618
651
|
value === "logout"
|
|
619
652
|
)
|
|
620
653
|
return value;
|
|
654
|
+
if (value === "profile" && values[0] === "list") return "profile list";
|
|
621
655
|
if (value === "github" && values[0] === "connect") return "github connect";
|
|
622
656
|
if (value === "github" && values[0] === "status") return "github status";
|
|
623
657
|
if (value === "operation" && values[0] === "get") return "operation get";
|
|
@@ -788,16 +822,32 @@ export const parseProductCliCommand = (argv: readonly string[]): ProductCliComma
|
|
|
788
822
|
}
|
|
789
823
|
if (dryRun) throw new InvalidCommandError();
|
|
790
824
|
if (first === "login" && !revoke && !yes && !wait && !follow && !stdin) {
|
|
791
|
-
const options = parseOptionalOptions(values, ["--organization"]);
|
|
825
|
+
const options = parseOptionalOptions(values, ["--organization", "--user"]);
|
|
792
826
|
const organizationId = options["--organization"];
|
|
793
|
-
|
|
827
|
+
const userId = options["--user"];
|
|
828
|
+
if (
|
|
829
|
+
(organizationId !== undefined && !ORGANIZATION_ULID.test(organizationId)) ||
|
|
830
|
+
(userId !== undefined && !isProfileUserId(userId))
|
|
831
|
+
)
|
|
794
832
|
throw new InvalidCommandError();
|
|
795
833
|
return {
|
|
796
834
|
kind: "login",
|
|
797
835
|
...(organizationId === undefined ? {} : { organizationId }),
|
|
836
|
+
...(userId === undefined ? {} : { userId }),
|
|
798
837
|
credentialStore,
|
|
799
838
|
};
|
|
800
839
|
}
|
|
840
|
+
if (
|
|
841
|
+
first === "profile" &&
|
|
842
|
+
values.length === 1 &&
|
|
843
|
+
values[0] === "list" &&
|
|
844
|
+
!revoke &&
|
|
845
|
+
!yes &&
|
|
846
|
+
!wait &&
|
|
847
|
+
!follow &&
|
|
848
|
+
!stdin
|
|
849
|
+
)
|
|
850
|
+
return { kind: "profile-list" };
|
|
801
851
|
if (first === "logout") {
|
|
802
852
|
if (!yes && !wait && !follow && !stdin && values.length === 0)
|
|
803
853
|
return { kind: "logout", revoke, credentialStore };
|
|
@@ -1781,15 +1831,44 @@ export const parseProductCliCommand = (argv: readonly string[]): ProductCliComma
|
|
|
1781
1831
|
values.shift();
|
|
1782
1832
|
const name = values.shift();
|
|
1783
1833
|
if (!isUserSecretName(name)) throw new InvalidCommandError();
|
|
1784
|
-
const options =
|
|
1834
|
+
const options = parseOptionalOptions(values, [
|
|
1835
|
+
"--project",
|
|
1836
|
+
"--environment",
|
|
1837
|
+
"--idempotency-key",
|
|
1838
|
+
"--token-user",
|
|
1839
|
+
"--token-organization",
|
|
1840
|
+
"--profile-user",
|
|
1841
|
+
"--profile-organization",
|
|
1842
|
+
]);
|
|
1843
|
+
const projectId = options["--project"];
|
|
1844
|
+
const environmentId = options["--environment"];
|
|
1845
|
+
const idempotencyKey = options["--idempotency-key"];
|
|
1846
|
+
const environmentToken = handedAccount(
|
|
1847
|
+
options["--token-user"],
|
|
1848
|
+
options["--token-organization"],
|
|
1849
|
+
);
|
|
1850
|
+
const profileAccount = handedAccount(
|
|
1851
|
+
options["--profile-user"],
|
|
1852
|
+
options["--profile-organization"],
|
|
1853
|
+
);
|
|
1854
|
+
// A key form and a saved-login form contradict each other; neither wins.
|
|
1855
|
+
if (
|
|
1856
|
+
projectId === undefined ||
|
|
1857
|
+
environmentId === undefined ||
|
|
1858
|
+
idempotencyKey === undefined ||
|
|
1859
|
+
(environmentToken !== undefined && profileAccount !== undefined)
|
|
1860
|
+
)
|
|
1861
|
+
throw new InvalidCommandError();
|
|
1785
1862
|
return {
|
|
1786
1863
|
kind: "secret-set",
|
|
1787
|
-
projectId
|
|
1788
|
-
environmentId
|
|
1864
|
+
projectId,
|
|
1865
|
+
environmentId,
|
|
1789
1866
|
name,
|
|
1790
|
-
idempotencyKey
|
|
1867
|
+
idempotencyKey,
|
|
1791
1868
|
stdin,
|
|
1792
1869
|
wait,
|
|
1870
|
+
...(environmentToken === undefined ? {} : { environmentToken }),
|
|
1871
|
+
...(profileAccount === undefined ? {} : { profileAccount }),
|
|
1793
1872
|
credentialStore,
|
|
1794
1873
|
};
|
|
1795
1874
|
}
|
|
@@ -2034,6 +2113,32 @@ const accessTtlSeconds = (value: string | undefined): number => {
|
|
|
2034
2113
|
/** A platform organization identifier as the API returns it. */
|
|
2035
2114
|
const ORGANIZATION_ULID = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/u;
|
|
2036
2115
|
|
|
2116
|
+
/** The account a command handed to a terminal must run as; never a credential. */
|
|
2117
|
+
export interface HandedAccount {
|
|
2118
|
+
readonly userId: string;
|
|
2119
|
+
readonly organizationId: string;
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
/**
|
|
2123
|
+
* A user and an organization named together, or neither. A pasted key is refused here, before any
|
|
2124
|
+
* message could repeat it.
|
|
2125
|
+
*/
|
|
2126
|
+
const handedAccount = (
|
|
2127
|
+
userId: string | undefined,
|
|
2128
|
+
organizationId: string | undefined,
|
|
2129
|
+
): HandedAccount | undefined => {
|
|
2130
|
+
if (userId === undefined && organizationId === undefined) return undefined;
|
|
2131
|
+
if (
|
|
2132
|
+
userId === undefined ||
|
|
2133
|
+
organizationId === undefined ||
|
|
2134
|
+
!isProfileUserId(userId) ||
|
|
2135
|
+
WORKOS_USER_API_KEY_PATTERN.test(userId) ||
|
|
2136
|
+
!ORGANIZATION_ULID.test(organizationId)
|
|
2137
|
+
)
|
|
2138
|
+
throw new InvalidCommandError();
|
|
2139
|
+
return { userId, organizationId };
|
|
2140
|
+
};
|
|
2141
|
+
|
|
2037
2142
|
const isValue = (value: string | undefined): value is string =>
|
|
2038
2143
|
value !== undefined && value.length > 0 && !value.startsWith("--");
|
|
2039
2144
|
|