@amerged/ohmyhost-mcp 0.1.19 → 0.1.21
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-PXGLL6SR.js → chunk-4WY7AAPR.js} +11 -11
- package/dist/index.js +1 -1
- package/dist/stdio-main.js +1575 -310
- package/package.json +1 -1
- package/src/apps/mcp/local-client.ts +119 -17
- package/src/apps/mcp/local-server.ts +321 -88
- package/src/apps/mcp/stdio-main.ts +11 -2
- package/src/apps/product-cli/cli.ts +370 -92
- package/src/apps/product-cli/command.ts +163 -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 +4 -0
- package/src/apps/product-cli/product-api.ts +32 -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 +63 -7
- package/src/apps/product-cli/workspace.ts +75 -13
- package/src/packages/agent-skills/generated-skill-resources.ts +10 -10
- package/src/packages/contracts/operation-failure.ts +3 -3
- package/src/packages/sdk-ts/generated/index.ts +21 -0
- package/src/packages/sdk-ts/generated/sdk.gen.ts +142 -0
- package/src/packages/sdk-ts/generated/types.gen.ts +200 -2
|
@@ -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";
|
|
@@ -125,6 +127,11 @@ export type ProductCliCommand =
|
|
|
125
127
|
readonly organizationId: string;
|
|
126
128
|
readonly credentialStore: "native";
|
|
127
129
|
}
|
|
130
|
+
| {
|
|
131
|
+
readonly kind: "referral-link";
|
|
132
|
+
readonly organizationId: string;
|
|
133
|
+
readonly credentialStore: "native";
|
|
134
|
+
}
|
|
128
135
|
| {
|
|
129
136
|
readonly kind: "credits-balance";
|
|
130
137
|
readonly organizationId: string;
|
|
@@ -182,8 +189,11 @@ export type ProductCliCommand =
|
|
|
182
189
|
| {
|
|
183
190
|
readonly kind: "login";
|
|
184
191
|
readonly organizationId?: string;
|
|
192
|
+
/** The user the browser must sign in as; a different account stores nothing. */
|
|
193
|
+
readonly userId?: string;
|
|
185
194
|
readonly credentialStore: "native";
|
|
186
195
|
}
|
|
196
|
+
| { readonly kind: "profile-list" }
|
|
187
197
|
| {
|
|
188
198
|
readonly kind: "logout";
|
|
189
199
|
readonly revoke: boolean;
|
|
@@ -251,6 +261,18 @@ export type ProductCliCommand =
|
|
|
251
261
|
readonly projectId: string;
|
|
252
262
|
readonly credentialStore: "native";
|
|
253
263
|
}
|
|
264
|
+
| {
|
|
265
|
+
readonly kind: "project-flag-status";
|
|
266
|
+
readonly projectId: string;
|
|
267
|
+
readonly credentialStore: "native";
|
|
268
|
+
}
|
|
269
|
+
| {
|
|
270
|
+
readonly kind: "project-flag-set";
|
|
271
|
+
readonly projectId: string;
|
|
272
|
+
readonly enabled: boolean;
|
|
273
|
+
readonly idempotencyKey: string;
|
|
274
|
+
readonly credentialStore: "native";
|
|
275
|
+
}
|
|
254
276
|
| {
|
|
255
277
|
readonly kind: "database-write";
|
|
256
278
|
readonly projectId: string;
|
|
@@ -421,6 +443,10 @@ export type ProductCliCommand =
|
|
|
421
443
|
readonly idempotencyKey: string;
|
|
422
444
|
readonly stdin: true;
|
|
423
445
|
readonly wait: boolean;
|
|
446
|
+
/** Handed over from an OHMYHOST_TOKEN process: only a key of this account may run it. */
|
|
447
|
+
readonly environmentToken?: HandedAccount;
|
|
448
|
+
/** Handed over for a saved login: the login that runs it must belong to this account. */
|
|
449
|
+
readonly profileAccount?: HandedAccount;
|
|
424
450
|
readonly credentialStore: "native";
|
|
425
451
|
}
|
|
426
452
|
| {
|
|
@@ -497,6 +523,25 @@ export type ProductCliCommand =
|
|
|
497
523
|
readonly credentialStore: "native";
|
|
498
524
|
};
|
|
499
525
|
|
|
526
|
+
/**
|
|
527
|
+
* Remove the global login selector from argv. Every authenticated command accepts it; `login` uses
|
|
528
|
+
* the same flag to name the login it adds. The value is an alias, never a credential.
|
|
529
|
+
*/
|
|
530
|
+
export const extractProfileName = (
|
|
531
|
+
argv: readonly string[],
|
|
532
|
+
): { readonly argv: readonly string[]; readonly profileName?: string } => {
|
|
533
|
+
const index = argv.indexOf("--profile-name");
|
|
534
|
+
if (index < 0) return { argv };
|
|
535
|
+
const value = argv[index + 1];
|
|
536
|
+
if (
|
|
537
|
+
value === undefined ||
|
|
538
|
+
!isProfileName(value) ||
|
|
539
|
+
argv.indexOf("--profile-name", index + 1) >= 0
|
|
540
|
+
)
|
|
541
|
+
throw new InvalidCommandError();
|
|
542
|
+
return { argv: [...argv.slice(0, index), ...argv.slice(index + 2)], profileName: value };
|
|
543
|
+
};
|
|
544
|
+
|
|
500
545
|
export class InvalidCommandError extends Error {
|
|
501
546
|
public constructor() {
|
|
502
547
|
super("The command arguments are invalid.");
|
|
@@ -521,6 +566,7 @@ export type RecognizedCommandLabel =
|
|
|
521
566
|
| "version"
|
|
522
567
|
| "whoami"
|
|
523
568
|
| "credits account"
|
|
569
|
+
| "referral link"
|
|
524
570
|
| "credits balance"
|
|
525
571
|
| "credits usage"
|
|
526
572
|
| "budget get"
|
|
@@ -528,6 +574,7 @@ export type RecognizedCommandLabel =
|
|
|
528
574
|
| "init"
|
|
529
575
|
| "login"
|
|
530
576
|
| "logout"
|
|
577
|
+
| "profile list"
|
|
531
578
|
| "operation get"
|
|
532
579
|
| "operation reconcile"
|
|
533
580
|
| "token create"
|
|
@@ -548,6 +595,8 @@ export type RecognizedCommandLabel =
|
|
|
548
595
|
| "project dev-share rotate"
|
|
549
596
|
| "project dev-share revoke"
|
|
550
597
|
| "project dev-access mode"
|
|
598
|
+
| "project flag status"
|
|
599
|
+
| "project flag set"
|
|
551
600
|
| "project handle check"
|
|
552
601
|
| "project handle set"
|
|
553
602
|
| "database write"
|
|
@@ -598,6 +647,10 @@ export const recognizedCommandLabel = (argv: readonly string[]): RecognizedComma
|
|
|
598
647
|
if (values.includes("--version")) return "version";
|
|
599
648
|
while (values.length > 0) {
|
|
600
649
|
const value = values.shift();
|
|
650
|
+
if (value === "--profile-name") {
|
|
651
|
+
values.shift();
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
601
654
|
if (
|
|
602
655
|
value === "--json" ||
|
|
603
656
|
value === "--dry-run" ||
|
|
@@ -618,10 +671,12 @@ export const recognizedCommandLabel = (argv: readonly string[]): RecognizedComma
|
|
|
618
671
|
value === "logout"
|
|
619
672
|
)
|
|
620
673
|
return value;
|
|
674
|
+
if (value === "profile" && values[0] === "list") return "profile list";
|
|
621
675
|
if (value === "github" && values[0] === "connect") return "github connect";
|
|
622
676
|
if (value === "github" && values[0] === "status") return "github status";
|
|
623
677
|
if (value === "operation" && values[0] === "get") return "operation get";
|
|
624
678
|
if (value === "credits" && values[0] === "account") return "credits account";
|
|
679
|
+
if (value === "referral" && values[0] === "link") return "referral link";
|
|
625
680
|
if (value === "credits" && values[0] === "balance") return "credits balance";
|
|
626
681
|
if (value === "billing" && values[0] === "recharge" && values[1] === "get")
|
|
627
682
|
return "billing recharge get";
|
|
@@ -667,6 +722,10 @@ export const recognizedCommandLabel = (argv: readonly string[]): RecognizedComma
|
|
|
667
722
|
return "project dev-access mode";
|
|
668
723
|
if (value === "project" && values[0] === "dev-access" && values[1] === "create")
|
|
669
724
|
return "project dev-access create";
|
|
725
|
+
if (value === "project" && values[0] === "flag" && values[1] === "status")
|
|
726
|
+
return "project flag status";
|
|
727
|
+
if (value === "project" && values[0] === "flag" && values[1] === "set")
|
|
728
|
+
return "project flag set";
|
|
670
729
|
if (value === "database" && values[0] === "compute" && values[1] === "set")
|
|
671
730
|
return "database compute set";
|
|
672
731
|
if (value === "database" && values[0] === "compute" && values[1] === "get")
|
|
@@ -788,16 +847,32 @@ export const parseProductCliCommand = (argv: readonly string[]): ProductCliComma
|
|
|
788
847
|
}
|
|
789
848
|
if (dryRun) throw new InvalidCommandError();
|
|
790
849
|
if (first === "login" && !revoke && !yes && !wait && !follow && !stdin) {
|
|
791
|
-
const options = parseOptionalOptions(values, ["--organization"]);
|
|
850
|
+
const options = parseOptionalOptions(values, ["--organization", "--user"]);
|
|
792
851
|
const organizationId = options["--organization"];
|
|
793
|
-
|
|
852
|
+
const userId = options["--user"];
|
|
853
|
+
if (
|
|
854
|
+
(organizationId !== undefined && !ORGANIZATION_ULID.test(organizationId)) ||
|
|
855
|
+
(userId !== undefined && !isProfileUserId(userId))
|
|
856
|
+
)
|
|
794
857
|
throw new InvalidCommandError();
|
|
795
858
|
return {
|
|
796
859
|
kind: "login",
|
|
797
860
|
...(organizationId === undefined ? {} : { organizationId }),
|
|
861
|
+
...(userId === undefined ? {} : { userId }),
|
|
798
862
|
credentialStore,
|
|
799
863
|
};
|
|
800
864
|
}
|
|
865
|
+
if (
|
|
866
|
+
first === "profile" &&
|
|
867
|
+
values.length === 1 &&
|
|
868
|
+
values[0] === "list" &&
|
|
869
|
+
!revoke &&
|
|
870
|
+
!yes &&
|
|
871
|
+
!wait &&
|
|
872
|
+
!follow &&
|
|
873
|
+
!stdin
|
|
874
|
+
)
|
|
875
|
+
return { kind: "profile-list" };
|
|
801
876
|
if (first === "logout") {
|
|
802
877
|
if (!yes && !wait && !follow && !stdin && values.length === 0)
|
|
803
878
|
return { kind: "logout", revoke, credentialStore };
|
|
@@ -1030,6 +1105,12 @@ export const parseProductCliCommand = (argv: readonly string[]): ProductCliComma
|
|
|
1030
1105
|
const options = parseOptions(values, ["--organization"]);
|
|
1031
1106
|
return { kind: "credits-account", organizationId: options["--organization"], credentialStore };
|
|
1032
1107
|
}
|
|
1108
|
+
if (first === "referral" && values[0] === "link") {
|
|
1109
|
+
values.shift();
|
|
1110
|
+
if (yes || wait || follow || stdin) throw new InvalidCommandError();
|
|
1111
|
+
const options = parseOptions(values, ["--organization"]);
|
|
1112
|
+
return { kind: "referral-link", organizationId: options["--organization"], credentialStore };
|
|
1113
|
+
}
|
|
1033
1114
|
if (first === "credits" && values.shift() === "balance") {
|
|
1034
1115
|
if (yes || wait || follow || stdin) throw new InvalidCommandError();
|
|
1035
1116
|
const options = parseOptions(values, ["--organization"]);
|
|
@@ -1216,6 +1297,27 @@ export const parseProductCliCommand = (argv: readonly string[]): ProductCliComma
|
|
|
1216
1297
|
credentialStore,
|
|
1217
1298
|
};
|
|
1218
1299
|
}
|
|
1300
|
+
if (subcommand === "flag") {
|
|
1301
|
+
const action = values.shift();
|
|
1302
|
+
if (yes || wait || follow || stdin) throw new InvalidCommandError();
|
|
1303
|
+
if (action === "status") {
|
|
1304
|
+
const options = parseOptions(values, ["--project"]);
|
|
1305
|
+
return { kind: "project-flag-status", projectId: options["--project"], credentialStore };
|
|
1306
|
+
}
|
|
1307
|
+
if (action === "set") {
|
|
1308
|
+
const options = parseOptions(values, ["--project", "--enabled", "--idempotency-key"]);
|
|
1309
|
+
if (options["--enabled"] !== "true" && options["--enabled"] !== "false")
|
|
1310
|
+
throw new InvalidCommandError();
|
|
1311
|
+
return {
|
|
1312
|
+
kind: "project-flag-set",
|
|
1313
|
+
projectId: options["--project"],
|
|
1314
|
+
enabled: options["--enabled"] === "true",
|
|
1315
|
+
idempotencyKey: options["--idempotency-key"],
|
|
1316
|
+
credentialStore,
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
throw new InvalidCommandError();
|
|
1320
|
+
}
|
|
1219
1321
|
if (subcommand === "dev-access" && values.shift() === "create") {
|
|
1220
1322
|
if (yes || wait || follow || stdin) throw new InvalidCommandError();
|
|
1221
1323
|
const options = parseOptions(values, ["--project"]);
|
|
@@ -1781,15 +1883,44 @@ export const parseProductCliCommand = (argv: readonly string[]): ProductCliComma
|
|
|
1781
1883
|
values.shift();
|
|
1782
1884
|
const name = values.shift();
|
|
1783
1885
|
if (!isUserSecretName(name)) throw new InvalidCommandError();
|
|
1784
|
-
const options =
|
|
1886
|
+
const options = parseOptionalOptions(values, [
|
|
1887
|
+
"--project",
|
|
1888
|
+
"--environment",
|
|
1889
|
+
"--idempotency-key",
|
|
1890
|
+
"--token-user",
|
|
1891
|
+
"--token-organization",
|
|
1892
|
+
"--profile-user",
|
|
1893
|
+
"--profile-organization",
|
|
1894
|
+
]);
|
|
1895
|
+
const projectId = options["--project"];
|
|
1896
|
+
const environmentId = options["--environment"];
|
|
1897
|
+
const idempotencyKey = options["--idempotency-key"];
|
|
1898
|
+
const environmentToken = handedAccount(
|
|
1899
|
+
options["--token-user"],
|
|
1900
|
+
options["--token-organization"],
|
|
1901
|
+
);
|
|
1902
|
+
const profileAccount = handedAccount(
|
|
1903
|
+
options["--profile-user"],
|
|
1904
|
+
options["--profile-organization"],
|
|
1905
|
+
);
|
|
1906
|
+
// A key form and a saved-login form contradict each other; neither wins.
|
|
1907
|
+
if (
|
|
1908
|
+
projectId === undefined ||
|
|
1909
|
+
environmentId === undefined ||
|
|
1910
|
+
idempotencyKey === undefined ||
|
|
1911
|
+
(environmentToken !== undefined && profileAccount !== undefined)
|
|
1912
|
+
)
|
|
1913
|
+
throw new InvalidCommandError();
|
|
1785
1914
|
return {
|
|
1786
1915
|
kind: "secret-set",
|
|
1787
|
-
projectId
|
|
1788
|
-
environmentId
|
|
1916
|
+
projectId,
|
|
1917
|
+
environmentId,
|
|
1789
1918
|
name,
|
|
1790
|
-
idempotencyKey
|
|
1919
|
+
idempotencyKey,
|
|
1791
1920
|
stdin,
|
|
1792
1921
|
wait,
|
|
1922
|
+
...(environmentToken === undefined ? {} : { environmentToken }),
|
|
1923
|
+
...(profileAccount === undefined ? {} : { profileAccount }),
|
|
1793
1924
|
credentialStore,
|
|
1794
1925
|
};
|
|
1795
1926
|
}
|
|
@@ -2034,6 +2165,32 @@ const accessTtlSeconds = (value: string | undefined): number => {
|
|
|
2034
2165
|
/** A platform organization identifier as the API returns it. */
|
|
2035
2166
|
const ORGANIZATION_ULID = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/u;
|
|
2036
2167
|
|
|
2168
|
+
/** The account a command handed to a terminal must run as; never a credential. */
|
|
2169
|
+
export interface HandedAccount {
|
|
2170
|
+
readonly userId: string;
|
|
2171
|
+
readonly organizationId: string;
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
/**
|
|
2175
|
+
* A user and an organization named together, or neither. A pasted key is refused here, before any
|
|
2176
|
+
* message could repeat it.
|
|
2177
|
+
*/
|
|
2178
|
+
const handedAccount = (
|
|
2179
|
+
userId: string | undefined,
|
|
2180
|
+
organizationId: string | undefined,
|
|
2181
|
+
): HandedAccount | undefined => {
|
|
2182
|
+
if (userId === undefined && organizationId === undefined) return undefined;
|
|
2183
|
+
if (
|
|
2184
|
+
userId === undefined ||
|
|
2185
|
+
organizationId === undefined ||
|
|
2186
|
+
!isProfileUserId(userId) ||
|
|
2187
|
+
WORKOS_USER_API_KEY_PATTERN.test(userId) ||
|
|
2188
|
+
!ORGANIZATION_ULID.test(organizationId)
|
|
2189
|
+
)
|
|
2190
|
+
throw new InvalidCommandError();
|
|
2191
|
+
return { userId, organizationId };
|
|
2192
|
+
};
|
|
2193
|
+
|
|
2037
2194
|
const isValue = (value: string | undefined): value is string =>
|
|
2038
2195
|
value !== undefined && value.length > 0 && !value.startsWith("--");
|
|
2039
2196
|
|