rush-ai 0.6.0 → 0.7.0
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.
- package/AGENTS.md +37 -0
- package/dist/index.js +222 -43
- package/dist/index.js.map +1 -1
- package/dist/plugin-assets/SKILL.md +66 -59
- package/dist/skills/README.md +48 -0
- package/dist/skills/agent-shelf.md +102 -0
- package/dist/skills/hand-off.md +163 -0
- package/package.json +3 -1
- package/skills/README.md +48 -0
- package/skills/agent-shelf.md +102 -0
- package/skills/hand-off.md +163 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# AGENTS.md — for AI agents using rush-ai
|
|
2
|
+
|
|
3
|
+
If you are an AI agent (Cursor, Claude Code, or another IDE-resident assistant) and you landed in this package, read this file first.
|
|
4
|
+
|
|
5
|
+
## What rush-ai is for
|
|
6
|
+
|
|
7
|
+
`rush-ai` is how a local agent hands off work to the Rush platform — without asking the user to re-state anything. Two situations you'll use it in:
|
|
8
|
+
|
|
9
|
+
1. **Hand-off** — the conversation you're in produces work that belongs on Rush (a live website, a task for a specialist). Relay the context you already have. → read [`skills/hand-off.md`](./skills/hand-off.md).
|
|
10
|
+
2. **Sub-agent in your workflow** — you're composing a multi-step plan and a step needs a specialist from Rush's agent shelf. → read [`skills/agent-shelf.md`](./skills/agent-shelf.md).
|
|
11
|
+
|
|
12
|
+
## Getting usage on demand
|
|
13
|
+
|
|
14
|
+
From inside any shell (the one you already have a Bash tool for), these three commands give you everything you need:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx rush-ai skill # prints the index — start here
|
|
18
|
+
npx rush-ai skill hand-off # full hand-off playbook
|
|
19
|
+
npx rush-ai skill agent-shelf # full agent-shelf playbook
|
|
20
|
+
npx rush-ai agent list # see the live list of available agents
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Every command also supports `--help` with a "When to use" section and example flows.
|
|
24
|
+
|
|
25
|
+
## Defaults that save you a round-trip
|
|
26
|
+
|
|
27
|
+
- Recommended invocation: **`npx rush-ai`** (always latest, zero install).
|
|
28
|
+
- Default agent: **`rush`** — `-a` defaults to `rush` when omitted. Pass `-a web-builder` for site-building tasks.
|
|
29
|
+
- Always pass **`--json`** when the result will be parsed.
|
|
30
|
+
- Iterate with **`task send <id>`**, not a new `task create`.
|
|
31
|
+
|
|
32
|
+
## What NOT to do
|
|
33
|
+
|
|
34
|
+
- Don't ask the user to summarize requirements they already told you — relay them.
|
|
35
|
+
- Don't invent agent names; always confirm via `agent list`.
|
|
36
|
+
- Don't run `npx rush-ai auth login` for the user (it's interactive / opens a browser). Ask them to.
|
|
37
|
+
- Don't silently retry a failed task. Surface the error and ask what to do.
|
package/dist/index.js
CHANGED
|
@@ -161,37 +161,122 @@ function requireAuth() {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
// src/commands/agent/index.ts
|
|
164
|
+
var AGENT_HELP_AFTER = `
|
|
165
|
+
When to use:
|
|
166
|
+
Rush hosts a shelf of specialist agents \u2014 call them as sub-agents from
|
|
167
|
+
your own workflows instead of writing the prompts yourself. Always
|
|
168
|
+
discover first, then invoke.
|
|
169
|
+
|
|
170
|
+
Typical flows:
|
|
171
|
+
$ rush-ai agent list --default --json # just the built-in defaults
|
|
172
|
+
$ rush-ai agent list --search "\u4EBA\u529B" --json # fuzzy-filter by name / desc
|
|
173
|
+
$ rush-ai agent list --all --json # everything \u2014 may be long
|
|
174
|
+
$ rush-ai agent info <name> --json # inspect one agent's skills / MCP
|
|
175
|
+
|
|
176
|
+
$ rush-ai task create -a <name> -p "..." # call the agent as a sub-agent
|
|
177
|
+
$ rush-ai task status <id> --json # grab its output
|
|
178
|
+
|
|
179
|
+
Built-in default agents (see --default):
|
|
180
|
+
rush general-purpose agent
|
|
181
|
+
web-builder site / landing-page builder (returns previewUrl + gitRepoUrl)
|
|
182
|
+
skill-publisher publishes reusable skills back onto the platform
|
|
183
|
+
|
|
184
|
+
For agents: run \`rush-ai skill agent-shelf\` for the full playbook.
|
|
185
|
+
`;
|
|
164
186
|
function registerAgentCommand(program) {
|
|
165
|
-
const agent = program.command("agent").description("Manage and inspect agents");
|
|
166
|
-
agent.command("list").alias("ls").description("List available agents").
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
187
|
+
const agent = program.command("agent").description("Manage and inspect agents").addHelpText("after", AGENT_HELP_AFTER);
|
|
188
|
+
agent.command("list").alias("ls").description("List available agents").option(
|
|
189
|
+
"-l, --limit <n>",
|
|
190
|
+
"Max agents per page (1\u2013500, default 50)",
|
|
191
|
+
(v) => Number.parseInt(v, 10),
|
|
192
|
+
50
|
|
193
|
+
).option(
|
|
194
|
+
"-p, --page <n>",
|
|
195
|
+
"Page number (1-indexed, default 1)",
|
|
196
|
+
(v) => Number.parseInt(v, 10),
|
|
197
|
+
1
|
|
198
|
+
).option("-q, --search <text>", "Filter agents by name / description").option(
|
|
199
|
+
"--default",
|
|
200
|
+
"Only show built-in default agents (web-builder, rush, skill-publisher, ...)"
|
|
201
|
+
).option(
|
|
202
|
+
"--all",
|
|
203
|
+
"Fetch every page and return the full list (may issue several requests)"
|
|
204
|
+
).action(
|
|
205
|
+
async (opts) => {
|
|
206
|
+
requireAuth();
|
|
207
|
+
const format = resolveFormat(program.opts());
|
|
208
|
+
const client = createClient();
|
|
209
|
+
const baseParams = new URLSearchParams();
|
|
210
|
+
const rawLimit = Number.isFinite(opts.limit) ? opts.limit : 50;
|
|
211
|
+
const apiLimit = Math.min(Math.max(rawLimit, 1), 500);
|
|
212
|
+
const rawPage = Number.isFinite(opts.page) ? opts.page : 1;
|
|
213
|
+
const requestedPage = Math.max(rawPage, 1);
|
|
214
|
+
if (opts.search) baseParams.set("q", opts.search);
|
|
215
|
+
if (opts.default) baseParams.set("is_builtin", "true");
|
|
216
|
+
async function fetchPage(page2, limit) {
|
|
217
|
+
const params = new URLSearchParams(baseParams);
|
|
218
|
+
params.set("page", String(page2));
|
|
219
|
+
params.set("limit", String(limit));
|
|
220
|
+
const { data: data2 } = await client.get(
|
|
221
|
+
`/api/agents?${params.toString()}`
|
|
222
|
+
);
|
|
223
|
+
return data2;
|
|
224
|
+
}
|
|
225
|
+
let data;
|
|
226
|
+
if (opts.all) {
|
|
227
|
+
const first = await fetchPage(1, 500);
|
|
228
|
+
const totalPages2 = first.pagination?.totalPages ?? 1;
|
|
229
|
+
const all = [...first.agents];
|
|
230
|
+
for (let p = 2; p <= totalPages2; p++) {
|
|
231
|
+
const next = await fetchPage(p, 500);
|
|
232
|
+
all.push(...next.agents);
|
|
233
|
+
}
|
|
234
|
+
data = {
|
|
235
|
+
agents: all,
|
|
236
|
+
pagination: first.pagination ? { ...first.pagination, page: 1, limit: all.length } : {
|
|
237
|
+
total: all.length,
|
|
238
|
+
page: 1,
|
|
239
|
+
limit: all.length,
|
|
240
|
+
totalPages: 1
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
} else {
|
|
244
|
+
data = await fetchPage(requestedPage, apiLimit);
|
|
245
|
+
}
|
|
246
|
+
if (format === "json") {
|
|
247
|
+
output.log(JSON.stringify(data, null, 2));
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (data.agents.length === 0) {
|
|
251
|
+
output.info("No agents found.");
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const total = data.pagination?.total ?? data.agents.length;
|
|
255
|
+
const shown = data.agents.length;
|
|
256
|
+
const page = data.pagination?.page ?? 1;
|
|
257
|
+
const totalPages = data.pagination?.totalPages ?? 1;
|
|
258
|
+
output.log(output.bold(`Agents (showing ${shown} of ${total}):`));
|
|
259
|
+
output.newline();
|
|
260
|
+
const rows = data.agents.map((a) => ({
|
|
261
|
+
Name: a.name,
|
|
262
|
+
Description: truncate2(a.description ?? "", 50),
|
|
263
|
+
Status: a.status,
|
|
264
|
+
Skills: String(a.skills?.length ?? 0),
|
|
265
|
+
MCP: String(a.mcp_servers?.length ?? 0)
|
|
266
|
+
}));
|
|
267
|
+
output.log(
|
|
268
|
+
formatOutput(rows, format, {
|
|
269
|
+
columns: { Description: { maxWidth: 50 } }
|
|
270
|
+
})
|
|
271
|
+
);
|
|
272
|
+
if (!opts.all && shown < total) {
|
|
273
|
+
output.newline();
|
|
274
|
+
output.dim(
|
|
275
|
+
`Page ${page}/${totalPages}. Use --page <n>, --limit <n>, --search <text>, or --all to see more.`
|
|
276
|
+
);
|
|
277
|
+
}
|
|
178
278
|
}
|
|
179
|
-
|
|
180
|
-
output.log(output.bold(`Agents (${total} total):`));
|
|
181
|
-
output.newline();
|
|
182
|
-
const rows = data.agents.map((a) => ({
|
|
183
|
-
Name: a.name,
|
|
184
|
-
Description: truncate2(a.description ?? "", 50),
|
|
185
|
-
Status: a.status,
|
|
186
|
-
Skills: String(a.skills?.length ?? 0),
|
|
187
|
-
MCP: String(a.mcp_servers?.length ?? 0)
|
|
188
|
-
}));
|
|
189
|
-
output.log(
|
|
190
|
-
formatOutput(rows, format, {
|
|
191
|
-
columns: { Description: { maxWidth: 50 } }
|
|
192
|
-
})
|
|
193
|
-
);
|
|
194
|
-
});
|
|
279
|
+
);
|
|
195
280
|
agent.command("info").description("Show agent details").argument("<name>", "Agent name or ID").action(async (nameOrId) => {
|
|
196
281
|
requireAuth();
|
|
197
282
|
const format = resolveFormat(program.opts());
|
|
@@ -286,7 +371,7 @@ function getApiBaseUrl() {
|
|
|
286
371
|
async function loginViaBrowser(jsonMode) {
|
|
287
372
|
const baseUrl = getApiBaseUrl();
|
|
288
373
|
const state = randomBytes(16).toString("hex");
|
|
289
|
-
return new Promise((
|
|
374
|
+
return new Promise((resolve10, reject) => {
|
|
290
375
|
const server = createServer(async (req, res) => {
|
|
291
376
|
try {
|
|
292
377
|
const url = new URL(req.url ?? "/", "http://localhost");
|
|
@@ -382,7 +467,7 @@ async function loginViaBrowser(jsonMode) {
|
|
|
382
467
|
);
|
|
383
468
|
}
|
|
384
469
|
}
|
|
385
|
-
|
|
470
|
+
resolve10();
|
|
386
471
|
} catch (err) {
|
|
387
472
|
server.close();
|
|
388
473
|
reject(
|
|
@@ -3244,6 +3329,66 @@ function printVerifyResults(results) {
|
|
|
3244
3329
|
}
|
|
3245
3330
|
}
|
|
3246
3331
|
|
|
3332
|
+
// src/commands/skill/index.ts
|
|
3333
|
+
import { existsSync as existsSync17, readdirSync as readdirSync2, readFileSync as readFileSync10 } from "fs";
|
|
3334
|
+
import { basename as basename2, resolve as resolve8 } from "path";
|
|
3335
|
+
var SKILL_DESCRIPTION = "Print agent usage skills (hand-off, agent-shelf, ...) as raw markdown.";
|
|
3336
|
+
var SKILL_HELP_AFTER = `
|
|
3337
|
+
Examples:
|
|
3338
|
+
$ npx rush-ai skill Print the skills index
|
|
3339
|
+
$ npx rush-ai skill hand-off Print the hand-off playbook
|
|
3340
|
+
$ npx rush-ai skill agent-shelf Print the agent-shelf playbook
|
|
3341
|
+
$ npx rush-ai skill --list List available skills
|
|
3342
|
+
|
|
3343
|
+
Designed to be consumed by AI agents inside IDEs (Cursor, Claude Code,
|
|
3344
|
+
etc). Output is raw markdown on stdout \u2014 pipe it, grep it, feed it to
|
|
3345
|
+
your own context.
|
|
3346
|
+
`;
|
|
3347
|
+
function resolveSkillsDir() {
|
|
3348
|
+
const baseDir = import.meta.dirname ?? __dirname;
|
|
3349
|
+
if (!baseDir) return null;
|
|
3350
|
+
const candidates = [
|
|
3351
|
+
resolve8(baseDir, "skills"),
|
|
3352
|
+
resolve8(baseDir, "..", "skills"),
|
|
3353
|
+
resolve8(baseDir, "..", "..", "skills"),
|
|
3354
|
+
resolve8(baseDir, "..", "..", "..", "skills"),
|
|
3355
|
+
resolve8(baseDir, "..", "..", "..", "..", "skills")
|
|
3356
|
+
];
|
|
3357
|
+
for (const p of candidates) {
|
|
3358
|
+
if (existsSync17(p)) return p;
|
|
3359
|
+
}
|
|
3360
|
+
return null;
|
|
3361
|
+
}
|
|
3362
|
+
function listSkills(dir) {
|
|
3363
|
+
return readdirSync2(dir).filter((f) => f.endsWith(".md")).map((f) => basename2(f, ".md")).sort();
|
|
3364
|
+
}
|
|
3365
|
+
function registerSkillCommand(program) {
|
|
3366
|
+
program.command("skill [name]").description(SKILL_DESCRIPTION).addHelpText("after", SKILL_HELP_AFTER).option("--list", "List available skill names and exit").action((name, opts) => {
|
|
3367
|
+
const dir = resolveSkillsDir();
|
|
3368
|
+
if (!dir) {
|
|
3369
|
+
output.error(
|
|
3370
|
+
"Could not locate the skills/ directory. This is a packaging bug \u2014 please file an issue."
|
|
3371
|
+
);
|
|
3372
|
+
process.exit(2);
|
|
3373
|
+
return;
|
|
3374
|
+
}
|
|
3375
|
+
const available = listSkills(dir);
|
|
3376
|
+
if (opts.list) {
|
|
3377
|
+
for (const s of available) output.log(s);
|
|
3378
|
+
return;
|
|
3379
|
+
}
|
|
3380
|
+
const target = name ?? "README";
|
|
3381
|
+
const file = resolve8(dir, `${target}.md`);
|
|
3382
|
+
if (!existsSync17(file)) {
|
|
3383
|
+
output.error(`Unknown skill "${target}".`);
|
|
3384
|
+
output.dim(`Available: ${available.join(", ") || "(none)"}`);
|
|
3385
|
+
process.exit(1);
|
|
3386
|
+
return;
|
|
3387
|
+
}
|
|
3388
|
+
process.stdout.write(readFileSync10(file, "utf-8"));
|
|
3389
|
+
});
|
|
3390
|
+
}
|
|
3391
|
+
|
|
3247
3392
|
// src/commands/task/index.ts
|
|
3248
3393
|
import { createWriteStream } from "fs";
|
|
3249
3394
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
@@ -3285,28 +3430,28 @@ async function readStdinIfPiped() {
|
|
|
3285
3430
|
if (process.stdin.isTTY) {
|
|
3286
3431
|
return null;
|
|
3287
3432
|
}
|
|
3288
|
-
return new Promise((
|
|
3433
|
+
return new Promise((resolve10, reject) => {
|
|
3289
3434
|
const chunks = [];
|
|
3290
3435
|
process.stdin.on("data", (chunk) => {
|
|
3291
3436
|
chunks.push(chunk);
|
|
3292
3437
|
});
|
|
3293
3438
|
process.stdin.on("end", () => {
|
|
3294
|
-
|
|
3439
|
+
resolve10(Buffer.concat(chunks).toString("utf-8").trim());
|
|
3295
3440
|
});
|
|
3296
3441
|
process.stdin.on("error", reject);
|
|
3297
3442
|
});
|
|
3298
3443
|
}
|
|
3299
3444
|
|
|
3300
3445
|
// src/commands/task/deploy.ts
|
|
3301
|
-
import { resolve as
|
|
3446
|
+
import { resolve as resolve9 } from "path";
|
|
3302
3447
|
import chalk7 from "chalk";
|
|
3303
3448
|
|
|
3304
3449
|
// src/util/git.ts
|
|
3305
3450
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
3306
|
-
import { existsSync as
|
|
3451
|
+
import { existsSync as existsSync18 } from "fs";
|
|
3307
3452
|
import { join as join8 } from "path";
|
|
3308
3453
|
function isGitRepo(projectPath) {
|
|
3309
|
-
return
|
|
3454
|
+
return existsSync18(join8(projectPath, ".git"));
|
|
3310
3455
|
}
|
|
3311
3456
|
function gitInit(projectPath) {
|
|
3312
3457
|
execFileSync3("git", ["init"], { cwd: projectPath, stdio: "pipe" });
|
|
@@ -3374,7 +3519,7 @@ function registerDeploySubcommand(task, program) {
|
|
|
3374
3519
|
requireAuth();
|
|
3375
3520
|
const format = resolveFormat(program.opts());
|
|
3376
3521
|
const client = createClient();
|
|
3377
|
-
const projectPath =
|
|
3522
|
+
const projectPath = resolve9(opts.path);
|
|
3378
3523
|
if (format !== "json") {
|
|
3379
3524
|
output.info("Checking project readiness...");
|
|
3380
3525
|
}
|
|
@@ -3618,10 +3763,31 @@ function buildCategorySummary(files) {
|
|
|
3618
3763
|
}
|
|
3619
3764
|
return Object.entries(counts).map(([cat, count]) => `${count} ${cat}`).join(", ");
|
|
3620
3765
|
}
|
|
3766
|
+
var TASK_HELP_AFTER = `
|
|
3767
|
+
When to use:
|
|
3768
|
+
Call \`task create\` whenever the next unit of work belongs on the Rush
|
|
3769
|
+
platform instead of your local machine \u2014 a specialist Rush agent runs
|
|
3770
|
+
it, and you get a task id to track / iterate on.
|
|
3771
|
+
|
|
3772
|
+
Typical flows:
|
|
3773
|
+
# Hand-off from an IDE conversation \u2192 Rush agent builds, you iterate
|
|
3774
|
+
$ rush-ai task create -a web-builder -p "<prompt synthesized from context>" --json
|
|
3775
|
+
$ rush-ai task status <id> --json # includes previewUrl / gitRepoUrl
|
|
3776
|
+
$ rush-ai task send <id> -p "<follow-up>" # same task, keep iterating
|
|
3777
|
+
|
|
3778
|
+
# Quick one-shot with the default agent (\`rush\`)
|
|
3779
|
+
$ rush-ai task create -a rush -p "Summarize the latest release notes"
|
|
3780
|
+
|
|
3781
|
+
For agents: run \`rush-ai skill hand-off\` for the full playbook.
|
|
3782
|
+
`;
|
|
3621
3783
|
function registerTaskCommand(program) {
|
|
3622
|
-
const task = program.command("task").description("Create and manage tasks");
|
|
3784
|
+
const task = program.command("task").description("Create and manage tasks").addHelpText("after", TASK_HELP_AFTER);
|
|
3623
3785
|
registerDeploySubcommand(task, program);
|
|
3624
|
-
task.command("create").description("Create a task asynchronously").
|
|
3786
|
+
task.command("create").description("Create a task asynchronously").option(
|
|
3787
|
+
"-a, --agent <name>",
|
|
3788
|
+
"Agent name to execute the task (defaults to `rush`)",
|
|
3789
|
+
"rush"
|
|
3790
|
+
).option("-p, --prompt <text>", "Task prompt").option("--skills <skills>", "Comma-separated skills to add", commaSplit).option("--mcp <servers>", "Comma-separated MCP servers to add", commaSplit).action(
|
|
3625
3791
|
async (options) => {
|
|
3626
3792
|
requireAuth();
|
|
3627
3793
|
const format = resolveFormat(program.opts());
|
|
@@ -4078,6 +4244,7 @@ function registerCommands(program) {
|
|
|
4078
4244
|
registerAuthCommand(program);
|
|
4079
4245
|
registerAgentCommand(program);
|
|
4080
4246
|
registerTaskCommand(program);
|
|
4247
|
+
registerSkillCommand(program);
|
|
4081
4248
|
registerCheckCommand(program);
|
|
4082
4249
|
registerMcpCommand(program);
|
|
4083
4250
|
registerPluginCommand(program);
|
|
@@ -4149,17 +4316,29 @@ async function checkForUpdate(currentVersion) {
|
|
|
4149
4316
|
// src/index.ts
|
|
4150
4317
|
var BANNER = `
|
|
4151
4318
|
${chalk8.bold.cyan("Rush CLI")} ${chalk8.dim(`v${VERSION}`)}
|
|
4152
|
-
${chalk8.dim("
|
|
4319
|
+
${chalk8.dim("Call Rush agents from your terminal \u2014 relay the context, not the prompt.")}
|
|
4320
|
+
|
|
4321
|
+
${chalk8.dim("Use cases:")}
|
|
4322
|
+
${chalk8.dim("\xB7")} From Cursor / Claude Code, hand off a task to a Rush agent without restating context.
|
|
4323
|
+
${chalk8.dim("\xB7")} Compose workflows where a Rush specialist agent runs as your sub-agent.
|
|
4324
|
+
|
|
4325
|
+
${chalk8.dim("For agents:")} ${chalk8.cyan("rush-ai skill")} prints ready-to-consume usage playbooks.
|
|
4153
4326
|
`;
|
|
4154
4327
|
function showWelcomeGuide() {
|
|
4155
4328
|
const lines = [
|
|
4156
4329
|
"",
|
|
4157
4330
|
` ${chalk8.bold.cyan("Rush CLI")} ${chalk8.dim(`v${VERSION}`)}`,
|
|
4331
|
+
` ${chalk8.dim("Call Rush agents from your terminal \u2014 relay the context, not the prompt.")}`,
|
|
4158
4332
|
"",
|
|
4159
4333
|
chalk8.dim(" Quick start:"),
|
|
4160
|
-
` ${chalk8.cyan("rush-ai auth login")}
|
|
4161
|
-
` ${chalk8.cyan("rush-ai agent list")}
|
|
4162
|
-
` ${chalk8.cyan("rush-ai task create -a
|
|
4334
|
+
` ${chalk8.cyan("rush-ai auth login")} Log in to the Rush platform`,
|
|
4335
|
+
` ${chalk8.cyan("rush-ai agent list")} Browse available agents`,
|
|
4336
|
+
` ${chalk8.cyan("rush-ai task create -a web-builder")} Hand a task to a Rush agent`,
|
|
4337
|
+
"",
|
|
4338
|
+
chalk8.dim(" For AI agents:"),
|
|
4339
|
+
` ${chalk8.cyan("rush-ai skill")} Print usage playbooks (markdown)`,
|
|
4340
|
+
` ${chalk8.cyan("rush-ai skill hand-off")} IDE \u2192 Rush task hand-off`,
|
|
4341
|
+
` ${chalk8.cyan("rush-ai skill agent-shelf")} Calling a Rush agent as a sub-agent`,
|
|
4163
4342
|
""
|
|
4164
4343
|
];
|
|
4165
4344
|
try {
|