@cargo-ai/cli 1.0.72 → 1.0.74

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.
Files changed (100) hide show
  1. package/README.md +21 -0
  2. package/build/commands/ai/agent.js +2 -2
  3. package/build/commands/ai/chat.js +1 -1
  4. package/build/commands/ai/document.js +1 -1
  5. package/build/commands/ai/memory.js +3 -3
  6. package/build/commands/ai/message.js +2 -2
  7. package/build/commands/ai/release.d.ts.map +1 -1
  8. package/build/commands/ai/release.js +3 -3
  9. package/build/commands/ai/vote.d.ts.map +1 -1
  10. package/build/commands/ai/vote.js +1 -1
  11. package/build/commands/auth/email.d.ts +24 -0
  12. package/build/commands/auth/email.d.ts.map +1 -1
  13. package/build/commands/auth/email.js +27 -14
  14. package/build/commands/auth/index.d.ts.map +1 -1
  15. package/build/commands/auth/index.js +9 -3
  16. package/build/commands/auth/workspace.d.ts.map +1 -1
  17. package/build/commands/auth/workspace.js +99 -26
  18. package/build/commands/billing/subscription.d.ts.map +1 -1
  19. package/build/commands/billing/subscription.js +3 -3
  20. package/build/commands/billing/usage.d.ts.map +1 -1
  21. package/build/commands/billing/usage.js +1 -1
  22. package/build/commands/connection/action.d.ts.map +1 -1
  23. package/build/commands/connection/action.js +1 -1
  24. package/build/commands/connection/connector.d.ts.map +1 -1
  25. package/build/commands/connection/connector.js +145 -22
  26. package/build/commands/connection/integration.d.ts.map +1 -1
  27. package/build/commands/connection/integration.js +1 -1
  28. package/build/commands/content/library.js +1 -1
  29. package/build/commands/context/runtime.js +1 -1
  30. package/build/commands/expression/recipe.d.ts.map +1 -1
  31. package/build/commands/expression/recipe.js +9 -9
  32. package/build/commands/mailboxManagement/event.js +1 -1
  33. package/build/commands/mailboxManagement/mailbox.d.ts.map +1 -1
  34. package/build/commands/mailboxManagement/mailbox.js +3 -3
  35. package/build/commands/mailboxManagement/message.js +1 -1
  36. package/build/commands/mailboxManagement/suppression.js +1 -1
  37. package/build/commands/mailboxManagement/thread.js +1 -1
  38. package/build/commands/observability/alert.js +2 -2
  39. package/build/commands/orchestration/action.d.ts.map +1 -1
  40. package/build/commands/orchestration/action.js +18 -63
  41. package/build/commands/orchestration/batch.js +7 -7
  42. package/build/commands/orchestration/node.js +2 -2
  43. package/build/commands/orchestration/play.d.ts.map +1 -1
  44. package/build/commands/orchestration/play.js +9 -9
  45. package/build/commands/orchestration/record.d.ts.map +1 -1
  46. package/build/commands/orchestration/record.js +10 -10
  47. package/build/commands/orchestration/release.js +1 -1
  48. package/build/commands/orchestration/run.d.ts.map +1 -1
  49. package/build/commands/orchestration/run.js +14 -14
  50. package/build/commands/orchestration/span.d.ts.map +1 -1
  51. package/build/commands/orchestration/span.js +4 -4
  52. package/build/commands/orchestration/tool.js +2 -2
  53. package/build/commands/orchestration/trace.d.ts.map +1 -1
  54. package/build/commands/orchestration/trace.js +2 -2
  55. package/build/commands/revenueOrganization/capacity.d.ts.map +1 -1
  56. package/build/commands/revenueOrganization/capacity.js +2 -2
  57. package/build/commands/revenueOrganization/territory.js +2 -2
  58. package/build/commands/segmentation/change.d.ts.map +1 -1
  59. package/build/commands/segmentation/change.js +4 -4
  60. package/build/commands/segmentation/record.js +1 -1
  61. package/build/commands/segmentation/segment.js +2 -2
  62. package/build/commands/start/brief.d.ts +107 -0
  63. package/build/commands/start/brief.d.ts.map +1 -0
  64. package/build/commands/start/brief.js +222 -0
  65. package/build/commands/start/index.d.ts +44 -0
  66. package/build/commands/start/index.d.ts.map +1 -0
  67. package/build/commands/start/index.js +431 -0
  68. package/build/commands/start/state.d.ts +50 -0
  69. package/build/commands/start/state.d.ts.map +1 -0
  70. package/build/commands/start/state.js +101 -0
  71. package/build/commands/storage/query.js +1 -1
  72. package/build/commands/storage/record.js +2 -2
  73. package/build/commands/storage/run.js +2 -2
  74. package/build/commands/systemOfRecordIntegration/log.js +1 -1
  75. package/build/commands/systemOfRecordIntegration/systemOfRecord.js +1 -1
  76. package/build/commands/version.js +1 -1
  77. package/build/commands/workspaceManagement/folder.d.ts.map +1 -1
  78. package/build/commands/workspaceManagement/folder.js +1 -1
  79. package/build/commands/workspaceManagement/role.d.ts.map +1 -1
  80. package/build/commands/workspaceManagement/role.js +2 -2
  81. package/build/commands/workspaceManagement/session.js +1 -1
  82. package/build/commands/workspaceManagement/user.d.ts.map +1 -1
  83. package/build/commands/workspaceManagement/user.js +2 -2
  84. package/build/commands/workspaceManagement/workspaces.js +1 -1
  85. package/build/config.d.ts +1 -0
  86. package/build/config.d.ts.map +1 -1
  87. package/build/config.js +1 -0
  88. package/build/index.js +50 -6
  89. package/build/paletteLayout.d.ts +16 -0
  90. package/build/paletteLayout.d.ts.map +1 -0
  91. package/build/paletteLayout.js +131 -0
  92. package/build/setupIssues.d.ts +4 -16
  93. package/build/setupIssues.d.ts.map +1 -1
  94. package/build/setupIssues.js +3 -52
  95. package/build/utils/booleanOption.d.ts.map +1 -1
  96. package/build/utils/booleanOption.js +5 -4
  97. package/package.json +3 -3
  98. package/build/commands/orchestration/costTable.d.ts +0 -121
  99. package/build/commands/orchestration/costTable.d.ts.map +0 -1
  100. package/build/commands/orchestration/costTable.js +0 -363
