@cargo-ai/cli 1.0.140 → 1.0.142

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.
@@ -0,0 +1,5 @@
1
+ import type { Command } from "commander";
2
+ /** The same address the website links as its documentation. */
3
+ export declare const DOCS_URL = "https://docs.getcargo.ai";
4
+ export declare function registerDocsCommand(program: Command): void;
5
+ //# sourceMappingURL=docs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/commands/docs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,+DAA+D;AAC/D,eAAO,MAAM,QAAQ,6BAA6B,CAAC;AAMnD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAe1D"}
@@ -0,0 +1,27 @@
1
+ import { openBrowser } from "../utils/openBrowser.js";
2
+ import { colors, info, outputJson } from "./runHandler.js";
3
+ /** The same address the website links as its documentation. */
4
+ export const DOCS_URL = "https://docs.getcargo.ai";
5
+ export function registerDocsCommand(program) {
6
+ program
7
+ .command("docs")
8
+ .description("Open the Cargo documentation in your browser")
9
+ .option("--no-open", "Print the URL without launching a browser")
10
+ .addHelpText("after", `
11
+ Examples:
12
+ $ cargo-ai docs
13
+ $ cargo-ai docs --no-open`)
14
+ .action((opts) => {
15
+ runDocs(opts);
16
+ });
17
+ }
18
+ function runDocs(opts) {
19
+ const opened = opts.open === true;
20
+ info("");
21
+ info(`The Cargo docs: ${colors.cyan(DOCS_URL)}`);
22
+ info("");
23
+ if (opened === true) {
24
+ openBrowser(DOCS_URL);
25
+ }
26
+ outputJson({ ok: true, url: DOCS_URL, opened });
27
+ }
@@ -1,4 +1,4 @@
1
1
  export declare const SIGN_UP_COMMAND = "cargo-ai login --email you@company.com";
2
- export declare const SIGNED_OUT_NOTICE = "Not signed in: reading the official integrations and their actions only. Sign up with `cargo-ai login --email you@company.com` (100 free credits, no card) to run one.";
2
+ export declare const SIGNED_OUT_NOTICE = "Not signed in: reading the official integrations and their actions only. Sign up with `cargo-ai login --email you@company.com` (100 free credits for your first month; no card with a work email) to run one.";
3
3
  export declare function noteSignedOut(): void;
4
4
  //# sourceMappingURL=signedOutNotice.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"signedOutNotice.d.ts","sourceRoot":"","sources":["../../src/commands/signedOutNotice.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,eAAe,2CAA2C,CAAC;AAExE,eAAO,MAAM,iBAAiB,2KAAyJ,CAAC;AAExL,wBAAgB,aAAa,IAAI,IAAI,CAIpC"}
