@cargo-ai/cli 1.0.35 → 1.0.37

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 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,GAAG,EAAY,MAAM,eAAe,CAAC;AAInD,YAAY,EAAE,GAAG,EAAE,CAAC;AAQpB,wBAAgB,SAAS,CAAC,IAAI,EAAE;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC,GAAG,GAAG,CAQN"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,GAAG,EAAY,MAAM,eAAe,CAAC;AAInD,YAAY,EAAE,GAAG,EAAE,CAAC;AAQpB,wBAAgB,SAAS,CAAC,IAAI,EAAE;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC,GAAG,GAAG,CAWN"}
package/build/api.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createRequire } from "node:module";
2
2
  import { buildApi } from "@cargo-ai/api";
3
- import { getProxyTransport } from "./proxy.js";
3
+ import { getProxyFetch } from "./proxy.js";
4
4
  const require = createRequire(import.meta.url);
5
5
  const { version } = require("../package.json");
6
6
  const ORIGIN = { name: "cli", version };
@@ -10,6 +10,9 @@ export function createApi(opts) {
10
10
  workspaceUuid: opts.workspaceUuid,
11
11
  accessToken: opts.accessToken,
12
12
  origin: ORIGIN,
13
- transport: getProxyTransport(opts.baseUrl),
13
+ // The client is `fetch`-based; supply a proxy-tunneling `fetch` (undici
14
+ // `ProxyAgent`) when proxy env vars are set, since Node's global `fetch`
15
+ // does not honor them. `undefined` when no proxy applies.
16
+ transport: { fetch: getProxyFetch(opts.baseUrl) },
14
17
  });
15
18
  }
@@ -23,7 +23,7 @@ Examples:
23
23
  $ cargo-ai login --oauth --workspace-uuid 550e8400-e29b-41d4-a716-446655440000
24
24
 
25
25
  Credentials are stored in ~/.config/cargo-ai/credentials.json.
26
- Environment variables (CARGO_API_TOKEN, CARGO_WORKSPACE_UUID, CARGO_BASE_URL) take precedence over saved credentials.`)
26
+ Environment variables (CARGO_API_TOKEN, CARGO_WORKSPACE_UUID, CARGO_BASE_URL) take precedence over saved credentials, and the nearest project .env (walking up from the current directory) fills them in when they are not already exported.`)
27
27
  .action(async (opts) => {
28
28
  await runLogin(opts);
29
29
  });
