@cargo-ai/cli 1.0.119 → 1.0.120
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.
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type WorkspaceManagement } from "@cargo-ai/api";
|
|
2
|
+
import { type Api } from "../../api.js";
|
|
2
3
|
export type ResolvedWorkspace = {
|
|
3
4
|
uuid: string;
|
|
4
5
|
name: string;
|
|
@@ -15,4 +16,23 @@ export declare function resolveWorkspace(opts: {
|
|
|
15
16
|
explicitName: string | undefined;
|
|
16
17
|
}): Promise<WorkspaceResolution>;
|
|
17
18
|
export declare function findWorkspaceByName(workspaces: readonly WorkspaceManagement.Workspace[], name: string): ResolvedWorkspace | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* The workspace the sign-in Action just created, when it is the account's only
|
|
21
|
+
* one: named "Personal" and created within SIGN_IN_WORKSPACE_MAX_AGE_MS.
|
|
22
|
+
*
|
|
23
|
+
* A fresh "Personal" can also be somebody else's that this account was invited
|
|
24
|
+
* into, which `isOnlyMember` rules out.
|
|
25
|
+
*/
|
|
26
|
+
export declare function findSignInWorkspace(workspaces: readonly Pick<WorkspaceManagement.Workspace, "uuid" | "name" | "createdAt">[], now: Date): ResolvedWorkspace | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Whether the signed-in account is the workspace's only member — what tells
|
|
29
|
+
* the workspace sign-in just created for it apart from one it was invited
|
|
30
|
+
* into, which still holds whoever did the inviting.
|
|
31
|
+
*
|
|
32
|
+
* A listing that fails reads as "someone else's": renaming a colleague's
|
|
33
|
+
* workspace is a worse outcome than the second workspace this avoids.
|
|
34
|
+
*
|
|
35
|
+
* Exported for tests; `resolveWorkspace` is the only production caller.
|
|
36
|
+
*/
|
|
37
|
+
export declare function isOnlyMember(api: Api): Promise<boolean>;
|
|
18
38
|
//# sourceMappingURL=workspace.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/workspace.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/workspace.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAGzD,OAAO,EAAE,KAAK,GAAG,EAAa,MAAM,cAAc,CAAC;AAUnD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,iBAAiB,CAAC;IAC7B,mFAAmF;IACnF,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAuBF,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAwH/B;AAED,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,SAAS,mBAAmB,CAAC,SAAS,EAAE,EACpD,IAAI,EAAE,MAAM,GACX,iBAAiB,GAAG,SAAS,CAY/B;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,SAAS,IAAI,CACvB,mBAAmB,CAAC,SAAS,EAC7B,MAAM,GAAG,MAAM,GAAG,WAAW,CAC9B,EAAE,EACH,GAAG,EAAE,IAAI,GACR,iBAAiB,GAAG,SAAS,CAkB/B;AAsHD;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,CAQ7D"}
|
|
@@ -9,6 +9,17 @@ import { ExitCodes, failWith, handleApiCall, info, success, } from "../runHandle
|
|
|
9
9
|
*/
|
|
10
10
|
const CREATE = " create";
|
|
11
11
|
const DEFAULT_WORKSPACE_NAME = "My workspace";
|
|
12
|
+
/**
|
|
13
|
+
* What the sign-in Action names the workspace it creates for an account that
|
|
14
|
+
* has none. Matches PERSONAL_WORKSPACE_NAME in the backend's action route.
|
|
15
|
+
*/
|
|
16
|
+
const SIGN_IN_WORKSPACE_NAME = "Personal";
|
|
17
|
+
/**
|
|
18
|
+
* How recently that workspace must have been created to count as this
|
|
19
|
+
* sign-in's. An older "Personal" may hold work, so naming a workspace then
|
|
20
|
+
* creates a new one rather than renaming it.
|
|
21
|
+
*/
|
|
22
|
+
const SIGN_IN_WORKSPACE_MAX_AGE_MS = 10 * 60 * 1000;
|
|
12
23
|
export async function resolveWorkspace(opts) {
|
|
13
24
|
const accessToken = opts.accessToken;
|
|
14
25
|
const api = createApi({
|
|
@@ -24,6 +35,25 @@ export async function resolveWorkspace(opts) {
|
|
|
24
35
|
if (existingWorkspace !== undefined) {
|
|
25
36
|
return { workspace: existingWorkspace, wasCreated: false };
|
|
26
37
|
}
|
|
38
|
+
// A brand-new account already has the workspace sign-in created for it,
|
|
39
|
+
// and the name given here is for that one, not a second beside it.
|
|
40
|
+
const signInWorkspace = findSignInWorkspace(workspaces, new Date());
|
|
41
|
+
if (signInWorkspace !== undefined) {
|
|
42
|
+
// Reading the members and renaming both go through workspace-scoped
|
|
43
|
+
// routes, so this client carries the workspace the listing one could
|
|
44
|
+
// not.
|
|
45
|
+
const signInApi = createApi({
|
|
46
|
+
baseUrl: opts.baseUrl,
|
|
47
|
+
getAccessToken: () => Promise.resolve(accessToken),
|
|
48
|
+
workspaceUuid: signInWorkspace.uuid,
|
|
49
|
+
});
|
|
50
|
+
if ((await isOnlyMember(signInApi)) === true) {
|
|
51
|
+
return {
|
|
52
|
+
workspace: await renameWorkspace(signInApi, opts.explicitName),
|
|
53
|
+
wasCreated: false,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
27
57
|
return {
|
|
28
58
|
workspace: await createWorkspace(api, opts.explicitName),
|
|
29
59
|
wasCreated: true,
|
|
@@ -86,6 +116,27 @@ export function findWorkspaceByName(workspaces, name) {
|
|
|
86
116
|
}
|
|
87
117
|
return { uuid: matched.uuid, name: matched.name };
|
|
88
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* The workspace the sign-in Action just created, when it is the account's only
|
|
121
|
+
* one: named "Personal" and created within SIGN_IN_WORKSPACE_MAX_AGE_MS.
|
|
122
|
+
*
|
|
123
|
+
* A fresh "Personal" can also be somebody else's that this account was invited
|
|
124
|
+
* into, which `isOnlyMember` rules out.
|
|
125
|
+
*/
|
|
126
|
+
export function findSignInWorkspace(workspaces, now) {
|
|
127
|
+
const [onlyWorkspace] = workspaces;
|
|
128
|
+
if (workspaces.length !== 1 || onlyWorkspace === undefined) {
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
if (onlyWorkspace.name !== SIGN_IN_WORKSPACE_NAME) {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
const age = now.getTime() - new Date(onlyWorkspace.createdAt).getTime();
|
|
135
|
+
if (age > SIGN_IN_WORKSPACE_MAX_AGE_MS) {
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
return { uuid: onlyWorkspace.uuid, name: onlyWorkspace.name };
|
|
139
|
+
}
|
|
89
140
|
/** Pick from the workspaces you have, or name a new one, in one question. */
|
|
90
141
|
async function chooseWorkspace(api, workspaces) {
|
|
91
142
|
if (workspaces.length === 0) {
|
|
@@ -169,6 +220,29 @@ async function createWorkspace(api, name) {
|
|
|
169
220
|
const result = await handleApiCall(() => api.workspaceManagement.workspace.create({ name }), { spinner: "Creating workspace..." });
|
|
170
221
|
return { uuid: result.workspace.uuid, name: result.workspace.name };
|
|
171
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* Whether the signed-in account is the workspace's only member — what tells
|
|
225
|
+
* the workspace sign-in just created for it apart from one it was invited
|
|
226
|
+
* into, which still holds whoever did the inviting.
|
|
227
|
+
*
|
|
228
|
+
* A listing that fails reads as "someone else's": renaming a colleague's
|
|
229
|
+
* workspace is a worse outcome than the second workspace this avoids.
|
|
230
|
+
*
|
|
231
|
+
* Exported for tests; `resolveWorkspace` is the only production caller.
|
|
232
|
+
*/
|
|
233
|
+
export async function isOnlyMember(api) {
|
|
234
|
+
try {
|
|
235
|
+
const { users } = await api.workspaceManagement.user.all();
|
|
236
|
+
return users.length === 1;
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
async function renameWorkspace(api, name) {
|
|
243
|
+
const result = await handleApiCall(() => api.workspaceManagement.workspace.update({ name }), { spinner: "Naming workspace..." });
|
|
244
|
+
return { uuid: result.workspace.uuid, name: result.workspace.name };
|
|
245
|
+
}
|
|
172
246
|
async function promptWorkspaceSelection(workspaces, input) {
|
|
173
247
|
const rl = readline.createInterface({
|
|
174
248
|
input,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cargo-ai/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.120",
|
|
4
4
|
"mcpName": "io.github.getcargohq/cargo",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -74,10 +74,10 @@
|
|
|
74
74
|
"dependencies": {
|
|
75
75
|
"@ai-sdk/harness": "^1.0.144",
|
|
76
76
|
"@ai-sdk/harness-claude-code": "^1.0.148",
|
|
77
|
-
"@cargo-ai/api": "^1.0.
|
|
77
|
+
"@cargo-ai/api": "^1.0.99",
|
|
78
78
|
"@cargo-ai/app-sdk": "^1.0.11",
|
|
79
79
|
"@cargo-ai/cdk": "^1.0.116",
|
|
80
|
-
"@cargo-ai/types": "^1.0.
|
|
80
|
+
"@cargo-ai/types": "^1.0.99",
|
|
81
81
|
"@cargo-ai/utils": "^1.0.33",
|
|
82
82
|
"@cargo-ai/worker-sdk": "^1.0.21",
|
|
83
83
|
"@modelcontextprotocol/sdk": "^1.31.0",
|