1
+ {"version":3,"file":"signedOutNotice.d.ts","sourceRoot":"","sources":["../../src/commands/signedOutNotice.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,eAAe,2CAA2C,CAAC;AAExE,eAAO,MAAM,iBAAiB,kNAAgM,CAAC;AAE/N,wBAAgB,aAAa,IAAI,IAAI,CAIpC"}
@@ -3,7 +3,7 @@
3
3
  import { isSignedIn } from "@cargo-ai/cdk/cli";
4
4
  import { info } from "./runHandler.js";
5
5
  export const SIGN_UP_COMMAND = "cargo-ai login --email you@company.com";
6
- export const SIGNED_OUT_NOTICE = `Not signed in: reading the official integrations and their actions only. Sign up with \`${SIGN_UP_COMMAND}\` (100 free credits, no card) to run one.`;
6
+ export const SIGNED_OUT_NOTICE = `Not signed in: reading the official integrations and their actions only. Sign up with \`${SIGN_UP_COMMAND}\` (100 free credits for your first month; no card with a work email) to run one.`;
7
7
  export function noteSignedOut() {
8
8
  if (isSignedIn() === false) {
9
9
  info(SIGNED_OUT_NOTICE);
@@ -0,0 +1,3 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerSkillsCommands(program: Command): void;
3
+ //# sourceMappingURL=skills.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/commands/skills.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsB7D"}
@@ -0,0 +1,32 @@
1
+ import { installSkillsGlobally, SKILLS_INSTALL_COMMAND, skillsInstalledFor, } from "@cargo-ai/cdk/cli";
2
+ import { failWith, info, outputJson } from "./runHandler.js";
3
+ export function registerSkillsCommands(program) {
4
+ const skills = program
5
+ .command("skills")
6
+ .description("The Cargo skills, so your coding agent knows this CLI");
7
+ skills
8
+ .command("install")
9
+ .description("Install the Cargo skills for every coding agent here")
10
+ .addHelpText("after", `
11
+ Installs the getcargohq/cargo-skills bundle for every coding agent on this
12
+ machine (Claude Code, Codex, Cursor, …). Does nothing when this machine, or the
13
+ project you are in, already has them. Running it is the consent: unlike the
14
+ offer after sign-in, it does not ask first.
15
+
16
+ Equivalent to:
17
+ $ ${SKILLS_INSTALL_COMMAND}`)
18
+ .action(() => {
19
+ runInstall();
20
+ });
21
+ }
22
+ function runInstall() {
23
+ if (skillsInstalledFor(process.cwd()) === true) {
24
+ info("The Cargo skills are already installed.");
25
+ outputJson({ ok: true, installed: true });
26
+ return;
27
+ }
28
+ if (installSkillsGlobally() === false) {
29
+ failWith(`Could not install the Cargo skills. Install them with: ${SKILLS_INSTALL_COMMAND}`);
30
+ }
31
+ outputJson({ ok: true, installed: true });
32
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/workspaceManagement/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAWxC,wBAAgB,mCAAmC,CACjD,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CAgBN"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/workspaceManagement/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAUxC,wBAAgB,mCAAmC,CACjD,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CAeN"}
@@ -3,14 +3,13 @@ import { registerFileCommands } from "./file.js";
3
3
  import { registerFolderCommands } from "./folder.js";
4
4
  import { registerReportCommands } from "./report.js";
5
5
  import { registerRoleCommands } from "./role.js";
6
- import { registerSessionCommands } from "./session.js";
7
6
  import { registerTokenCommands } from "./token.js";
8
7
  import { registerUserCommands } from "./user.js";
9
8
  import { registerWorkspacesCommands } from "./workspaces.js";
10
9
  export function registerWorkspaceManagementCommands(parent, getApi) {
11
10
  const workspaceManagement = parent
12
11
  .command("workspaceManagement")
13
- .description("Workspaces, users, tokens, environment variables, roles, folders, reports, sessions");
12
+ .description("Workspaces, users, tokens, environment variables, roles, folders, reports");
14
13
  registerWorkspacesCommands(workspaceManagement, getApi);
15
14
  registerUserCommands(workspaceManagement, getApi);
16
15
  registerTokenCommands(workspaceManagement, getApi);
@@ -19,5 +18,4 @@ export function registerWorkspaceManagementCommands(parent, getApi) {
19
18
  registerFolderCommands(workspaceManagement, getApi);
20
19
  registerFileCommands(workspaceManagement, getApi);
21
20
  registerReportCommands(workspaceManagement, getApi);
22
- registerSessionCommands(workspaceManagement, getApi);
23
21
  }
package/build/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from "node:module";
3
- import { availableCodingAgents, BRAND, canRunPalette, creditsLeftOf, declareSources, fetchStateConnected, fetchSubscription, fetchWorkspaceName, findProjectDir, formatWorkspaceSuffix, isInteractive, isUnpaidPlan, printSetupIssues, registerCommands as registerCdkCommands, runPalette, SessionExpiredError, } from "@cargo-ai/cdk/cli";
3
+ import { availableCodingAgents, BRAND, canRunPalette, creditsLeftOf, declareSources, fetchStateConnected, fetchSubscription, fetchWorkspaceName, findProjectDir, formatWorkspaceSuffix, isInteractive, isUnpaidPlan, printSetupIssues, registerCommands as registerCdkCommands, runPalette, SessionExpiredError, skillsInstalledFor, } from "@cargo-ai/cdk/cli";
4
4
  import { Command } from "commander";
5
5
  import { AGENT_SKILLS_HINT } from "./agentSkills.js";
6
6
  import { createApi } from "./api.js";
@@ -14,6 +14,7 @@ import { registerBookDemoCommand } from "./commands/bookDemo.js";
14
14
  import { registerConnectionCommands } from "./commands/connection/index.js";
15
15
  import { registerContentCommands } from "./commands/content/index.js";
16
16
  import { registerContextCommands } from "./commands/context/index.js";
17
+ import { registerDocsCommand } from "./commands/docs.js";
17
18
  import { registerDoctorCommand } from "./commands/doctor.js";
18
19
  import { registerExpressionCommands } from "./commands/expression/index.js";
19
20
  import { registerHostingCommands } from "./commands/hosting/index.js";
@@ -24,6 +25,7 @@ import { registerOrchestrationCommands } from "./commands/orchestration/index.js
24
25
  import { registerRevenueOrganizationCommands } from "./commands/revenueOrganization/index.js";
25
26
  import { ExitCodes, failWith } from "./commands/runHandler.js";
26
27
  import { registerSegmentationCommands } from "./commands/segmentation/index.js";
28
+ import { registerSkillsCommands } from "./commands/skills.js";
27
29
  import { registerStartCommand, runStart } from "./commands/start/index.js";
28
30
  import { loadStartState, shouldRunStart } from "./commands/start/state.js";
29
31
  import { registerStorageCommands } from "./commands/storage/index.js";
@@ -32,6 +34,7 @@ import { registerUserManagementCommands } from "./commands/userManagement/index.
32
34
  import { registerVersionCommand } from "./commands/version.js";
33
35
  import { registerWorkspaceManagementCommands } from "./commands/workspaceManagement/index.js";
34
36
  import { getConfig } from "./config.js";
37
+ import { removeLegacySessionHooks } from "./legacySessionHooks.js";
35
38
  import { buildPaletteLayout } from "./paletteLayout.js";
36
39
  import { collectSetupIssues, isSignedIn } from "./setupIssues.js";
37
40
  import { cachedLatestSkillsPin, cachedLatestVersion, maybeRefreshUpdateCache, } from "./updateNotifier.js";
@@ -106,6 +109,9 @@ const SETUP_HEADER_SKIP = [
106
109
  "mcp",
107
110
  "ask",
108
111
  "book-demo",
112
+ "docs",
113
+ // The header's skills line would ask for the install this command runs.
114
+ "skills",
109
115
  ];
110
116
  /**
111
117
  * Say what is wrong before the command runs rather than after it fails, and
@@ -237,6 +243,17 @@ declareSources({
237
243
  },
238
244
  ],
239
245
  });
246
+ // Before parsing, so it also runs from the legacy hook itself, which still
247
+ // calls the `workspaceManagement session upsert` command removed with it.
248
+ try {
249
+ const removal = removeLegacySessionHooks();
250
+ if (removal.outcome === "removed") {
251
+ process.stderr.write(`Removed the retired Cargo session hooks: ${removal.paths.join(", ")}.\n`);
252
+ }
253
+ }
254
+ catch {
255
+ // A cleanup that fails is retried by the next command; it never blocks this one.
256
+ }
240
257
  const argv = pinAskBooleanFlags(rewriteChatFlag(process.argv));
241
258
  const binPath = process.argv[1] === undefined ? "cargo-ai" : process.argv[1];
242
259
  // First, so it is the first row of the palette: for someone signed in, this is
@@ -248,6 +265,8 @@ registerAuthCommands(program, getApi);
248
265
  registerVersionCommand(program, version);
249
266
  registerDoctorCommand(program, version);
250
267
  registerBookDemoCommand(program);
268
+ registerDocsCommand(program);
269
+ registerSkillsCommands(program);
251
270
  registerObservabilityCommands(program, getApi);
252
271
  registerOrchestrationCommands(program, getApi, getPublicApi);
253
272
  registerWorkspaceManagementCommands(program, getApi);
@@ -321,6 +340,8 @@ async function openPalette(startPath) {
321
340
  agents,
322
341
  projectDir: root,
323
342
  cwd,
343
+ // Re-read with the rest: picking "Install skills" is what changes it.
344
+ skillsInstalled: skillsInstalledFor(cwd),
324
345
  unpaidPlan: lookups.unpaidPlan,
325
346
  // Only trusted for the project it was asked about: a command can `cd`
326
347
  // the process or create a project, and an answer about another state
@@ -0,0 +1,9 @@
1
+ export type RemoveLegacySessionHooksResult = {
2
+ outcome: "removed";
3
+ paths: string[];
4
+ } | {
5
+ outcome: "notRemoved";
6
+ reason: "noLegacyHooks" | "settingsUnreadable";
7
+ };
8
+ export declare const removeLegacySessionHooks: (homeDir?: string) => RemoveLegacySessionHooksResult;
9
+ //# sourceMappingURL=legacySessionHooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legacySessionHooks.d.ts","sourceRoot":"","sources":["../src/legacySessionHooks.ts"],"names":[],"mappings":"AAyBA,MAAM,MAAM,8BAA8B,GACtC;IAAE,OAAO,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,GACvC;IAAE,OAAO,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,eAAe,GAAG,oBAAoB,CAAA;CAAE,CAAC;AAE9E,eAAO,MAAM,wBAAwB,aAC1B,MAAM,KACd,8BAwBF,CAAC"}
@@ -0,0 +1,101 @@
1
+ import { existsSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ // What the retired standalone installer (api.getcargo.io/install.sh) put in
5
+ // ~/.claude/hooks: session hooks that uploaded each session's latest prompt and
6
+ // an AI-written summary. That standalone session-start.sh installs the pinned
7
+ // CLI at every session start, so this release reaches those machines through
8
+ // it, and removes the hooks the first time any `cargo-ai` command runs.
9
+ const LEGACY_HOOK_FILES = [
10
+ "session-start.sh",
11
+ "session-checkpoint.sh",
12
+ "session-end.sh",
13
+ ];
14
+ // Every version of those scripts opens with this, and only ours do: a file of
15
+ // the same name that another tool wrote is left alone.
16
+ const CARGO_HOOK_HEADER = "# Cargo session";
17
+ export const removeLegacySessionHooks = (homeDir = homedir()) => {
18
+ const hooksDir = join(homeDir, ".claude", "hooks");
19
+ const paths = LEGACY_HOOK_FILES.map((file) => join(hooksDir, file)).filter((path) => isCargoHook(path));
20
+ if (paths.length === 0) {
21
+ return { outcome: "notRemoved", reason: "noLegacyHooks" };
22
+ }
23
+ // Deregister first, and delete only once that worked: a hook still listed in
24
+ // settings.json but missing on disk errors at every session.
25
+ const settingsPath = join(homeDir, ".claude", "settings.json");
26
+ const isDeregistered = deregisterHooks(settingsPath, paths);
27
+ if (isDeregistered === false) {
28
+ return { outcome: "notRemoved", reason: "settingsUnreadable" };
29
+ }
30
+ paths.forEach((path) => {
31
+ unlinkSync(path);
32
+ });
33
+ return { outcome: "removed", paths };
34
+ };
35
+ function isCargoHook(path) {
36
+ if (existsSync(path) === false) {
37
+ return false;
38
+ }
39
+ return readFileSync(path, "utf8").includes(CARGO_HOOK_HEADER);
40
+ }
41
+ function deregisterHooks(settingsPath, paths) {
42
+ if (existsSync(settingsPath) === false) {
43
+ return true;
44
+ }
45
+ let settings;
46
+ try {
47
+ settings = JSON.parse(readFileSync(settingsPath, "utf8"));
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ if (isRecord(settings) === false) {
53
+ return false;
54
+ }
55
+ const hooks = settings["hooks"];
56
+ if (isRecord(hooks) === false) {
57
+ return true;
58
+ }
59
+ let isChanged = false;
60
+ const keptHooks = {};
61
+ Object.entries(hooks).forEach(([event, entries]) => {
62
+ if (Array.isArray(entries) === false) {
63
+ keptHooks[event] = entries;
64
+ return;
65
+ }
66
+ const keptEntries = entries.flatMap((entry) => {
67
+ if (isRecord(entry) === false ||
68
+ Array.isArray(entry["hooks"]) === false) {
69
+ return [entry];
70
+ }
71
+ const commands = entry["hooks"];
72
+ const keptCommands = commands.filter((command) => isRecord(command) === false ||
73
+ paths.includes(String(command["command"])) === false);
74
+ if (keptCommands.length === commands.length) {
75
+ return [entry];
76
+ }
77
+ isChanged = true;
78
+ if (keptCommands.length === 0) {
79
+ return [];
80
+ }
81
+ return [{ ...entry, hooks: keptCommands }];
82
+ });
83
+ if (keptEntries.length > 0) {
84
+ keptHooks[event] = keptEntries;
85
+ }
86
+ });
87
+ if (isChanged === false) {
88
+ return true;
89
+ }
90
+ // Through a temporary file, so an interrupted write never leaves Claude Code
91
+ // with half a settings.json.
92
+ const temporaryPath = `${settingsPath}.cargo-${String(process.pid)}`;
93
+ writeFileSync(temporaryPath, `${JSON.stringify({ ...settings, hooks: keptHooks }, null, 2)}\n`);
94
+ renameSync(temporaryPath, settingsPath);
95
+ return true;
96
+ }
97
+ function isRecord(value) {
98
+ return (typeof value === "object" &&
99
+ value !== null &&
100
+ Array.isArray(value) === false);
101
+ }
@@ -22,6 +22,11 @@ export type PaletteLayoutInput = {
22
22
  * row that fails when picked.
23
23
  */
24
24
  stateConnected?: boolean;
25
+ /**
26
+ * Whether a coding agent opened here would find the Cargo skills. True hides
27
+ * "Agent skills": a row that would only say "already installed".
28
+ */
29
+ skillsInstalled?: boolean;
25
30
  };
26
31
  export declare function buildPaletteLayout(input: PaletteLayoutInput): PaletteLayout;
27
32
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"paletteLayout.d.ts","sourceRoot":"","sources":["../src/paletteLayout.ts"],"names":[],"mappings":"AAYA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,mBAAmB,CAAC;AAgF3B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;IAC/B,mFAAmF;IACnF,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,GAAG,aAAa,CAS3E;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,kBAAkB,GAAG,SAAS,EAAE,CAmFjE"}
1
+ {"version":3,"file":"paletteLayout.d.ts","sourceRoot":"","sources":["../src/paletteLayout.ts"],"names":[],"mappings":"AAYA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,mBAAmB,CAAC;AAwH3B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;IAC/B,mFAAmF;IACnF,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,GAAG,aAAa,CAQ3E;AA2BD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,kBAAkB,GAAG,SAAS,EAAE,CAmFjE"}
@@ -37,16 +37,20 @@ const ENTRANCE = "start";
37
37
  * opens a menu of rows already on screen is a detour. `ask` is the same kind
38
38
  * of entrance — pinned as "Ask Cargo" — so drawing it again in the tree is a
39
39
  * second door to the same room. `version` is `--version`, and `doctor`
40
- * reports it anyway. `book-demo` is hidden only when it is pinned (see
41
- * `buildPaletteLayout`); otherwise it stays in the last section.
40
+ * reports it anyway. `login`, `logout`, `skills` and `book-demo` come and go
41
+ * with the session; see `hiddenRows`.
42
42
  */
43
43
  const HIDDEN = [ENTRANCE, "ask", "version"];
44
44
  /**
45
- * The sections, in reading order: everything the workspace is made of, then
46
- * the workspace as code on its own, then the machine you are sitting at —
47
- * which ends beside `/exit`, since leaving, checking your setup, and talking
48
- * to sales are the same kind of errand. What people reach for most is not
49
- * here at all; those are the pinned rows, above the first section.
45
+ * The sections, in reading order: the errands you run on your own setup —
46
+ * your account, the docs, the agent skills — then the workspace as code, then
47
+ * the command groups. What people reach for most is not here at all; those
48
+ * are the pinned rows, above the first section.
49
+ *
50
+ * The command groups come last because they are the reference shelf: each is
51
+ * a menu of its own, and nobody opening the palette starts by reading them
52
+ * all. The short rows above them would otherwise sit two screens down, beside
53
+ * `/exit`.
50
54
  *
51
55
  * Anything a release adds and nobody lists here still appears, in tree order,
52
56
  * in a final section — a new command is never invisible by omission. So a new
@@ -54,6 +58,12 @@ const HIDDEN = [ENTRANCE, "ask", "version"];
54
58
  * no entry to be reachable.
55
59
  */
56
60
  const SECTIONS = [
61
+ // Signed out, `login` and `logout` are both hidden behind the pinned Sign in,
62
+ // so `login` is only ever seen signed in, as "Switch account".
63
+ ["whoami", "login", "logout", "docs", "skills", "doctor", "book-demo"],
64
+ // The workspace as code sits on its own: it is the same resources again,
65
+ // declared in a repo rather than run from here.
66
+ ["project"],
57
67
  // Everything the workspace is: what you run, the data and connectors it runs
58
68
  // on, the knowledge it reads, and the surfaces it exposes. One group, most
59
69
  // used first — the divisions that used to be here were the CLI's own
@@ -78,20 +88,69 @@ const SECTIONS = [
78
88
  "user-management",
79
89
  "system-of-record",
80
90
  ],
81
- // The workspace as code sits on its own: it is the same resources again,
82
- // declared in a repo rather than run from here.
83
- ["project"],
84
- ["doctor", "whoami", "login", "logout", "book-demo"],
91
+ ];
92
+ /**
93
+ * What each root row reads as. Command names are written for a shell
94
+ * (`mailboxManagement`, `system-of-record`); a menu row is read by a person.
95
+ * The slash name still filters (`/ai` finds "AI"), and a command missing here
96
+ * keeps its `/name`.
97
+ */
98
+ const LABELS = [
99
+ { name: "whoami", label: "Who am I" },
100
+ { name: "login", label: "Switch account" },
101
+ { name: "logout", label: "Log out" },
102
+ { name: "docs", label: "Docs" },
103
+ { name: "skills", label: "Agent skills" },
104
+ { name: "doctor", label: "Check setup" },
105
+ { name: "book-demo", label: "Book a demo" },
106
+ { name: "project", label: "Project" },
107
+ { name: "orchestration", label: "Orchestration" },
108
+ { name: "storage", label: "Storage" },
109
+ { name: "connection", label: "Connections" },
110
+ { name: "segmentation", label: "Segmentation" },
111
+ { name: "ai", label: "AI" },
112
+ { name: "context", label: "Context" },
113
+ { name: "content", label: "Content" },
114
+ { name: "hosting", label: "Hosting" },
115
+ { name: "mcp", label: "MCP" },
116
+ { name: "mailboxManagement", label: "Mailboxes" },
117
+ { name: "workspaceManagement", label: "Workspace" },
118
+ { name: "billing", label: "Billing" },
119
+ { name: "observability", label: "Observability" },
120
+ { name: "revenue-organization", label: "Revenue organization" },
121
+ { name: "expression", label: "Expressions" },
122
+ { name: "user-management", label: "User" },
123
+ { name: "system-of-record", label: "Systems of record" },
85
124
  ];
86
125
  export function buildPaletteLayout(input) {
87
- const pinBookDemo = input.signedIn === true && input.unpaidPlan === true;
88
126
  return {
89
127
  pinned: pinnedRows(input),
90
- hide: pinBookDemo === true ? [...HIDDEN, "book-demo"] : HIDDEN,
128
+ hide: hiddenRows(input),
91
129
  sections: SECTIONS,
130
+ labels: LABELS,
92
131
  placeholder: "type to filter, or ask a question",
93
132
  };
94
133
  }
134
+ /**
135
+ * `HIDDEN`, plus the rows this session makes pointless. Signed out, there is
136
+ * nothing to log out of, and the pinned "Sign in" is the way in — it carries
137
+ * on into the rest of the setup, which a bare `login` does not. "Agent skills"
138
+ * goes once they are installed (installing is all the group does), and "Book a
139
+ * demo" is hidden here only when it is pinned.
140
+ */
141
+ function hiddenRows(input) {
142
+ const hidden = [...HIDDEN];
143
+ if (input.signedIn === false) {
144
+ hidden.push("login", "logout");
145
+ }
146
+ if (input.skillsInstalled === true) {
147
+ hidden.push("skills");
148
+ }
149
+ if (input.signedIn === true && input.unpaidPlan === true) {
150
+ hidden.push("book-demo");
151
+ }
152
+ return hidden;
153
+ }
95
154
  /**
96
155
  * The rows above the rule. Signed out there is exactly one thing worth
97
156
  * offering, and it is not a list of twenty command groups that all exit 3.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cargo-ai/cli",
3
- "version": "1.0.140",
3
+ "version": "1.0.142",
4
4
  "mcpName": "io.github.getcargohq/cargo",
5
5
  "private": false,
6
6
  "license": "UNLICENSED",
@@ -48,7 +48,7 @@
48
48
  "node": ">=22"
49
49
  },
50
50
  "volta": {
51
- "node": "22.22.2"
51
+ "node": "24.22.2"
52
52
  },
53
53
  "type": "module",
54
54
  "bin": {
@@ -74,11 +74,11 @@
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.105",
77
+ "@cargo-ai/api": "^1.0.106",
78
78
  "@cargo-ai/app-sdk": "^1.0.11",
79
- "@cargo-ai/cdk": "^1.0.133",
80
- "@cargo-ai/types": "^1.0.104",
81
- "@cargo-ai/utils": "^1.0.35",
79
+ "@cargo-ai/cdk": "^1.0.136",
80
+ "@cargo-ai/types": "^1.0.106",
81
+ "@cargo-ai/utils": "^1.0.36",
82
82
  "@cargo-ai/worker-sdk": "^1.0.21",
83
83
  "@modelcontextprotocol/sdk": "^1.32.0",
84
84
  "ai": "^7.0.133",
@@ -1,4 +0,0 @@
1
- import type { Command } from "commander";
2
- import type { Api } from "../../api.js";
3
- export declare function registerSessionCommands(parent: Command, getApi: () => Api): void;
4
- //# sourceMappingURL=session.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/commands/workspaceManagement/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAIxC,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CAkDN"}
@@ -1,32 +0,0 @@
1
- import { parseBooleanOption } from "../../utils/booleanOption.js";
2
- import { handleApiCall, outputJson } from "../runHandler.js";
3
- export function registerSessionCommands(parent, getApi) {
4
- const session = parent
5
- .command("session")
6
- .description("Claude Code session tracking");
7
- session
8
- .command("upsert")
9
- .description("Create or update a Claude Code session")
10
- .requiredOption("--session-id <sessionId>", "Claude Code session id")
11
- .requiredOption("--title <title>", "Short title for the session")
12
- .requiredOption("--summary <summary>", "Summary of what happened in the session")
13
- .option("--finished [true|false]", "Mark the session as finished now (sets finishedAt = now)", parseBooleanOption)
14
- .option("--finished-at <timestamp>", "Explicit ISO timestamp for when the session finished")
15
- .action(async (opts) => {
16
- let finishedAt;
17
- if (opts.finishedAt !== undefined) {
18
- finishedAt = opts.finishedAt;
19
- }
20
- else if (opts.finished === true) {
21
- finishedAt = new Date().toISOString();
22
- }
23
- const api = getApi();
24
- const result = await handleApiCall(() => api.workspaceManagement.session.upsert({
25
- sessionId: opts.sessionId,
26
- title: opts.title,
27
- summary: opts.summary,
28
- finishedAt,
29
- }));
30
- outputJson(result);
31
- });
32
- }