@@ -0,0 +1,4 @@
1
+ import type { Command } from "commander";
2
+ import type { Api } from "../../api.js";
3
+ export declare function registerActionSearchCommands(parent: Command, getApi: () => Api): void;
4
+ //# sourceMappingURL=action.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../../src/commands/connection/action.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AA+CxC,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CAuHN"}
@@ -0,0 +1,131 @@
1
+ import { ExitCodes, failWith, handleApiCall, outputJson, } from "../runHandler.js";
2
+ const DEFAULT_LIMIT = 20;
3
+ const DESCRIPTION_MAX_LENGTH = 300;
4
+ export function registerActionSearchCommands(parent, getApi) {
5
+ const action = parent
6
+ .command("action")
7
+ .description("Discover integration actions");
8
+ action
9
+ .command("search [query...]")
10
+ .description("Search integration actions by keyword across action slug, name, description, and integration — " +
11
+ "instead of scanning the full `integration list` payload")
12
+ .option("--category <category>", "Filter by integration category (string)")
13
+ .option("--integration <slug>", "Filter by integration slug (string)")
14
+ .option("--credits-only", "Only return credits-based (paid) actions (boolean flag)")
15
+ .option("--limit <n>", `Maximum results to return (integer, default: ${String(DEFAULT_LIMIT)})`, String(DEFAULT_LIMIT))
16
+ .addHelpText("after", `
17
+ All query terms must match somewhere (action slug/name, integration, or description).
18
+ Matches on the action slug or name rank above integration matches, which rank above
19
+ description matches. Without a query, lists actions filtered by the flags alone.
20
+
21
+ Examples:
22
+ $ cargo-ai connection action search email verify
23
+ $ cargo-ai connection action search "job change" --credits-only
24
+ $ cargo-ai connection action search enrich --integration waterfall
25
+ $ cargo-ai connection action search --category crm --limit 50`)
26
+ .action(async (queryTerms, opts) => {
27
+ const limit = parseInt(opts.limit, 10);
28
+ if (Number.isNaN(limit) === true || limit < 1) {
29
+ failWith("--limit must be a positive integer.", {
30
+ code: ExitCodes.InvalidUsage,
31
+ });
32
+ }
33
+ const api = getApi();
34
+ const { integrations } = await handleApiCall(() => api.connection.integration.list({
35
+ hasActions: true,
36
+ category: opts.category,
37
+ slug: opts.integration,
38
+ }));
39
+ const terms = queryTerms
40
+ .flatMap((term) => term.split(/\s+/))
41
+ .map((term) => term.toLowerCase())
42
+ .filter((term) => term.length > 0);
43
+ const results = [];
44
+ for (const integration of integrations) {
45
+ const actions = integration.actions;
46
+ if (actions === undefined) {
47
+ continue;
48
+ }
49
+ for (const [actionSlug, actionDef] of Object.entries(actions)) {
50
+ const costs = actionDef.credits?.costs;
51
+ if (opts.creditsOnly === true &&
52
+ (costs === undefined || costs.length === 0)) {
53
+ continue;
54
+ }
55
+ const score = scoreAction(terms, {
56
+ actionText: `${actionSlug} ${actionDef.name ?? ""}`,
57
+ integrationText: `${integration.slug} ${integration.name}`,
58
+ descriptionText: actionDef.description ?? "",
59
+ });
60
+ if (score === 0) {
61
+ continue;
62
+ }
63
+ results.push({
64
+ integrationSlug: integration.slug,
65
+ integrationName: integration.name,
66
+ category: integration.category,
67
+ actionSlug,
68
+ name: actionDef.name,
69
+ description: truncate(actionDef.description),
70
+ credits: costs?.map((cost) => mapSearchableCreditsCost(cost)),
71
+ score,
72
+ });
73
+ }
74
+ }
75
+ results.sort((a, b) => b.score - a.score || a.actionSlug.localeCompare(b.actionSlug));
76
+ outputJson({
77
+ query: terms.join(" "),
78
+ totalMatches: results.length,
79
+ results: results.slice(0, limit),
80
+ });
81
+ });
82
+ }
83
+ // Every term must match somewhere (AND semantics); the sum of the strongest
84
+ // match per term ranks the result. Action slug/name beats integration beats
85
+ // description.
86
+ function scoreAction(terms, fields) {
87
+ if (terms.length === 0) {
88
+ return 1;
89
+ }
90
+ const actionText = fields.actionText.toLowerCase();
91
+ const integrationText = fields.integrationText.toLowerCase();
92
+ const descriptionText = fields.descriptionText.toLowerCase();
93
+ let total = 0;
94
+ for (const term of terms) {
95
+ if (actionText.includes(term) === true) {
96
+ total += 3;
97
+ }
98
+ else if (integrationText.includes(term) === true) {
99
+ total += 2;
100
+ }
101
+ else if (descriptionText.includes(term) === true) {
102
+ total += 1;
103
+ }
104
+ else {
105
+ return 0;
106
+ }
107
+ }
108
+ return total;
109
+ }
110
+ function mapSearchableCreditsCost(cost) {
111
+ const mapped = {
112
+ type: cost.type,
113
+ cost: cost.cost,
114
+ };
115
+ if (cost.unit !== undefined) {
116
+ mapped.unit = cost.unit;
117
+ }
118
+ if (cost.unitsCount !== undefined) {
119
+ mapped.unitsCount = cost.unitsCount;
120
+ }
121
+ if (cost.fixedCost !== undefined) {
122
+ mapped.fixedCost = cost.fixedCost;
123
+ }
124
+ return mapped;
125
+ }
126
+ function truncate(value) {
127
+ if (value === undefined || value.length <= DESCRIPTION_MAX_LENGTH) {
128
+ return value;
129
+ }
130
+ return `${value.slice(0, DESCRIPTION_MAX_LENGTH)}…`;
131
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/connection/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAMxC,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CASN"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/connection/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAOxC,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CAUN"}
@@ -1,3 +1,4 @@
1
+ import { registerActionSearchCommands } from "./action.js";
1
2
  import { registerConnectorCommands } from "./connector.js";
2
3
  import { registerCustomIntegrationCommands } from "./customIntegration.js";
3
4
  import { registerIntegrationCommands } from "./integration.js";
@@ -8,6 +9,7 @@ export function registerConnectionCommands(parent, getApi) {
8
9
  .description("Connectors and integrations");
9
10
  registerConnectorCommands(connection, getApi);
10
11
  registerIntegrationCommands(connection, getApi);
12
+ registerActionSearchCommands(connection, getApi);
11
13
  registerNativeIntegrationCommands(connection, getApi);
12
14
  registerCustomIntegrationCommands(connection, getApi);
13
15
  }
