@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;AAazD,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;AAUF,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,CAkG/B;AAED,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,SAAS,mBAAmB,CAAC,SAAS,EAAE,EACpD,IAAI,EAAE,MAAM,GACX,iBAAiB,GAAG,SAAS,CAY/B"}
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.119",
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.98",
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.98",
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",