@@ -0,0 +1,431 @@
1
+ // `cargo-ai start` — and what a bare `cargo-ai` opens when nobody is signed in
2
+ // yet.
3
+ //
4
+ // Open a coding agent, run the guided demo, scaffold a CDK project, explore in
5
+ // the palette, or nothing. Each is a value of `--continue`, so the whole flow
6
+ // runs headless. `onboard` survives as an alias for anything already written
7
+ // down.
8
+ //
9
+ // Three steps and no more: sign in, land in a workspace, choose where to carry
10
+ // on. Everything past that belongs to whatever you chose — `cdk init` asks its
11
+ // own questions about a project, a coding agent asks its own about the work.
12
+ // The flow writes nothing to disk except its own state.
13
+ //
14
+ // Every question is also a flag, so the whole thing runs headless for an agent
15
+ // or a docs snippet, and every step leaves a valid machine behind: cancel after
16
+ // signing in and you are signed in.
17
+ import { spawnSync } from "node:child_process";
18
+ import { askText, availableCodingAgents, cdkProjectRoot, COMPANY_CONTEXT_PATH, hasCompanyContext, installedCookbooks, isInteractive, launchBriefed, requireAnswer, selectOne, skillsInstalledFor, } from "@cargo-ai/cdk/cli";
19
+ import { AGENT_SKILLS_NEXT_STEP } from "../../agentSkills.js";
20
+ import { isSignedIn } from "../../setupIssues.js";
21
+ import { parseBooleanOption } from "../../utils/booleanOption.js";
22
+ import { signInWithEmail } from "../auth/email.js";
23
+ import { runOAuthDeviceFlow } from "../auth/oauth.js";
24
+ import { establishSession } from "../auth/session.js";
25
+ import { ExitCodes, failWith, handleApiCall, info, success, } from "../runHandler.js";
26
+ import { buildBrief, buildDemoBrief, CDK_SKILL, DEMO_SKILL, EXPLORE_PATH, formatStartNextSteps, parseDestination, ROUTER_SKILL, } from "./brief.js";
27
+ import { saveStartState } from "./state.js";
28
+ const OAUTH = "oauth";
29
+ const EMAIL = "email";
30
+ /**
31
+ * Where the agent is about to be opened. Three cases, all decided locally —
32
+ * this runs before every handoff, including from the palette, so it must not
33
+ * touch the network.
34
+ *
35
+ * Exported for tests; `go` is the only production caller.
36
+ */
37
+ export function resolveProjectContext(cwd) {
38
+ const root = cdkProjectRoot(cwd);
39
+ if (root === undefined) {
40
+ return { kind: "none" };
41
+ }
42
+ const companyContextPath = hasCompanyContext(root) === true ? COMPANY_CONTEXT_PATH : undefined;
43
+ const cookbooks = installedCookbooks(root);
44
+ if (cookbooks.length > 0) {
45
+ return { kind: "cookbook", root, companyContextPath, cookbooks };
46
+ }
47
+ return { kind: "cdk", root, companyContextPath };
48
+ }
49
+ export function registerStartCommand(program, getApi, deps) {
50
+ program
51
+ .command("start")
52
+ .alias("onboard")
53
+ .description("Open a coding agent, run the guided demo, or set up a project — signing you in first if needed")
54
+ .option("--email <email>", "Sign in with a code emailed to this address")
55
+ .option("--code <code>", "The emailed code, to finish a sign-in this command already started (`-` reads it from stdin)")
56
+ .option("--oauth [true|false]", "Sign in via browser", parseBooleanOption)
57
+ .option("--workspace-name <name>", "Workspace to use, created if it does not exist")
58
+ .option("--workspace-uuid <uuid>", "Workspace to use")
59
+ .option("--continue <where>", 'Where to continue: a coding agent ("claude", "cursor", "codex", "gemini"), "code" for a CDK project, "cli" for the palette, "demo" for the guided tour, or "none"')
60
+ .option("--directory <path>", "Directory to scaffold into, for `--continue code`. Required when there is nobody to ask; supplying it also skips the project wizard, the way `cdk init <directory>` does")
61
+ .option("--icp <description>", "Who you sell to, used to brief the guided demo")
62
+ .option("--base-url <url>", "Cargo API base URL")
63
+ .addHelpText("after", `
64
+ This is what a bare \`cargo-ai\` opens for someone who has never signed in, and
65
+ what to run any time after that to open an agent, take the tour, or start a
66
+ project. Signed in already? The sign-in and workspace steps are skipped.
67
+
68
+ Every question has a flag, so the whole flow runs unattended:
69
+ $ cargo-ai start --email you@company.com --workspace-name "Acme GTM" --continue claude
70
+
71
+ Emailed sign-in takes two runs where there is no terminal to type the code
72
+ into. The first sends the code and prints the second, which carries the same
73
+ flags so the destination is not lost:
74
+ $ cargo-ai start --email you@company.com --continue claude --code 123456
75
+
76
+ Already have an API token? \`cargo-ai login --token <token>\` is the whole setup.`)
77
+ .action(async (opts) => {
78
+ await runStart(getApi, deps, opts);
79
+ });
80
+ }
81
+ export async function runStart(getApi, deps, opts) {
82
+ // Checked before anything happens: a mistyped `--continue` is a usage
83
+ // error, and finding it out after a browser sign-in is a poor way to learn.
84
+ const supplied = opts.continue === undefined ? undefined : requireDestination(opts.continue);
85
+ // Same reasoning, one step further. Scaffolding headless needs a directory,
86
+ // and `cdk init` cannot ask for one — so without this the run signs in,
87
+ // saves its state, and *then* dies on a usage error from a child
88
+ // process, having done everything except the thing it was asked to do.
89
+ if (supplied !== undefined &&
90
+ supplied.kind === "code" &&
91
+ opts.directory === undefined &&
92
+ isInteractive() === false) {
93
+ requireAnswer({
94
+ needs: "scaffolding a project needs a directory to scaffold into",
95
+ retryCommand: "cargo-ai start --continue code --directory my-workspace",
96
+ });
97
+ }
98
+ info("");
99
+ info("Cargo — GTM infrastructure your agents can run on.");
100
+ info("");
101
+ const workspace = isSignedIn() === true ? await currentWorkspace(getApi) : await signIn(opts);
102
+ success(`Workspace: ${workspace.name}`);
103
+ const facts = {
104
+ workspace,
105
+ // Decides whether the briefs and the next-steps block tell the reader to
106
+ // go and install the skills. Shared with `ensureSkillsInstalled` so the
107
+ // two cannot disagree about a repo that carries its own copy.
108
+ skillsInstalled: skillsInstalledFor(process.cwd()),
109
+ };
110
+ const destination = supplied !== undefined ? supplied : await askDestination();
111
+ saveStartState({
112
+ version: 1,
113
+ completedAt: new Date().toISOString(),
114
+ workspaceUuid: workspace.uuid,
115
+ continued: destination.kind === "agent" ? destination.agent.bin : destination.kind,
116
+ });
117
+ await go(destination, facts, deps, opts);
118
+ }
119
+ /** Runs the chosen destination. */
120
+ async function go(destination, facts, deps, opts) {
121
+ // A handoff may install the skills on its way past. When one then fails to
122
+ // launch, the block at the bottom of this function is what the user is left
123
+ // with, and reading the facts it came in with told them to install skills
124
+ // that had just been installed.
125
+ let known = facts;
126
+ if (destination.kind === "agent") {
127
+ // Offered before the agent starts, not mentioned in its brief afterwards:
128
+ // an agent that has to install its own instructions spends its first turn
129
+ // on setup, and often just guesses at the CLI instead.
130
+ const cwd = process.cwd();
131
+ // Resolved once and used twice: the context decides which skill the launch
132
+ // loads, and what the brief tells the agent to do once it is open.
133
+ const project = resolveProjectContext(cwd);
134
+ const skill = agentSkill(project);
135
+ const launch = await launchBriefed({
136
+ agent: destination.agent,
137
+ cwd,
138
+ skill,
139
+ brief: (skillsInstalled) => buildBrief({ ...facts, skillsInstalled }, skill, project),
140
+ });
141
+ known = { ...facts, skillsInstalled: launch.skillsInstalled };
142
+ if (launch.launched === true) {
143
+ return;
144
+ }
145
+ }
146
+ if (destination.kind === "demo") {
147
+ const demo = await runDemo(facts, opts);
148
+ known = demo.facts;
149
+ if (demo.launched === true) {
150
+ return;
151
+ }
152
+ }
153
+ if (destination.kind === "code") {
154
+ scaffoldProject(deps, opts);
155
+ return;
156
+ }
157
+ if (destination.kind === "cli") {
158
+ await deps.openPalette(EXPLORE_PATH);
159
+ return;
160
+ }
161
+ info("");
162
+ info(formatStartNextSteps(known));
163
+ if (known.skillsInstalled === false) {
164
+ info("");
165
+ info(AGENT_SKILLS_NEXT_STEP);
166
+ }
167
+ }
168
+ /**
169
+ * The skill to load for a general agent handoff: `cargo-cdk` when inside a
170
+ * CDK project (the user is building infra as code), `cargo` (the router)
171
+ * everywhere else.
172
+ */
173
+ function agentSkill(project) {
174
+ return project.kind === "none" ? ROUTER_SKILL : CDK_SKILL;
175
+ }
176
+ /**
177
+ * Hand the whole project question to `cdk init`, which owns it: where the
178
+ * project goes, what it starts from, and the company questions worth asking
179
+ * once there is a repo to write the answers into.
180
+ *
181
+ * Returns only when a project was created. Anything else exits, because
182
+ * `start --continue code` is a scripted path, and reporting success over a
183
+ * project that does not exist is the one outcome nothing downstream can
184
+ * recover from.
185
+ */
186
+ function scaffoldProject(deps, opts) {
187
+ // `init` asks for a directory only when it can; headless it needs one on the
188
+ // command line, which `--directory` is here to forward.
189
+ const scaffold = spawnSync(process.execPath, [
190
+ deps.binPath,
191
+ "cdk",
192
+ "init",
193
+ ...(opts.directory === undefined ? [] : [opts.directory]),
194
+ ], { stdio: "inherit" });
195
+ if (scaffold.error !== undefined) {
196
+ failWith(`Could not run \`cdk init\`: ${scaffold.error.message}`);
197
+ }
198
+ // The child has already said what went wrong on this terminal, so this
199
+ // carries its code rather than adding a second message. A null status means
200
+ // a signal killed it, which must not read as a scaffolded project either.
201
+ if (scaffold.status !== 0) {
202
+ process.exit(scaffold.status === null ? ExitCodes.GenericError : scaffold.status);
203
+ }
204
+ }
205
+ /**
206
+ * The guided demo: find companies matching an ICP, then the people at them.
207
+ * It runs inside a coding agent rather than as a scripted CLI sequence —
208
+ * sourcing is a conversation about who you sell to, and the agent can price
209
+ * each step and stop when the answer is good enough.
210
+ *
211
+ * Returns whether one started, and the facts as they now stand: this may
212
+ * have installed the skills, which the caller's fallback has to know about.
213
+ */
214
+ async function runDemo(facts, opts) {
215
+ const agents = availableCodingAgents();
216
+ const icp = opts.icp !== undefined && opts.icp.length > 0
217
+ ? opts.icp
218
+ : isInteractive() === false
219
+ ? undefined
220
+ : blankToUndefined(await askText({
221
+ message: "Who are you trying to reach? (Enter to skip)",
222
+ placeholder: "heads of growth at Series B SaaS in Europe",
223
+ defaultValue: "",
224
+ // Enter already skips it; Escape must not instead throw away a
225
+ // sign-in and the destination that came with it.
226
+ skippable: true,
227
+ }));
228
+ const agent = agents[0];
229
+ if (agent === undefined) {
230
+ info("");
231
+ info("The demo runs inside a coding agent, and none is installed on this machine.");
232
+ info("Install one (Claude Code, Cursor, Codex, Gemini CLI) and run:");
233
+ info(" cargo-ai start --continue demo");
234
+ return { launched: false, facts };
235
+ }
236
+ const launch = await launchBriefed({
237
+ agent,
238
+ cwd: process.cwd(),
239
+ skill: DEMO_SKILL,
240
+ brief: (skillsInstalled) => buildDemoBrief({ ...facts, skillsInstalled }, icp),
241
+ });
242
+ return {
243
+ launched: launch.launched,
244
+ facts: { ...facts, skillsInstalled: launch.skillsInstalled },
245
+ };
246
+ }
247
+ async function currentWorkspace(getApi) {
248
+ const api = getApi();
249
+ const { workspace } = await handleApiCall(() => api.workspaceManagement.workspace.getCurrent());
250
+ return { uuid: workspace.uuid, name: workspace.name };
251
+ }
252
+ async function signIn(opts) {
253
+ const channel = await chooseChannel(opts);
254
+ return channel === EMAIL
255
+ ? await signInByEmail(opts)
256
+ : await signInByBrowser(opts);
257
+ }
258
+ /**
259
+ * Sign in with an emailed code, which takes two runs where there is no
260
+ * terminal to type the code into: the first sends it and prints the command
261
+ * that finishes the job — see `resumeCommand` for why that is `start` again
262
+ * rather than `login`.
263
+ */
264
+ async function signInByEmail(opts) {
265
+ const email = opts.email !== undefined && opts.email.length > 0
266
+ ? opts.email
267
+ : await askText({
268
+ message: "Your work email",
269
+ placeholder: "you@company.com",
270
+ defaultValue: "",
271
+ validate: (raw) => raw !== undefined && raw.includes("@") === true
272
+ ? undefined
273
+ : "That does not look like an email address.",
274
+ });
275
+ const result = await signInWithEmail({
276
+ email,
277
+ code: opts.code,
278
+ workspaceName: opts.workspaceName,
279
+ workspaceUuid: opts.workspaceUuid,
280
+ baseUrl: opts.baseUrl,
281
+ resumeCommand: resumeCommand(email, opts),
282
+ });
283
+ if (result.outcome === "codeSent") {
284
+ // The code is already sent, so this is a pause rather than a failure.
285
+ info(`Re-run with the code to finish: ${result.next}`);
286
+ process.exit(ExitCodes.Success);
287
+ }
288
+ success(`Signed in as ${result.email}.`);
289
+ return result.workspace;
290
+ }
291
+ async function signInByBrowser(opts) {
292
+ const workspace = await establishSession({
293
+ tokens: await runOAuthDeviceFlow(),
294
+ baseUrlOverride: opts.baseUrl,
295
+ workspaceUuid: opts.workspaceUuid,
296
+ workspaceName: opts.workspaceName,
297
+ });
298
+ success("Signed in.");
299
+ return workspace;
300
+ }
301
+ /**
302
+ * The command that finishes what this run started, for a machine with no
303
+ * terminal to type the emailed code into.
304
+ *
305
+ * It has to be `start` rather than `login`: `login --code` signs the user in
306
+ * and stops, so the destination this run was headed for is lost and re-running
307
+ * `start --email` issues a second code instead of spending the first. Every
308
+ * flag that decided where this was going is carried over.
309
+ *
310
+ * Exported for tests; `signIn` is the only production caller.
311
+ */
312
+ export function resumeCommand(email, opts) {
313
+ const carried = [
314
+ ["--email", email],
315
+ ["--continue", opts.continue],
316
+ ["--directory", opts.directory],
317
+ ["--workspace-name", opts.workspaceName],
318
+ ["--workspace-uuid", opts.workspaceUuid],
319
+ ["--icp", opts.icp],
320
+ ["--base-url", opts.baseUrl],
321
+ ];
322
+ const flags = carried
323
+ .filter((entry) => entry[1] !== undefined)
324
+ .map(([flag, value]) => `${flag} ${shellArgument(value)}`);
325
+ // `<code>` is a placeholder for the reader to replace, not a value, so it is
326
+ // not quoted — quoting would read as something to type literally.
327
+ return `cargo-ai start ${flags.join(" ")} --code <code>`;
328
+ }
329
+ /**
330
+ * `value` as one shell argument.
331
+ *
332
+ * This line is printed to be run — copied by a person or relayed by an agent —
333
+ * and every value in it came off a command line the caller controls. Wrapping
334
+ * in double quotes, as this used to, means a value carrying a quote ends the
335
+ * argument early and the rest is read as more command. Single quotes have
336
+ * exactly one escape to handle and no interpolation inside them.
337
+ *
338
+ * Left bare when there is nothing to quote, so the common case still reads as
339
+ * something you would type.
340
+ */
341
+ function shellArgument(value) {
342
+ // Not `-foo`: bare, the next `cargo-ai` would read it as a flag rather than
343
+ // as this flag's value, and the line is printed to be run.
344
+ if (/^[\w.@:/=-]+$/.test(value) === true && value.startsWith("-") === false) {
345
+ return value;
346
+ }
347
+ return `'${value.split("'").join(`'\\''`)}'`;
348
+ }
349
+ async function chooseChannel(opts) {
350
+ if (opts.email !== undefined && opts.email.length > 0) {
351
+ return EMAIL;
352
+ }
353
+ if (opts.oauth === true) {
354
+ return OAUTH;
355
+ }
356
+ if (isInteractive() === false) {
357
+ requireAnswer({
358
+ needs: "`cargo-ai start` needs to know how to sign you in",
359
+ retryCommand: "cargo-ai start --email you@company.com",
360
+ });
361
+ }
362
+ return await selectOne({
363
+ message: "How do you want to sign in?",
364
+ recommended: OAUTH,
365
+ choices: [
366
+ {
367
+ value: OAUTH,
368
+ label: "Browser sign-in",
369
+ hint: "opens a browser; nothing to copy",
370
+ },
371
+ {
372
+ value: EMAIL,
373
+ label: "Emailed code",
374
+ hint: "no browser; signs you up on first use",
375
+ },
376
+ ],
377
+ });
378
+ }
379
+ /** `--continue <where>`, or a usage error naming what it accepts. */
380
+ function requireDestination(value) {
381
+ const parsed = parseDestination(value, availableCodingAgents());
382
+ if (parsed === undefined) {
383
+ failWith(`Cannot continue in "${value}". Expected a coding agent installed on this machine, "code", "cli", "demo" or "none".`, { code: ExitCodes.InvalidUsage });
384
+ }
385
+ return parsed;
386
+ }
387
+ async function askDestination() {
388
+ const agents = availableCodingAgents();
389
+ if (isInteractive() === false) {
390
+ return { kind: "none" };
391
+ }
392
+ const chosen = await selectOne({
393
+ message: "What do you want to do?",
394
+ recommended: agents[0] === undefined ? "demo" : agents[0].bin,
395
+ choices: [
396
+ ...agents.map((agent) => ({
397
+ value: agent.bin,
398
+ label: `Open ${agent.label}`,
399
+ hint: "briefed on this workspace",
400
+ })),
401
+ {
402
+ value: "cli",
403
+ label: "Explore in the CLI",
404
+ hint: "the action catalog, in the palette",
405
+ },
406
+ {
407
+ value: "code",
408
+ label: "Set it up as code",
409
+ hint: "scaffold a CDK project with cargo-ai cdk init",
410
+ },
411
+ {
412
+ value: "demo",
413
+ label: "Show me a guided demo",
414
+ hint: "find companies, then the people, matching your ICP",
415
+ },
416
+ { value: "none", label: "Nothing for now", hint: "print the next steps" },
417
+ ],
418
+ });
419
+ const parsed = parseDestination(chosen, agents);
420
+ if (parsed === undefined) {
421
+ return { kind: "none" };
422
+ }
423
+ return parsed;
424
+ }
425
+ /** Clack returns the empty fallback for a skipped question; absent is undefined. */
426
+ function blankToUndefined(answer) {
427
+ if (answer.trim() === "") {
428
+ return undefined;
429
+ }
430
+ return answer.trim();
431
+ }
@@ -0,0 +1,50 @@
1
+ export type StartState = {
2
+ version: 1;
3
+ completedAt: string;
4
+ workspaceUuid: string;
5
+ /** Where the person chose to continue: an agent bin, or "code"/"cli"/"demo"/"none". */
6
+ continued?: string;
7
+ };
8
+ export declare function getStartStatePath(): string;
9
+ export declare function loadStartState(): StartState | undefined;
10
+ /**
11
+ * `value` as state, or undefined when it is not.
12
+ *
13
+ * Checked rather than cast, because the file is on a disk people edit and the
14
+ * cast promised a shape nothing verified. Unknown `version` reads as absent so
15
+ * a future format degrades to "never ran" — the entrance opens once more,
16
+ * which is the harmless direction.
17
+ *
18
+ * Exported for tests; `loadStartState` is the only production caller.
19
+ */
20
+ export declare function asStartState(value: unknown): StartState | undefined;
21
+ /**
22
+ * Best-effort: a machine that cannot write its config directory — a sandbox, a
23
+ * read-only home — has still just been through the flow, and failing the
24
+ * command at the end of a successful one would be the worst possible moment to
25
+ * complain.
26
+ */
27
+ export declare function saveStartState(state: StartState): boolean;
28
+ /**
29
+ * Forget that this machine has been through the flow, so the next bare
30
+ * `cargo-ai` runs it again. Signing out is the one unambiguous "start me over"
31
+ * this CLI has — someone who does it and then types `cargo-ai` is asking for
32
+ * the entrance, not for a palette of commands that all exit 3.
33
+ */
34
+ export declare function clearStartState(): boolean;
35
+ /**
36
+ * Whether a bare `cargo-ai` should run `start` rather than open the palette.
37
+ *
38
+ * Deliberately not "are you signed in" alone: the entrance greets a person
39
+ * once. After that, and for anything that is not a person at a terminal, bare
40
+ * `cargo-ai` keeps doing exactly what it did before.
41
+ *
42
+ * Exported for tests; `index.ts` is the only production caller.
43
+ */
44
+ export declare function shouldRunStart(input: {
45
+ signedIn: boolean;
46
+ interactive: boolean;
47
+ /** Whether the flow has already run on this machine. */
48
+ ranBefore: boolean;
49
+ }): boolean;
50
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/commands/start/state.ts"],"names":[],"mappings":"AAqBA,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,CAAC,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,cAAc,IAAI,UAAU,GAAG,SAAS,CAYvD;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CA0BnE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAUzD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAOzC;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,wDAAwD;IACxD,SAAS,EAAE,OAAO,CAAC;CACpB,GAAG,OAAO,CAMV"}
@@ -0,0 +1,101 @@
1
+ // What `start` remembers between runs.
2
+ //
3
+ // The file exists to answer one question — "has this machine been through the
4
+ // flow?" — because the alternative signal, "is there a credential?", is wrong
5
+ // in both directions: someone who signs out has still seen the entrance, and
6
+ // someone who has only ever run `cargo-ai login --token` in CI has not.
7
+ //
8
+ // It sits beside the credentials rather than in the repo: this is a fact about
9
+ // a person and their machine, not about a project.
10
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
11
+ import { join } from "node:path";
12
+ import { getConfigDir } from "@cargo-ai/cdk/cli";
13
+ export function getStartStatePath() {
14
+ return join(getConfigDir(), "start.json");
15
+ }
16
+ export function loadStartState() {
17
+ const path = getStartStatePath();
18
+ if (existsSync(path) === false) {
19
+ return undefined;
20
+ }
21
+ try {
22
+ return asStartState(JSON.parse(readFileSync(path, "utf-8")));
23
+ }
24
+ catch {
25
+ return undefined;
26
+ }
27
+ }
28
+ /**
29
+ * `value` as state, or undefined when it is not.
30
+ *
31
+ * Checked rather than cast, because the file is on a disk people edit and the
32
+ * cast promised a shape nothing verified. Unknown `version` reads as absent so
33
+ * a future format degrades to "never ran" — the entrance opens once more,
34
+ * which is the harmless direction.
35
+ *
36
+ * Exported for tests; `loadStartState` is the only production caller.
37
+ */
38
+ export function asStartState(value) {
39
+ if (value === null || typeof value !== "object") {
40
+ return undefined;
41
+ }
42
+ const { version, completedAt, workspaceUuid, continued } = value;
43
+ if (version !== 1 ||
44
+ typeof completedAt !== "string" ||
45
+ typeof workspaceUuid !== "string") {
46
+ return undefined;
47
+ }
48
+ return {
49
+ version: 1,
50
+ completedAt,
51
+ workspaceUuid,
52
+ continued: typeof continued === "string" ? continued : undefined,
53
+ };
54
+ }
55
+ /**
56
+ * Best-effort: a machine that cannot write its config directory — a sandbox, a
57
+ * read-only home — has still just been through the flow, and failing the
58
+ * command at the end of a successful one would be the worst possible moment to
59
+ * complain.
60
+ */
61
+ export function saveStartState(state) {
62
+ try {
63
+ mkdirSync(getConfigDir(), { recursive: true });
64
+ writeFileSync(getStartStatePath(), `${JSON.stringify(state, null, 2)}\n`, {
65
+ mode: 0o600,
66
+ });
67
+ return true;
68
+ }
69
+ catch {
70
+ return false;
71
+ }
72
+ }
73
+ /**
74
+ * Forget that this machine has been through the flow, so the next bare
75
+ * `cargo-ai` runs it again. Signing out is the one unambiguous "start me over"
76
+ * this CLI has — someone who does it and then types `cargo-ai` is asking for
77
+ * the entrance, not for a palette of commands that all exit 3.
78
+ */
79
+ export function clearStartState() {
80
+ try {
81
+ rmSync(getStartStatePath(), { force: true });
82
+ return true;
83
+ }
84
+ catch {
85
+ return false;
86
+ }
87
+ }
88
+ /**
89
+ * Whether a bare `cargo-ai` should run `start` rather than open the palette.
90
+ *
91
+ * Deliberately not "are you signed in" alone: the entrance greets a person
92
+ * once. After that, and for anything that is not a person at a terminal, bare
93
+ * `cargo-ai` keeps doing exactly what it did before.
94
+ *
95
+ * Exported for tests; `index.ts` is the only production caller.
96
+ */
97
+ export function shouldRunStart(input) {
98
+ return (input.interactive === true &&
99
+ input.signedIn === false &&
100
+ input.ranBefore === false);
101
+ }
@@ -24,7 +24,7 @@ Examples:
24
24
  .command("download")
25
25
  .description("Download the result of a SQL query against storage models as files")
26
26
  .requiredOption("--query <sql>", "SQL query string")
27
- .option("--format <format>", "Download format (csv or parquet)", "csv")
27
+ .option("--format <csv|parquet>", "Download format", "csv")
28
28
  .addHelpText("after", `
29
29
  Tables must be referenced as [datasetSlug].[modelSlug] and are rewritten
30
30
  to the underlying warehouse table under the hood. Returns signed URLs to
@@ -22,8 +22,8 @@ Example:
22
22
  .requiredOption("--model-uuid <uuid>", "Model UUID (string, required)")
23
23
  .option("--limit <n>", "Max results to return (integer)")
24
24
  .option("--offset <n>", "Number of results to skip (integer)")
25
- .option("--sort-kind <kind>", "Sort direction. Allowed values: asc, desc")
26
- .option("--sort-column-slug <slug>", "Column to sort by. Allowed values: _id, _title, _emitted_at (_emitted_at is only available on models built from ingested records)")
25
+ .option("--sort-kind <asc|desc>", "Sort direction")
26
+ .option("--sort-column-slug <_id|_title|_emitted_at>", "Column to sort by (_emitted_at is only available on models built from ingested records)")
27
27
  .addHelpText("after", `
28
28
  Examples:
29
29
  $ cargo-ai storage record list --model-uuid 550e8400-...
@@ -21,8 +21,8 @@ export function registerRunCommands(parent, getApi) {
21
21
  .command("create")
22
22
  .description("Create a storage run")
23
23
  .requiredOption("--model-uuid <uuid>", "Model UUID")
24
- .option("--is-reset [value]", "Reset the model before running", parseBooleanOption)
25
- .option("--is-force [value]", "Force the run", parseBooleanOption)
24
+ .option("--is-reset [true|false]", "Reset the model before running", parseBooleanOption)
25
+ .option("--is-force [true|false]", "Force the run", parseBooleanOption)
26
26
  .action(async (opts) => {
27
27
  const api = getApi();
28
28
  const result = await handleApiCall(() => api.storage.run.create({
@@ -4,7 +4,7 @@ export function registerLogCommands(parent, getApi) {
4
4
  log
5
5
  .command("list")
6
6
  .description("List logs")
7
- .option("--statuses <statuses>", "Statuses (comma-separated)")
7
+ .option("--statuses <success,error>", "Statuses")
8
8
  .option("--query <query>", "Search query")
9
9
  .option("--limit <n>", "Limit")
10
10
  .option("--offset <n>", "Offset")
@@ -36,7 +36,7 @@ export function registerSystemOfRecordCommands(parent, getApi) {
36
36
  sor
37
37
  .command("create")
38
38
  .description("Create a system of record")
39
- .requiredOption("--kind <kind>", "System of record kind")
39
+ .requiredOption("--kind <bigQuery|snowflake>", "System of record kind")
40
40
  .option("--config <json>", "Configuration (JSON object)")
41
41
  .action(async (opts) => {
42
42
  const api = getApi();
@@ -6,7 +6,7 @@ export function registerVersionCommand(parent, currentVersion) {
6
6
  parent
7
7
  .command("version")
8
8
  .description("Print the installed CLI version, or check npm for a newer release with --check")
9
- .option("--check [value]", "Query the npm registry and report whether a newer version is available", parseBooleanOption)
9
+ .option("--check [true|false]", "Query the npm registry and report whether a newer version is available", parseBooleanOption)
10
10
  .action(async (opts) => {
11
11
  if (opts.check !== true) {
12
12
  outputJson({ version: currentVersion });
@@ -1 +1 @@
1
- {"version":3,"file":"folder.d.ts","sourceRoot":"","sources":["../../../src/commands/workspaceManagement/folder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAGxC,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CA6FN"}
1
+ {"version":3,"file":"folder.d.ts","sourceRoot":"","sources":["../../../src/commands/workspaceManagement/folder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAGxC,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CAgGN"}
@@ -22,7 +22,7 @@ export function registerFolderCommands(parent, getApi) {
22
22
  .description("Create a folder")
23
23
  .requiredOption("--name <name>", "Folder name")
24
24
  .requiredOption("--emoji-slug <slug>", "Emoji slug")
25
- .requiredOption("--kind <kind>", "Folder kind")
25
+ .requiredOption("--kind <tool|play|agent|file|mcpServer|model|app|worker|alert|mailbox>", "Folder kind")
26
26
  .option("--parent-uuid <uuid>", "Parent folder UUID")
27
27
  .action(async (opts) => {
28
28
  const api = getApi();
@@ -1 +1 @@
1
- {"version":3,"file":"role.d.ts","sourceRoot":"","sources":["../../../src/commands/workspaceManagement/role.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAGxC,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,IAAI,CAyF7E"}
1
+ {"version":3,"file":"role.d.ts","sourceRoot":"","sources":["../../../src/commands/workspaceManagement/role.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAGxC,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,IAAI,CAgG7E"}