@@ -0,0 +1,3 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerDoctorCommand(program: Command, currentVersion: string): void;
3
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgKzC,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,cAAc,EAAE,MAAM,GACrB,IAAI,CAoDN"}
@@ -0,0 +1,155 @@
1
+ import * as fs from "node:fs";
2
+ import * as os from "node:os";
3
+ import * as path from "node:path";
4
+ import { determineIfIsFetcherError } from "@cargo-ai/api";
5
+ import { createApi } from "../api.js";
6
+ import { getConfig } from "../config.js";
7
+ import { getCredentialsPath } from "../credentials.js";
8
+ import { fetchLatestVersion, isOutdated } from "../version.js";
9
+ import { ExitCodes, outputJson } from "./runHandler.js";
10
+ const SEMVER_PATTERN = /^\d+\.\d+\.\d+$/;
11
+ function getSkillsPinCandidates() {
12
+ const home = os.homedir();
13
+ const envDir = process.env["CARGO_SKILLS_DIR"];
14
+ const candidates = [];
15
+ if (envDir !== undefined && envDir.length > 0) {
16
+ candidates.push(path.join(envDir, "cargo", "cli-version"));
17
+ }
18
+ candidates.push(path.join(home, ".claude", "skills", "cargo", "cli-version"), path.join(home, ".claude", "plugins", "marketplaces", "cargo", "cargo", "cli-version"), path.join(home, ".openclaw", "skills", "cargo", "cli-version"));
19
+ return candidates;
20
+ }
21
+ function readSkillsPin() {
22
+ for (const candidate of getSkillsPinCandidates()) {
23
+ try {
24
+ const raw = fs.readFileSync(candidate, "utf8").trim();
25
+ if (SEMVER_PATTERN.test(raw)) {
26
+ return { version: raw, path: candidate };
27
+ }
28
+ }
29
+ catch {
30
+ // Missing or unreadable — try the next candidate.
31
+ }
32
+ }
33
+ return undefined;
34
+ }
35
+ function buildCliCheck(currentVersion, latestVersion) {
36
+ if (latestVersion === undefined) {
37
+ return { current: currentVersion, latest: null, upToDate: null };
38
+ }
39
+ return {
40
+ current: currentVersion,
41
+ latest: latestVersion,
42
+ upToDate: !isOutdated(currentVersion, latestVersion),
43
+ };
44
+ }
45
+ function buildSkillsPinCheck(currentVersion) {
46
+ const pin = readSkillsPin();
47
+ if (pin === undefined) {
48
+ return { found: false };
49
+ }
50
+ return {
51
+ found: true,
52
+ pinned: pin.version,
53
+ path: pin.path,
54
+ matchesCli: pin.version === currentVersion,
55
+ };
56
+ }
57
+ async function checkApi(config) {
58
+ if (config.accessToken === undefined) {
59
+ return {
60
+ check: {
61
+ ok: false,
62
+ error: {
63
+ status: "no-credentials",
64
+ message: 'Not authenticated. Run "cargo-ai login --token <token>" or "cargo-ai login --oauth".',
65
+ },
66
+ },
67
+ exitCode: ExitCodes.NotAuthenticated,
68
+ };
69
+ }
70
+ const client = createApi({
71
+ baseUrl: config.baseUrl,
72
+ accessToken: config.accessToken,
73
+ workspaceUuid: config.workspaceUuid,
74
+ });
75
+ try {
76
+ const { user } = await client.userManagement.user.getCurrent();
77
+ const { workspace } = await client.workspaceManagement.workspace.getCurrent();
78
+ return {
79
+ check: {
80
+ ok: true,
81
+ user: { uuid: user.uuid, email: user.email },
82
+ workspace: { uuid: workspace.uuid, name: workspace.name },
83
+ },
84
+ exitCode: ExitCodes.Success,
85
+ };
86
+ }
87
+ catch (error) {
88
+ const status = determineIfIsFetcherError(error)
89
+ ? (error.status ?? 0)
90
+ : 0;
91
+ let exitCode;
92
+ if (status === 401) {
93
+ exitCode = ExitCodes.NotAuthenticated;
94
+ }
95
+ else if (status === 403) {
96
+ exitCode = ExitCodes.PermissionDenied;
97
+ }
98
+ else {
99
+ exitCode = ExitCodes.GenericError;
100
+ }
101
+ return {
102
+ check: {
103
+ ok: false,
104
+ error: {
105
+ status,
106
+ message: error instanceof Error ? error.message : String(error),
107
+ },
108
+ },
109
+ exitCode,
110
+ };
111
+ }
112
+ }
113
+ export function registerDoctorCommand(program, currentVersion) {
114
+ program
115
+ .command("doctor")
116
+ .description("Diagnose the CLI setup: version vs latest and the skills-bundle pin, credentials, and API reachability")
117
+ .addHelpText("after", `
118
+ Runs every check and reports all results as one JSON object, then exits with the
119
+ most severe failure:
120
+
121
+ 0 healthy (an outdated CLI or a pin mismatch is reported but never fails the check)
122
+ 1 API unreachable or returned an unexpected error
123
+ 3 not authenticated (no credentials, or the API rejected them)
124
+ 4 permission denied for the configured workspace
125
+
126
+ Scripts and agents should branch on the exit code and read the JSON for details.
127
+
128
+ Examples:
129
+ $ cargo-ai doctor
130
+ $ cargo-ai doctor || echo "exit: $?"`)
131
+ .action(async () => {
132
+ let latestVersion;
133
+ try {
134
+ latestVersion = await fetchLatestVersion();
135
+ }
136
+ catch {
137
+ latestVersion = undefined;
138
+ }
139
+ const cli = buildCliCheck(currentVersion, latestVersion);
140
+ const skillsPin = buildSkillsPinCheck(currentVersion);
141
+ const config = getConfig();
142
+ const credentials = {
143
+ source: config.source,
144
+ baseUrl: config.baseUrl,
145
+ workspaceUuid: config.workspaceUuid !== undefined ? config.workspaceUuid : null,
146
+ credentialsFile: getCredentialsPath(),
147
+ };
148
+ const { check: api, exitCode } = await checkApi(config);
149
+ outputJson({
150
+ ok: exitCode === ExitCodes.Success,
151
+ checks: { cli, skillsPin, credentials, api },
152
+ });
153
+ process.exit(exitCode);
154
+ });
155
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../../src/commands/orchestration/action.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AASxC,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CA8JN"}
1
+ {"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../../src/commands/orchestration/action.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAaxC,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CA+KN"}
@@ -1,4 +1,4 @@
1
- import { handleApiCall, outputJson, parseJson, pollBatchUntilFinished, pollRunUntilFinished, } from "../runHandler.js";
1
+ import { applyRecordsLimit, ExitCodes, failWith, handleApiCall, outputJson, parseJson, parsePositiveInt, pollBatchUntilFinished, pollRunUntilFinished, } from "../runHandler.js";
2
2
  export function registerActionCommands(parent, getApi) {
3
3
  const action = parent
4
4
  .command("action")
@@ -37,15 +37,26 @@ Examples:
37
37
  .requiredOption("--records <json>", 'Records to process (JSON array, required). Example: \'[{"email":"a@b.com"},{"email":"c@d.com"}]\'')
38
38
  .option("--webhook-url <url>", "URL to call when the batch completes")
39
39
  .option("--webhook-secret <secret>", "Secret used to sign webhook deliveries")
40
+ .option("--limit <n>", "Pilot: only submit the first N records (integer). Inspect the pilot's output before re-running on the full set — credits-based actions bill per record.")
40
41
  .option("--wait-until-finished", "Poll the batch until it reaches a terminal status before returning (boolean flag)")
41
42
  .option("--polling-interval <ms>", "Polling interval in milliseconds, used with --wait-until-finished (integer, default: 5000)", "5000")
42
43
  .addHelpText("after", `
43
44
  Examples:
44
45
  $ cargo-ai orchestration action execute-batch --action '{"kind":"tool","toolUuid":"550e8400-...","config":{}}' --records '[{"email":"a@b.com"},{"email":"c@d.com"}]'
45
- $ cargo-ai orchestration action execute-batch --action '{"kind":"connector","integrationSlug":"slack","actionSlug":"send-message","config":{}}' --records '[{"channel":"#general"}]' --wait-until-finished`)
46
+ $ cargo-ai orchestration action execute-batch --action '{"kind":"connector","integrationSlug":"slack","actionSlug":"send-message","config":{}}' --records '[{"channel":"#general"}]' --wait-until-finished
47
+ $ cargo-ai orchestration action execute-batch --action '{"kind":"connector","integrationSlug":"waterfall","actionSlug":"findEmail","config":{}}' --records "$(cat records.json)" --limit 1 --wait-until-finished`)
46
48
  .action(async (opts) => {
47
49
  const actionPayload = parseJson(opts.action, "--action");
48
- const records = parseJson(opts.records, "--records");
50
+ let records = parseJson(opts.records, "--records");
51
+ if (opts.limit !== undefined) {
52
+ const limit = parsePositiveInt(opts.limit, "--limit");
53
+ if (Array.isArray(records) === false) {
54
+ failWith("--limit requires --records to be a JSON array.", {
55
+ code: ExitCodes.InvalidUsage,
56
+ });
57
+ }
58
+ records = applyRecordsLimit(records, limit).records;
59
+ }
49
60
  const api = getApi();
50
61
  const result = await handleApiCall(() => api.orchestration.action.executeBatch({
51
62
  action: actionPayload,
@@ -1 +1 @@
1
- {"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../../../src/commands/orchestration/batch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAexC,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CA2QN"}
1
+ {"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../../../src/commands/orchestration/batch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAexC,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CAgRN"}
@@ -64,7 +64,7 @@ export function registerBatchCommands(parent, getApi) {
64
64
  .description("Create a batch. Pass --file to test-run a Workflow SDK module (compiled and " +
65
65
  "run as custom nodes, with @cargo-ai/cdk handles resolved from cargo.state.json — no deploy).")
66
66
  .option("--workflow-uuid <uuid>", "Workflow UUID (string)")
67
- .requiredOption("--data <json>", 'Batch data source (JSON object, required). Supported kinds: {"kind":"segment","segmentUuid":"..."} or {"kind":"file","s3Filename":"..."}')
67
+ .requiredOption("--data <json>", 'Batch data source (JSON object, required). Kinds: {"kind":"segment","segmentUuid"}, {"kind":"file","s3Filename","mappings?"}, {"kind":"filter","modelUuid","filter?","sort?","limit?"}, {"kind":"recordIds","modelUuid","ids"}, {"kind":"records","records"}, {"kind":"change","changeUuid","changeKinds"}, {"kind":"runs","filter","reset"}')
68
68
  .option("--release-uuid <uuid>", "Release UUID to pin the batch to (string)")
69
69
  .option("--file <path>", "Path to a Workflow SDK module (its default export must be the compiled workflow returned by defineWorkflow()). Compiles it, resolves any @cargo-ai/cdk resource handles to real uuids from cargo.state.json, and runs the resulting nodes. Rejected with --nodes.")
70
70
  .option("--nodes <json>", "Custom nodes to override the workflow definition (JSON array). Rejected with --file.")
@@ -93,11 +93,12 @@ Examples:
93
93
  nodes = parseJson(opts.nodes, "--nodes");
94
94
  }
95
95
  const api = getApi();
96
+ const data = parseJson(opts.data, "--data");
96
97
  const result = await handleApiCall(() => api.orchestration.batch.create({
97
98
  workflowUuid: opts.workflowUuid,
98
99
  releaseUuid: opts.releaseUuid,
99
100
  nodes,
100
- data: parseJson(opts.data, "--data"),
101
+ data,
101
102
  }));
102
103
  if (opts.waitUntilFinished === true) {
103
104
  const intervalMs = parseInt(opts.pollingInterval, 10);
@@ -31,6 +31,12 @@ export type Spinner = {
31
31
  };
32
32
  export declare function startSpinner(message: string): Spinner;
33
33
  export declare function parseJson(value: string, optionName: string): any;
34
+ export declare function parsePositiveInt(value: string, optionName: string): number;
35
+ export declare function applyRecordsLimit<T>(records: T[], limit: number): {
36
+ records: T[];
37
+ wasTruncated: boolean;
38
+ total: number;
39
+ };
34
40
  type HandleApiCallOpts = {
35
41
  spinner?: string | false;
36
42
  };
@@ -1 +1 @@
1
- {"version":3,"file":"runHandler.d.ts","sourceRoot":"","sources":["../../src/commands/runHandler.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,SAAS;;;;;;;CAOZ,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAclE,eAAO,MAAM,MAAM;aACR,MAAM,KAAG,MAAM;eACb,MAAM,KAAG,MAAM;gBACd,MAAM,KAAG,MAAM;cACjB,MAAM,KAAG,MAAM;aAChB,MAAM,KAAG,MAAM;cACd,MAAM,KAAG,MAAM;CAC1B,CAAC;AAEF,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAM/C;AAED,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE7C;AAID,wBAAsB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUhE;AAED,KAAK,YAAY,GAAG;IAClB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC,CAAC;AAEF,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,KAAK,CAyBpE;AAKD,MAAM,MAAM,OAAO,GAAG;IAEpB,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAGlC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AAEF,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CA6CrD;AAGD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,GAAG,CAQhE;AAKD,KAAK,iBAAiB,GAAG;IACvB,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC1B,CAAC;AAEF,wBAAsB,aAAa,CAAC,CAAC,EACnC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,IAAI,CAAC,EAAE,iBAAiB,GACvB,OAAO,CAAC,CAAC,CAAC,CAiDZ;AAmFD,wBAAsB,oBAAoB,CAAC,CAAC,EAC1C,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,EAChC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,CAAC,CAAC,CASZ;AAED,wBAAsB,sBAAsB,CAAC,CAAC,EAC5C,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,EAChC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,CAAC,CAAC,CASZ;AAED,wBAAsB,wBAAwB,CAAC,CAAC,EAC9C,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,aAAa,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,EACvD,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,CAAC,CAAC,CAWZ"}
1
+ {"version":3,"file":"runHandler.d.ts","sourceRoot":"","sources":["../../src/commands/runHandler.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,SAAS;;;;;;;CAOZ,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAclE,eAAO,MAAM,MAAM;aACR,MAAM,KAAG,MAAM;eACb,MAAM,KAAG,MAAM;gBACd,MAAM,KAAG,MAAM;cACjB,MAAM,KAAG,MAAM;aAChB,MAAM,KAAG,MAAM;cACd,MAAM,KAAG,MAAM;CAC1B,CAAC;AAEF,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAM/C;AAED,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE7C;AAID,wBAAsB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUhE;AAED,KAAK,YAAY,GAAG;IAClB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC,CAAC;AAEF,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,KAAK,CAyBpE;AAKD,MAAM,MAAM,OAAO,GAAG;IAEpB,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAGlC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AAEF,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CA6CrD;AAGD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,GAAG,CAQhE;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAQ1E;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EACjC,OAAO,EAAE,CAAC,EAAE,EACZ,KAAK,EAAE,MAAM,GACZ;IAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IAAC,YAAY,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CASxD;AAKD,KAAK,iBAAiB,GAAG;IACvB,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC1B,CAAC;AAEF,wBAAsB,aAAa,CAAC,CAAC,EACnC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,IAAI,CAAC,EAAE,iBAAiB,GACvB,OAAO,CAAC,CAAC,CAAC,CAiDZ;AAmFD,wBAAsB,oBAAoB,CAAC,CAAC,EAC1C,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,EAChC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,CAAC,CAAC,CASZ;AAED,wBAAsB,sBAAsB,CAAC,CAAC,EAC5C,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,EAChC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,CAAC,CAAC,CASZ;AAED,wBAAsB,wBAAwB,CAAC,CAAC,EAC9C,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,aAAa,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,EACvD,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,CAAC,CAAC,CAWZ"}
@@ -131,6 +131,23 @@ export function parseJson(value, optionName) {
131
131
  });
132
132
  }
133
133
  }
134
+ export function parsePositiveInt(value, optionName) {
135
+ const n = parseInt(value, 10);
136
+ if (Number.isNaN(n) === true || n < 1) {
137
+ failWith(`${optionName} must be a positive integer.`, {
138
+ code: ExitCodes.InvalidUsage,
139
+ });
140
+ }
141
+ return n;
142
+ }
143
+ export function applyRecordsLimit(records, limit) {
144
+ const total = records.length;
145
+ if (limit < total) {
146
+ info(`Piloting: submitting the first ${String(limit)} of ${String(total)} record(s). Re-run without --limit for the full set.`);
147
+ return { records: records.slice(0, limit), wasTruncated: true, total };
148
+ }
149
+ return { records, wasTruncated: false, total };
150
+ }
134
151
  const SPINNER_DELAY_MS = 200;
135
152
  const DEFAULT_SPINNER_MESSAGE = "Loading...";
136
153
  export async function handleApiCall(fn, opts) {
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,kBAAkB,GAAG,MAAM,CAAC;AAEvE,MAAM,MAAM,MAAM,GAAG;IACnB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,MAAM,EAAE,YAAY,CAAC;CACtB,CAAC;AAIF,wBAAgB,SAAS,IAAI,MAAM,CA4BlC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,kBAAkB,GAAG,MAAM,CAAC;AAEvE,MAAM,MAAM,MAAM,GAAG;IACnB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,MAAM,EAAE,YAAY,CAAC;CACtB,CAAC;AAEF,wBAAgB,SAAS,IAAI,MAAM,CAclC"}
package/build/config.js CHANGED
@@ -1,47 +1,15 @@
1
+ import { loadProjectEnv, resolveAuthConfig } from "@cargo-ai/cdk/cli";
1
2
  import { loadCredentials } from "./credentials.js";
2
- const DEFAULT_BASE_URL = "https://api.getcargo.io";
3
3
  export function getConfig() {
4
+ // Fold project `.env` into the environment first (never overriding explicit
5
+ // exports): a repo pinned to one workspace must win over a personal login.
6
+ loadProjectEnv();
4
7
  const credentials = loadCredentials();
5
- const envToken = process.env["CARGO_API_TOKEN"];
6
- let accessToken;
7
- let source;
8
- if (envToken !== undefined) {
9
- accessToken = envToken;
10
- source = "environment";
11
- }
12
- else if (credentials !== undefined &&
13
- credentials.accessToken !== undefined) {
14
- accessToken = credentials.accessToken;
15
- source = "credentials-file";
16
- }
17
- else {
18
- accessToken = undefined;
19
- source = "none";
20
- }
8
+ const resolved = resolveAuthConfig(process.env, credentials);
21
9
  return {
22
- accessToken,
23
- baseUrl: getBaseUrl(credentials),
24
- workspaceUuid: getWorkspaceUuid(credentials),
25
- source,
10
+ accessToken: resolved.accessToken,
11
+ baseUrl: resolved.baseUrl,
12
+ workspaceUuid: resolved.workspaceUuid,
13
+ source: resolved.tokenSource,
26
14
  };
27
15
  }
28
- const getBaseUrl = (credentials) => {
29
- const envUrl = process.env["CARGO_BASE_URL"];
30
- if (envUrl !== undefined) {
31
- return envUrl;
32
- }
33
- if (credentials !== undefined && credentials.baseUrl !== undefined) {
34
- return credentials.baseUrl;
35
- }
36
- return DEFAULT_BASE_URL;
37
- };
38
- const getWorkspaceUuid = (credentials) => {
39
- const envUuid = process.env["CARGO_WORKSPACE_UUID"];
40
- if (envUuid !== undefined) {
41
- return envUuid;
42
- }
43
- if (credentials !== undefined) {
44
- return credentials.workspaceUuid;
45
- }
46
- return undefined;
47
- };
package/build/index.js CHANGED
@@ -9,6 +9,7 @@ import { registerBillingCommands } from "./commands/billing/index.js";
9
9
  import { registerConnectionCommands } from "./commands/connection/index.js";
10
10
  import { registerContentCommands } from "./commands/content/index.js";
11
11
  import { registerContextCommands } from "./commands/context/index.js";
12
+ import { registerDoctorCommand } from "./commands/doctor.js";
12
13
  import { registerExpressionCommands } from "./commands/expression/index.js";
13
14
  import { registerHostingCommands } from "./commands/hosting/index.js";
14
15
  import { registerInitCommand } from "./commands/init.js";
@@ -59,6 +60,7 @@ const getApi = () => {
59
60
  };
60
61
  registerAuthCommands(program, getApi);
61
62
  registerVersionCommand(program, version);
63
+ registerDoctorCommand(program, version);
62
64
  registerInitCommand(program, getApi);
63
65
  registerOrchestrationCommands(program, getApi);
64
66
  registerWorkspaceManagementCommands(program, getApi);
package/build/proxy.d.ts CHANGED
@@ -1,22 +1,7 @@
1
- import type { ClientTransport } from "@cargo-ai/api";
2
- /**
3
- * Build Axios transport overrides that tunnel requests through an
4
- * HTTP/HTTPS proxy when one is configured via the standard proxy env
5
- * vars (`HTTPS_PROXY`, `HTTP_PROXY`, `ALL_PROXY`, honoring `NO_PROXY`).
6
- *
7
- * This works around Axios' unreliable built-in proxy handling, which can
8
- * fall into a 308 redirect loop (`ERR_FR_TOO_MANY_REDIRECTS`) for HTTPS
9
- * targets inside proxied environments such as cloud agent sandboxes. We
10
- * disable Axios' env-based proxy (`proxy: false`) and tunnel via the
11
- * dedicated proxy agents instead.
12
- *
13
- * Returns `undefined` when no proxy applies, so the client keeps its
14
- * default direct-egress behavior.
15
- */
16
- export declare const getProxyTransport: (targetUrl: string) => ClientTransport | undefined;
17
1
  /**
18
2
  * Build a `fetch` implementation that tunnels through an HTTP/HTTPS proxy
19
- * when one is configured via the same env vars as {@link getProxyTransport}.
3
+ * when one is configured via the standard proxy env vars (`HTTPS_PROXY`,
4
+ * `HTTP_PROXY`, `ALL_PROXY`, honoring `NO_PROXY`).
20
5
  *
21
6
  * Node's built-in `fetch` (and therefore MCP's `StreamableHTTPClientTransport`)
22
7
  * does not honor `HTTPS_PROXY` / `HTTP_PROXY` on its own. Callers that need
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAmErD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,cACjB,MAAM,KAChB,eAAe,GAAG,SAWpB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,cACb,MAAM,YAER,MAAM,GAAG,GAAG,SAAS,WAAW,KAAK,QAAQ,QAAQ,CAAC,aAchE,CAAC"}
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAgEA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,cACb,MAAM,YAER,MAAM,GAAG,GAAG,SAAS,WAAW,KAAK,QAAQ,QAAQ,CAAC,aAchE,CAAC"}
package/build/proxy.js CHANGED
@@ -1,5 +1,3 @@
1
- import { HttpProxyAgent } from "http-proxy-agent";
2
- import { HttpsProxyAgent } from "https-proxy-agent";
3
1
  import { fetch as undiciFetch, ProxyAgent, } from "undici";
4
2
  const getEnv = (...names) => {
5
3
  for (const name of names) {
@@ -48,34 +46,10 @@ const resolveProxyUrl = (targetUrl) => {
48
46
  ? getEnv("HTTPS_PROXY", "https_proxy", "ALL_PROXY", "all_proxy")
49
47
  : getEnv("HTTP_PROXY", "http_proxy", "ALL_PROXY", "all_proxy");
50
48
  };
51
- /**
52
- * Build Axios transport overrides that tunnel requests through an
53
- * HTTP/HTTPS proxy when one is configured via the standard proxy env
54
- * vars (`HTTPS_PROXY`, `HTTP_PROXY`, `ALL_PROXY`, honoring `NO_PROXY`).
55
- *
56
- * This works around Axios' unreliable built-in proxy handling, which can
57
- * fall into a 308 redirect loop (`ERR_FR_TOO_MANY_REDIRECTS`) for HTTPS
58
- * targets inside proxied environments such as cloud agent sandboxes. We
59
- * disable Axios' env-based proxy (`proxy: false`) and tunnel via the
60
- * dedicated proxy agents instead.
61
- *
62
- * Returns `undefined` when no proxy applies, so the client keeps its
63
- * default direct-egress behavior.
64
- */
65
- export const getProxyTransport = (targetUrl) => {
66
- const proxyUrl = resolveProxyUrl(targetUrl);
67
- if (proxyUrl === undefined) {
68
- return undefined;
69
- }
70
- return {
71
- httpAgent: new HttpProxyAgent(proxyUrl),
72
- httpsAgent: new HttpsProxyAgent(proxyUrl),
73
- proxy: false,
74
- };
75
- };
76
49
  /**
77
50
  * Build a `fetch` implementation that tunnels through an HTTP/HTTPS proxy
78
- * when one is configured via the same env vars as {@link getProxyTransport}.
51
+ * when one is configured via the standard proxy env vars (`HTTPS_PROXY`,
52
+ * `HTTP_PROXY`, `ALL_PROXY`, honoring `NO_PROXY`).
79
53
  *
80
54
  * Node's built-in `fetch` (and therefore MCP's `StreamableHTTPClientTransport`)
81
55
  * does not honor `HTTPS_PROXY` / `HTTP_PROXY` on its own. Callers that need
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cargo-ai/cli",
3
- "version": "1.0.35",
3
+ "version": "1.0.37",
4
4
  "private": false,
5
5
  "license": "UNLICENSED",
6
6
  "description": "Command-line interface for the Cargo API",
@@ -30,17 +30,15 @@
30
30
  "format:check": "prettier --check ."
31
31
  },
32
32
  "dependencies": {
33
- "@cargo-ai/api": "^1.0.42",
33
+ "@cargo-ai/api": "^1.0.47",
34
34
  "@cargo-ai/app-sdk": "^1.0.5",
35
35
  "@cargo-ai/cdk": "*",
36
36
  "@cargo-ai/types": "*",
37
- "@cargo-ai/worker-sdk": "^1.0.6",
37
+ "@cargo-ai/worker-sdk": "^1.0.10",
38
38
  "@modelcontextprotocol/sdk": "1.29.0",
39
39
  "commander": "^12.1.0",
40
- "http-proxy-agent": "^9.1.0",
41
- "https-proxy-agent": "^9.1.0",
42
40
  "tsx": "^4.19.2",
43
- "undici": "^7.24.8"
41
+ "undici": "^7.28.0"
44
42
  },
45
43
  "devDependencies": {
46
44
  "@cargo-ai/eslint-config": "*",