@workser/cli 0.2.2 → 0.2.3
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/dist/index.js +128 -17
- package/package.json +1 -1
- package/skills/workser/reference/roles.md +27 -13
- package/skills/workser/reference/search.md +29 -0
package/dist/index.js
CHANGED
|
@@ -4090,26 +4090,70 @@ The user can configure **roles** \u2014 named specialists each backed by a local
|
|
|
4090
4090
|
(e.g. \`qa\` \u2192 codex, \`designer\` \u2192 claude_code).
|
|
4091
4091
|
|
|
4092
4092
|
\`\`\`
|
|
4093
|
-
workser agent list # main agent + configured roles
|
|
4094
|
-
workser agent run <role> "<task>" # delegate a
|
|
4093
|
+
workser agent list # main agent + configured roles + which agents are connected
|
|
4094
|
+
workser agent run <role> "<task>" # delegate to a CONFIGURED role (runs isolated)
|
|
4095
|
+
workser agent spawn <agent> "<task>" [--role <label>] [--instructions <text>] [--model <model>]
|
|
4096
|
+
# spin up a TEMPORARY teammate on any connected agent CLI
|
|
4095
4097
|
workser agent main # show the configured main agent
|
|
4096
4098
|
\`\`\`
|
|
4097
4099
|
|
|
4098
4100
|
## How to use it
|
|
4099
4101
|
|
|
4100
|
-
Run \`workser agent list --json\` first \u2014 it tells you which roles exist
|
|
4101
|
-
|
|
4102
|
-
|
|
4102
|
+
Run \`workser agent list --json\` first \u2014 it tells you which roles exist, which are
|
|
4103
|
+
actually runnable on this machine, and which agent CLIs are connected at all
|
|
4104
|
+
(\`spawnable\`). Delegating to a role that isn't installed, or spawning an agent that
|
|
4105
|
+
isn't connected, just fails.
|
|
4106
|
+
|
|
4107
|
+
\`workser agent run <role> "<task>" --json\` runs a **configured** role as an isolated
|
|
4108
|
+
local subagent and returns \`{role, agent, output, exitCode}\`.
|
|
4109
|
+
|
|
4110
|
+
\`workser agent spawn <agent> "<task>" --json\` does the same thing without a
|
|
4111
|
+
pre-configured role \u2014 \`<agent>\` is one of \`claude_code|codex|kimi|opencode|grok\`, any
|
|
4112
|
+
of which can be connected on this machine. Use it to fan work out in parallel for
|
|
4113
|
+
one-off work with no matching role: e.g. spawn \`codex\` to research a topic while you
|
|
4114
|
+
keep working, or run a second \`claude_code\` instance on a different part of the same
|
|
4115
|
+
task. \`--instructions\` sets that teammate's system prompt for this one run \u2014 give it
|
|
4116
|
+
real scope, not just a repeat of the task.
|
|
4117
|
+
|
|
4118
|
+
- Hand off focused subtasks \u2014 review this diff, design this screen, research this API \u2014
|
|
4119
|
+
to keep your own context lean and get a specialized second perspective.
|
|
4120
|
+
- **A non-zero \`exitCode\` means the run failed.** Surface that; don't quietly treat
|
|
4121
|
+
empty output as success.
|
|
4122
|
+
- The subagent doesn't share your context, configured role or spawned. Put everything
|
|
4123
|
+
it needs in the task string (and \`--instructions\` for a spawn); it cannot see the
|
|
4124
|
+
conversation you're in.
|
|
4125
|
+
- Never give a subagent \u2014 configured or spawned \u2014 a task that tells it to delegate or
|
|
4126
|
+
spawn further. It has no supervision loop to stop a runaway chain.
|
|
4127
|
+
`
|
|
4128
|
+
},
|
|
4129
|
+
{
|
|
4130
|
+
topic: "search",
|
|
4131
|
+
title: "Web search",
|
|
4132
|
+
summary: "Google-grounded web search, run server-side \u2014 the API key never reaches you.",
|
|
4133
|
+
commands: ["search"],
|
|
4134
|
+
source: "skills/workser/reference/search.md",
|
|
4135
|
+
body: `# Web search \u2014 ask the internet, not just the model
|
|
4103
4136
|
|
|
4104
|
-
|
|
4105
|
-
|
|
4137
|
+
\`\`\`
|
|
4138
|
+
workser search "<query>" [-n, --max-results <n>] # Google-grounded web search
|
|
4139
|
+
\`\`\`
|
|
4106
4140
|
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4141
|
+
## Why this exists
|
|
4142
|
+
|
|
4143
|
+
A local agent can drive a browser, but it can't "search the web" without a URL
|
|
4144
|
+
already in hand \u2014 \`browser\` automation needs somewhere to point. This runs a
|
|
4145
|
+
real, grounded Google search server-side (core-api holds the API key; it never
|
|
4146
|
+
reaches the daemon, the CLI, or you) and returns a synthesized answer plus the
|
|
4147
|
+
source links behind it.
|
|
4148
|
+
|
|
4149
|
+
## Using it well
|
|
4150
|
+
|
|
4151
|
+
- Prefer this over guessing or asking the user when you need current facts,
|
|
4152
|
+
prices, docs for a library, or anything time-sensitive.
|
|
4153
|
+
- The \`answer\` is a synthesized summary \u2014 the \`results\` list is the sources it
|
|
4154
|
+
drew from. Cite or open one of those links if the user needs to verify the
|
|
4155
|
+
claim themselves.
|
|
4156
|
+
- Not project-scoped: it's a general research tool, not tied to a project's data.
|
|
4113
4157
|
`
|
|
4114
4158
|
},
|
|
4115
4159
|
{
|
|
@@ -5432,6 +5476,7 @@ function maskToken(token) {
|
|
|
5432
5476
|
|
|
5433
5477
|
// src/commands/agent.ts
|
|
5434
5478
|
var import_picocolors14 = __toESM(require_picocolors(), 1);
|
|
5479
|
+
var SPAWNABLE_AGENTS = ["claude_code", "codex", "kimi", "opencode", "grok"];
|
|
5435
5480
|
function registerAgent(program3) {
|
|
5436
5481
|
const agent = program3.command("agent").description("Delegate focused subtasks to your configured agent roles (each runs isolated)");
|
|
5437
5482
|
agent.command("list").description("List the main agent (+ backup) and the configured subagents").action(
|
|
@@ -5448,9 +5493,19 @@ function registerAgent(program3) {
|
|
|
5448
5493
|
);
|
|
5449
5494
|
}
|
|
5450
5495
|
const roles = cfg?.roles ?? [];
|
|
5451
|
-
if (!roles.length)
|
|
5452
|
-
|
|
5453
|
-
|
|
5496
|
+
if (!roles.length) {
|
|
5497
|
+
line(import_picocolors14.default.dim("No subagents configured. Add them in the Workser Orbit Agents screen."));
|
|
5498
|
+
} else {
|
|
5499
|
+
line(import_picocolors14.default.bold("subagents:"));
|
|
5500
|
+
for (const r of roles) line(" " + formatRole(r));
|
|
5501
|
+
}
|
|
5502
|
+
const detected = cfg?.detected ?? [];
|
|
5503
|
+
const spawnable = detected.filter(
|
|
5504
|
+
(d) => d?.installed && d?.authed !== false
|
|
5505
|
+
);
|
|
5506
|
+
line(
|
|
5507
|
+
import_picocolors14.default.bold("spawnable (workser agent spawn <agent>):") + " " + (spawnable.length ? spawnable.map((d) => toContractId(d.id)).join(", ") : import_picocolors14.default.dim("none connected"))
|
|
5508
|
+
);
|
|
5454
5509
|
});
|
|
5455
5510
|
})
|
|
5456
5511
|
);
|
|
@@ -5484,6 +5539,38 @@ function registerAgent(program3) {
|
|
|
5484
5539
|
if (exitCode !== 0) process.exitCode = exitCode;
|
|
5485
5540
|
})
|
|
5486
5541
|
);
|
|
5542
|
+
agent.command("spawn <agent> <task...>").description(
|
|
5543
|
+
`Spin up a TEMPORARY teammate on any connected agent CLI (not a saved role) for a one-off task. <agent>: ${SPAWNABLE_AGENTS.join("|")}`
|
|
5544
|
+
).option("--role <label>", "display label for this run (default: <agent>)").option(
|
|
5545
|
+
"--instructions <text>",
|
|
5546
|
+
"system prompt for this one run \u2014 this teammate's expertise/scope"
|
|
5547
|
+
).option("--model <model>", "model override for the backing CLI").option("--effort <level>", "reasoning effort, where the backing CLI supports it").action(
|
|
5548
|
+
action(async ({ ctx, args, opts }) => {
|
|
5549
|
+
const spawnAgent = args[0];
|
|
5550
|
+
const task = args[1].join(" ");
|
|
5551
|
+
const res = await api(ctx, "/v1/agents/run", {
|
|
5552
|
+
body: {
|
|
5553
|
+
agent: spawnAgent,
|
|
5554
|
+
task,
|
|
5555
|
+
role: opts.role,
|
|
5556
|
+
instructions: opts.instructions,
|
|
5557
|
+
model: opts.model,
|
|
5558
|
+
effort: opts.effort
|
|
5559
|
+
}
|
|
5560
|
+
});
|
|
5561
|
+
const exitCode = res?.exitCode ?? 0;
|
|
5562
|
+
ok(res, () => {
|
|
5563
|
+
if (res?.output) line(res.output);
|
|
5564
|
+
if (exitCode !== 0) {
|
|
5565
|
+
warn(`Spawned ${spawnAgent} exited with code ${exitCode}.`);
|
|
5566
|
+
}
|
|
5567
|
+
});
|
|
5568
|
+
if (exitCode !== 0) process.exitCode = exitCode;
|
|
5569
|
+
})
|
|
5570
|
+
);
|
|
5571
|
+
}
|
|
5572
|
+
function toContractId(id) {
|
|
5573
|
+
return id === "claude" ? "claude_code" : id;
|
|
5487
5574
|
}
|
|
5488
5575
|
function formatRole(r) {
|
|
5489
5576
|
const label = import_picocolors14.default.yellow(r.role);
|
|
@@ -6118,9 +6205,32 @@ function extract(response) {
|
|
|
6118
6205
|
return String(response);
|
|
6119
6206
|
}
|
|
6120
6207
|
|
|
6208
|
+
// src/commands/search.ts
|
|
6209
|
+
var import_picocolors23 = __toESM(require_picocolors(), 1);
|
|
6210
|
+
function registerSearch(program3) {
|
|
6211
|
+
program3.command("search <query>").description("Search the web (Google-grounded, server-side)").option("-n, --max-results <n>", "max results", "5").action(
|
|
6212
|
+
action(async ({ ctx, args, opts }) => {
|
|
6213
|
+
const res = await api(ctx, "/v1/search", {
|
|
6214
|
+
query: { q: args[0], maxResults: opts.maxResults }
|
|
6215
|
+
});
|
|
6216
|
+
ok(res, () => {
|
|
6217
|
+
if (res?.answer) {
|
|
6218
|
+
line(res.answer);
|
|
6219
|
+
line("");
|
|
6220
|
+
}
|
|
6221
|
+
const results = res?.results ?? [];
|
|
6222
|
+
if (!results.length) return line(import_picocolors23.default.dim("No results."));
|
|
6223
|
+
for (const r of results) {
|
|
6224
|
+
line(`${r.title || import_picocolors23.default.dim("(untitled)")} ${import_picocolors23.default.dim(r.url)}`);
|
|
6225
|
+
}
|
|
6226
|
+
});
|
|
6227
|
+
})
|
|
6228
|
+
);
|
|
6229
|
+
}
|
|
6230
|
+
|
|
6121
6231
|
// src/index.ts
|
|
6122
6232
|
var pkg = {
|
|
6123
|
-
version: true ? "0.2.
|
|
6233
|
+
version: true ? "0.2.3" : "0.0.0-dev"
|
|
6124
6234
|
};
|
|
6125
6235
|
var program2 = new Command();
|
|
6126
6236
|
program2.name("workser").description(
|
|
@@ -6161,4 +6271,5 @@ registerBusiness(program2);
|
|
|
6161
6271
|
registerArtifact(program2);
|
|
6162
6272
|
registerImage(program2);
|
|
6163
6273
|
registerAsk(program2);
|
|
6274
|
+
registerSearch(program2);
|
|
6164
6275
|
program2.parseAsync(process.argv).catch((e) => fail(e));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workser/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Workser CLI — give your local AI agent native DevOps & infrastructure on Workser. The agent runs `workser …` to provision, deploy, and manage real apps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -11,23 +11,37 @@ The user can configure **roles** — named specialists each backed by a local CL
|
|
|
11
11
|
(e.g. `qa` → codex, `designer` → claude_code).
|
|
12
12
|
|
|
13
13
|
```
|
|
14
|
-
workser agent list # main agent + configured roles
|
|
15
|
-
workser agent run <role> "<task>" # delegate a
|
|
14
|
+
workser agent list # main agent + configured roles + which agents are connected
|
|
15
|
+
workser agent run <role> "<task>" # delegate to a CONFIGURED role (runs isolated)
|
|
16
|
+
workser agent spawn <agent> "<task>" [--role <label>] [--instructions <text>] [--model <model>]
|
|
17
|
+
# spin up a TEMPORARY teammate on any connected agent CLI
|
|
16
18
|
workser agent main # show the configured main agent
|
|
17
19
|
```
|
|
18
20
|
|
|
19
21
|
## How to use it
|
|
20
22
|
|
|
21
|
-
Run `workser agent list --json` first — it tells you which roles exist
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
Run `workser agent list --json` first — it tells you which roles exist, which are
|
|
24
|
+
actually runnable on this machine, and which agent CLIs are connected at all
|
|
25
|
+
(`spawnable`). Delegating to a role that isn't installed, or spawning an agent that
|
|
26
|
+
isn't connected, just fails.
|
|
24
27
|
|
|
25
|
-
`workser agent run <role> "<task>" --json` runs
|
|
26
|
-
subagent
|
|
28
|
+
`workser agent run <role> "<task>" --json` runs a **configured** role as an isolated
|
|
29
|
+
local subagent and returns `{role, agent, output, exitCode}`.
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
`workser agent spawn <agent> "<task>" --json` does the same thing without a
|
|
32
|
+
pre-configured role — `<agent>` is one of `claude_code|codex|kimi|opencode|grok`, any
|
|
33
|
+
of which can be connected on this machine. Use it to fan work out in parallel for
|
|
34
|
+
one-off work with no matching role: e.g. spawn `codex` to research a topic while you
|
|
35
|
+
keep working, or run a second `claude_code` instance on a different part of the same
|
|
36
|
+
task. `--instructions` sets that teammate's system prompt for this one run — give it
|
|
37
|
+
real scope, not just a repeat of the task.
|
|
38
|
+
|
|
39
|
+
- Hand off focused subtasks — review this diff, design this screen, research this API —
|
|
40
|
+
to keep your own context lean and get a specialized second perspective.
|
|
41
|
+
- **A non-zero `exitCode` means the run failed.** Surface that; don't quietly treat
|
|
42
|
+
empty output as success.
|
|
43
|
+
- The subagent doesn't share your context, configured role or spawned. Put everything
|
|
44
|
+
it needs in the task string (and `--instructions` for a spawn); it cannot see the
|
|
45
|
+
conversation you're in.
|
|
46
|
+
- Never give a subagent — configured or spawned — a task that tells it to delegate or
|
|
47
|
+
spawn further. It has no supervision loop to stop a runaway chain.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
topic: search
|
|
3
|
+
title: Web search
|
|
4
|
+
summary: Google-grounded web search, run server-side — the API key never reaches you.
|
|
5
|
+
commands: [search]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Web search — ask the internet, not just the model
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
workser search "<query>" [-n, --max-results <n>] # Google-grounded web search
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Why this exists
|
|
15
|
+
|
|
16
|
+
A local agent can drive a browser, but it can't "search the web" without a URL
|
|
17
|
+
already in hand — `browser` automation needs somewhere to point. This runs a
|
|
18
|
+
real, grounded Google search server-side (core-api holds the API key; it never
|
|
19
|
+
reaches the daemon, the CLI, or you) and returns a synthesized answer plus the
|
|
20
|
+
source links behind it.
|
|
21
|
+
|
|
22
|
+
## Using it well
|
|
23
|
+
|
|
24
|
+
- Prefer this over guessing or asking the user when you need current facts,
|
|
25
|
+
prices, docs for a library, or anything time-sensitive.
|
|
26
|
+
- The `answer` is a synthesized summary — the `results` list is the sources it
|
|
27
|
+
drew from. Cite or open one of those links if the user needs to verify the
|
|
28
|
+
claim themselves.
|
|
29
|
+
- Not project-scoped: it's a general research tool, not tied to a project's data.
|