@workser/cli 0.6.16 → 0.6.18
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 +830 -255
- package/package.json +1 -1
- package/skills/workser/SKILL.md +1 -0
package/dist/index.js
CHANGED
|
@@ -3663,6 +3663,158 @@ var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
|
3663
3663
|
|
|
3664
3664
|
// src/help-content.ts
|
|
3665
3665
|
var HELP_TOPICS = [
|
|
3666
|
+
{
|
|
3667
|
+
topic: "agent-cloud",
|
|
3668
|
+
title: "Ship an agent inside the app",
|
|
3669
|
+
summary: "Create an AI agent that runs on Workser and can be called from this project's apps.",
|
|
3670
|
+
commands: ["agent-cloud"],
|
|
3671
|
+
source: "skills/workser/reference/agent-cloud.md",
|
|
3672
|
+
body: `# Ship an agent inside the app
|
|
3673
|
+
|
|
3674
|
+
\`workser agent-cloud\` creates an AI agent that runs on **Workser's**
|
|
3675
|
+
infrastructure, keeps its own memory and tools, and can be called from the web,
|
|
3676
|
+
mobile, API or Python apps in this project.
|
|
3677
|
+
|
|
3678
|
+
**This is not \`workser agent\`.** That one hands a subtask to a coding agent on
|
|
3679
|
+
this machine \u2014 a teammate helping you build. This one is a thing the project
|
|
3680
|
+
*ships*: it works for the user after you are gone.
|
|
3681
|
+
|
|
3682
|
+
\`\`\`
|
|
3683
|
+
workser agent-cloud list
|
|
3684
|
+
workser agent-cloud create "Order desk" --instructions "..."
|
|
3685
|
+
workser agent-cloud show <agentId>
|
|
3686
|
+
workser agent-cloud run <agentId> "<what to do>"
|
|
3687
|
+
workser agent-cloud runs <agentId> # recent runs
|
|
3688
|
+
workser agent-cloud runs <runId> # one run, with what it cost
|
|
3689
|
+
\`\`\`
|
|
3690
|
+
|
|
3691
|
+
Every call is scoped to the project this folder belongs to.
|
|
3692
|
+
|
|
3693
|
+
## Creating one is not finishing one
|
|
3694
|
+
|
|
3695
|
+
An agent created with a name and a sentence knows nothing about the business.
|
|
3696
|
+
Teaching it is the actual work, and it is all here:
|
|
3697
|
+
|
|
3698
|
+
\`\`\`
|
|
3699
|
+
workser agent-cloud set <id> system_prompt="..." handle="orderdesk"
|
|
3700
|
+
workser agent-cloud add <id> skill name="Refunds" instructions_md="..."
|
|
3701
|
+
workser agent-cloud add <id> knowledge name="Price list" content_text="..."
|
|
3702
|
+
workser agent-cloud add <id> tool display_name="Send email" provider="gmail" \\
|
|
3703
|
+
provider_tool_id="GMAIL_SEND_EMAIL"
|
|
3704
|
+
workser agent-cloud add <id> secret key="STRIPE_KEY" value="..."
|
|
3705
|
+
workser agent-cloud add <id> subagent subagent_id=<otherId> name="researcher"
|
|
3706
|
+
workser agent-cloud get <id> skill # what it has
|
|
3707
|
+
workser agent-cloud remove <id> skill <itemId>
|
|
3708
|
+
\`\`\`
|
|
3709
|
+
|
|
3710
|
+
\`add\` takes \`key=value\` pairs and REFUSES a field it does not know, rather than
|
|
3711
|
+
sending it. That matters: the API silently drops unknown fields, so a typo
|
|
3712
|
+
would otherwise be accepted, dropped, and reported as success \u2014 leaving an
|
|
3713
|
+
agent that had been told nothing.
|
|
3714
|
+
|
|
3715
|
+
## Nothing takes effect until you publish
|
|
3716
|
+
|
|
3717
|
+
**This is the step to not forget.** The runtime resolves the PUBLISHED version
|
|
3718
|
+
of an agent and never the draft, so every \`set\` and \`add\` above is inert until:
|
|
3719
|
+
|
|
3720
|
+
\`\`\`
|
|
3721
|
+
workser agent-cloud publish <id> --note "taught it refunds"
|
|
3722
|
+
\`\`\`
|
|
3723
|
+
|
|
3724
|
+
Before publishing, try the setup without putting it live:
|
|
3725
|
+
|
|
3726
|
+
\`\`\`
|
|
3727
|
+
workser agent-cloud try <id> "a customer wants a refund on order 1042"
|
|
3728
|
+
\`\`\`
|
|
3729
|
+
|
|
3730
|
+
A \`try\` runs the draft, costs the same as a real run, and changes nothing that
|
|
3731
|
+
customers can reach.
|
|
3732
|
+
|
|
3733
|
+
## Choosing how it thinks and what it runs on
|
|
3734
|
+
|
|
3735
|
+
\`\`\`
|
|
3736
|
+
workser agent-cloud models # cheapest first, on Workser credit
|
|
3737
|
+
workser agent-cloud models --all # includes ones needing your own key
|
|
3738
|
+
workser agent-cloud set <id> default_provider=openrouter default_model=...
|
|
3739
|
+
|
|
3740
|
+
workser agent-cloud machines # video, data analysis, design, ...
|
|
3741
|
+
\`\`\`
|
|
3742
|
+
|
|
3743
|
+
A model marked "needs your own key" will make \`publish\` FAIL unless a matching
|
|
3744
|
+
secret is stored first. Add the key with \`add <id> secret\` before setting it.
|
|
3745
|
+
|
|
3746
|
+
## Agents need a paid plan \u2014 the trial does not include them
|
|
3747
|
+
|
|
3748
|
+
\`create\` and \`run\` both refuse with **402** on a free or trialling
|
|
3749
|
+
organisation. That is a rule, not a fault: every run buys model tokens and
|
|
3750
|
+
holds a machine, so it costs real money the moment it happens.
|
|
3751
|
+
|
|
3752
|
+
**When you hit it, hand the plan over \u2014 do not just describe it.** Workser
|
|
3753
|
+
files the refusal on the conversation as a step and an artifact the user can
|
|
3754
|
+
click, so the person you are helping gets something actionable rather than a
|
|
3755
|
+
paragraph. Say plainly what you were doing, that agents need a plan, and stop.
|
|
3756
|
+
|
|
3757
|
+
Do NOT:
|
|
3758
|
+
|
|
3759
|
+
- retry the call, or try a different agent \u2014 the answer is the same
|
|
3760
|
+
- try to work around it by running the job yourself as a coding agent; that is
|
|
3761
|
+
a different product and it will not be there when the user closes the window
|
|
3762
|
+
- guess at prices, discounts or trial extensions
|
|
3763
|
+
|
|
3764
|
+
If the user asks how much: it is per minute of run time plus the model, and the
|
|
3765
|
+
plan page has the current figures. You do not have them.
|
|
3766
|
+
|
|
3767
|
+
## When to reach for this
|
|
3768
|
+
|
|
3769
|
+
When the user describes a job that **keeps happening** and needs judgement:
|
|
3770
|
+
"check every order for stock and email me the problems", "read the LINE
|
|
3771
|
+
messages and file them", "reconcile these invoices". That is an agent.
|
|
3772
|
+
|
|
3773
|
+
A one-off transformation is not an agent \u2014 write the code. A fixed sequence of
|
|
3774
|
+
steps with no judgement in it is not an agent either \u2014 that is \`workser
|
|
3775
|
+
workflow\`.
|
|
3776
|
+
|
|
3777
|
+
## Calling it from the app you are building
|
|
3778
|
+
|
|
3779
|
+
Do NOT shell out to the CLI from app code. Use the SDK, which streams:
|
|
3780
|
+
|
|
3781
|
+
\`\`\`ts
|
|
3782
|
+
import { workser } from '@workser/app';
|
|
3783
|
+
|
|
3784
|
+
const run = await workser.agents.run(agentId, { message }, {
|
|
3785
|
+
referenceUserId: user.id, // who it is acting for
|
|
3786
|
+
});
|
|
3787
|
+
|
|
3788
|
+
for await (const event of workser.agents.stream(run.id)) {
|
|
3789
|
+
// event.type, event.data \u2014 forward these to the browser
|
|
3790
|
+
}
|
|
3791
|
+
\`\`\`
|
|
3792
|
+
|
|
3793
|
+
\`stream()\` reconnects itself through dropped connections, so the person
|
|
3794
|
+
watching sees the agent think. See the \`workser-sdk\` skill, \`reference/agents.md\`.
|
|
3795
|
+
|
|
3796
|
+
## Things that will bite you
|
|
3797
|
+
|
|
3798
|
+
1. **A run costs money by the minute.** It is metered \u2014 runtime, workspace, and
|
|
3799
|
+
a per-run fee \u2014 so a loop that starts agents is a loop that spends. Cancel
|
|
3800
|
+
what you abandon: \`workser agent-cloud runs <runId>\` shows the cost.
|
|
3801
|
+
|
|
3802
|
+
2. **Instructions are the product.** The agent does what its instructions say,
|
|
3803
|
+
in the user's own words. Write them the way you would brief a new colleague:
|
|
3804
|
+
what to do, what to leave alone, when to ask. Vague instructions are the
|
|
3805
|
+
single biggest cause of an agent that "doesn't work".
|
|
3806
|
+
|
|
3807
|
+
3. **Free plans cannot run agents at all**, and a trial has a small allowance.
|
|
3808
|
+
A \`402\` with \`spend_limit_reached\` is not a bug \u2014 tell the user what it says
|
|
3809
|
+
and point them at their plan.
|
|
3810
|
+
|
|
3811
|
+
4. **Say who it is for.** An agent acting for one of the app's customers needs
|
|
3812
|
+
\`referenceUserId\`, or its memory and audit trail belong to nobody.
|
|
3813
|
+
|
|
3814
|
+
5. **Do not invent an agent the user did not ask for.** Creating one is cheap;
|
|
3815
|
+
an agent nobody wanted, quietly costing money per run, is not.
|
|
3816
|
+
`
|
|
3817
|
+
},
|
|
3666
3818
|
{
|
|
3667
3819
|
topic: "analysis",
|
|
3668
3820
|
title: "Analysis \u2014 running Python on this project's data",
|
|
@@ -7459,8 +7611,366 @@ function formatRole(r) {
|
|
|
7459
7611
|
return `${label} ${agent} ${enabled} ${ready}${tail}`;
|
|
7460
7612
|
}
|
|
7461
7613
|
|
|
7462
|
-
// src/commands/
|
|
7614
|
+
// src/commands/agent-cloud.ts
|
|
7463
7615
|
var import_picocolors17 = __toESM(require_picocolors(), 1);
|
|
7616
|
+
function registerAgentCloud(program3) {
|
|
7617
|
+
const cloud = program3.command("agent-cloud").description(
|
|
7618
|
+
"Agents that run in the cloud and can be called from this project's apps (not the local coding agents \u2014 that's `workser agent`)"
|
|
7619
|
+
);
|
|
7620
|
+
cloud.command("list").description("List this project's cloud agents").action(
|
|
7621
|
+
action(async ({ ctx }) => {
|
|
7622
|
+
const res = await api(ctx, "/v1/agent-cloud");
|
|
7623
|
+
const agents = res?.agents ?? res ?? [];
|
|
7624
|
+
ok(res, () => {
|
|
7625
|
+
if (!agents.length) {
|
|
7626
|
+
line(import_picocolors17.default.dim("No cloud agents yet."));
|
|
7627
|
+
line(
|
|
7628
|
+
import_picocolors17.default.dim("Create one: ") + import_picocolors17.default.bold('workser agent-cloud create "Order desk" --instructions "..."')
|
|
7629
|
+
);
|
|
7630
|
+
return;
|
|
7631
|
+
}
|
|
7632
|
+
for (const a of agents) {
|
|
7633
|
+
line(
|
|
7634
|
+
`${import_picocolors17.default.bold(a.name ?? a.id)} ${import_picocolors17.default.dim(a.id)}` + (a.status ? ` ${import_picocolors17.default.dim(a.status)}` : "")
|
|
7635
|
+
);
|
|
7636
|
+
if (a.description) line(" " + import_picocolors17.default.dim(a.description));
|
|
7637
|
+
}
|
|
7638
|
+
});
|
|
7639
|
+
})
|
|
7640
|
+
);
|
|
7641
|
+
cloud.command("create <name>").description("Create a cloud agent in this project").option("--description <text>", "What it is for, in the owner's words").option(
|
|
7642
|
+
"--instructions <text>",
|
|
7643
|
+
"The agent's standing instructions \u2014 what it should always do"
|
|
7644
|
+
).action(
|
|
7645
|
+
action(async ({ ctx, args, opts }) => {
|
|
7646
|
+
const res = await api(ctx, "/v1/agent-cloud", {
|
|
7647
|
+
method: "POST",
|
|
7648
|
+
body: {
|
|
7649
|
+
name: args[0],
|
|
7650
|
+
description: opts.description,
|
|
7651
|
+
instructions: opts.instructions
|
|
7652
|
+
}
|
|
7653
|
+
});
|
|
7654
|
+
ok(res, () => {
|
|
7655
|
+
line(import_picocolors17.default.green("Created ") + import_picocolors17.default.bold(res?.name ?? args[0]));
|
|
7656
|
+
if (res?.id) line(import_picocolors17.default.dim(res.id));
|
|
7657
|
+
line("");
|
|
7658
|
+
line(
|
|
7659
|
+
import_picocolors17.default.dim("Give it work: ") + import_picocolors17.default.bold(`workser agent-cloud run ${res?.id ?? "<id>"} "..."`)
|
|
7660
|
+
);
|
|
7661
|
+
});
|
|
7662
|
+
})
|
|
7663
|
+
);
|
|
7664
|
+
cloud.command("show <agentId>").description("One cloud agent, with its configuration").action(
|
|
7665
|
+
action(async ({ ctx, args }) => {
|
|
7666
|
+
const res = await api(ctx, `/v1/agent-cloud/${encodeURIComponent(args[0])}`);
|
|
7667
|
+
ok(res, () => {
|
|
7668
|
+
line(import_picocolors17.default.bold(res?.name ?? args[0]));
|
|
7669
|
+
if (res?.description) line(import_picocolors17.default.dim(res.description));
|
|
7670
|
+
if (res?.instructions) {
|
|
7671
|
+
line("");
|
|
7672
|
+
line(import_picocolors17.default.bold("instructions:"));
|
|
7673
|
+
line(res.instructions);
|
|
7674
|
+
}
|
|
7675
|
+
});
|
|
7676
|
+
})
|
|
7677
|
+
);
|
|
7678
|
+
cloud.command("run <agentId> <message>").description("Give a cloud agent something to do").action(
|
|
7679
|
+
action(async ({ ctx, args }) => {
|
|
7680
|
+
const res = await api(
|
|
7681
|
+
ctx,
|
|
7682
|
+
`/v1/agent-cloud/${encodeURIComponent(args[0])}/runs`,
|
|
7683
|
+
{ method: "POST", body: { input: { message: args[1] } } }
|
|
7684
|
+
);
|
|
7685
|
+
ok(res, () => {
|
|
7686
|
+
line(import_picocolors17.default.green("Started run ") + import_picocolors17.default.bold(res?.id ?? ""));
|
|
7687
|
+
line(
|
|
7688
|
+
import_picocolors17.default.dim("Follow it: ") + import_picocolors17.default.bold(`workser agent-cloud runs ${res?.id ?? "<runId>"}`)
|
|
7689
|
+
);
|
|
7690
|
+
});
|
|
7691
|
+
})
|
|
7692
|
+
);
|
|
7693
|
+
cloud.command("runs [agentIdOrRunId]").description("Recent runs for an agent, or one run in detail").option("--limit <n>", "How many to list", "10").action(
|
|
7694
|
+
action(async ({ ctx, args, opts }) => {
|
|
7695
|
+
const id = args[0];
|
|
7696
|
+
if (!id) {
|
|
7697
|
+
warn("Give an agent id to list its runs, or a run id to inspect one.");
|
|
7698
|
+
return;
|
|
7699
|
+
}
|
|
7700
|
+
try {
|
|
7701
|
+
const run = await api(
|
|
7702
|
+
ctx,
|
|
7703
|
+
`/v1/agent-cloud/runs/${encodeURIComponent(id)}`
|
|
7704
|
+
);
|
|
7705
|
+
ok(run, () => printRun(run));
|
|
7706
|
+
return;
|
|
7707
|
+
} catch {
|
|
7708
|
+
}
|
|
7709
|
+
const res = await api(
|
|
7710
|
+
ctx,
|
|
7711
|
+
`/v1/agent-cloud/${encodeURIComponent(id)}/runs`,
|
|
7712
|
+
{ query: { limit: opts.limit } }
|
|
7713
|
+
);
|
|
7714
|
+
const runs = res?.runs ?? res ?? [];
|
|
7715
|
+
ok(res, () => {
|
|
7716
|
+
if (!runs.length) {
|
|
7717
|
+
line(import_picocolors17.default.dim("No runs yet."));
|
|
7718
|
+
return;
|
|
7719
|
+
}
|
|
7720
|
+
for (const r of runs) printRun(r, true);
|
|
7721
|
+
});
|
|
7722
|
+
})
|
|
7723
|
+
);
|
|
7724
|
+
const COLLECTIONS = {
|
|
7725
|
+
skill: {
|
|
7726
|
+
path: "skills",
|
|
7727
|
+
key: "skills",
|
|
7728
|
+
label: "skill",
|
|
7729
|
+
fields: ["name", "description", "instructions_md"],
|
|
7730
|
+
required: ["name"]
|
|
7731
|
+
},
|
|
7732
|
+
tool: {
|
|
7733
|
+
path: "tools",
|
|
7734
|
+
key: "tools",
|
|
7735
|
+
label: "action",
|
|
7736
|
+
fields: ["display_name", "provider", "provider_tool_id", "description"],
|
|
7737
|
+
required: ["display_name"]
|
|
7738
|
+
},
|
|
7739
|
+
mcp: {
|
|
7740
|
+
path: "mcp-servers",
|
|
7741
|
+
key: "servers",
|
|
7742
|
+
label: "MCP server",
|
|
7743
|
+
fields: ["name", "url"],
|
|
7744
|
+
required: ["name", "url"]
|
|
7745
|
+
},
|
|
7746
|
+
knowledge: {
|
|
7747
|
+
path: "resources",
|
|
7748
|
+
key: "resources",
|
|
7749
|
+
label: "reference material",
|
|
7750
|
+
fields: ["name", "content_text"],
|
|
7751
|
+
required: ["name"]
|
|
7752
|
+
},
|
|
7753
|
+
secret: {
|
|
7754
|
+
path: "secrets",
|
|
7755
|
+
key: "secrets",
|
|
7756
|
+
label: "stored key",
|
|
7757
|
+
fields: ["key", "value", "description"],
|
|
7758
|
+
required: ["key", "value"]
|
|
7759
|
+
},
|
|
7760
|
+
subagent: {
|
|
7761
|
+
path: "subagents",
|
|
7762
|
+
key: "subagents",
|
|
7763
|
+
label: "team member",
|
|
7764
|
+
fields: ["subagent_id", "name", "description"],
|
|
7765
|
+
required: ["subagent_id", "name"]
|
|
7766
|
+
},
|
|
7767
|
+
workflow: {
|
|
7768
|
+
path: "workflows",
|
|
7769
|
+
key: "workflows",
|
|
7770
|
+
label: "workflow",
|
|
7771
|
+
fields: ["workflow_id", "description"],
|
|
7772
|
+
required: ["workflow_id"]
|
|
7773
|
+
}
|
|
7774
|
+
};
|
|
7775
|
+
const kinds = Object.keys(COLLECTIONS).join(" | ");
|
|
7776
|
+
cloud.command("get <agentId> <kind>").description(`What an agent has been given (${kinds})`).action(
|
|
7777
|
+
action(async ({ ctx, args }) => {
|
|
7778
|
+
const spec = COLLECTIONS[args[1]];
|
|
7779
|
+
if (!spec) throw new Error(`Unknown kind "${args[1]}". One of: ${kinds}`);
|
|
7780
|
+
const res = await api(ctx, `/v1/agent-cloud/${encodeURIComponent(args[0])}/${spec.path}`);
|
|
7781
|
+
const items = res?.[spec.key] ?? [];
|
|
7782
|
+
ok(res, () => {
|
|
7783
|
+
if (!items.length) {
|
|
7784
|
+
line(import_picocolors17.default.dim(`No ${spec.label} yet.`));
|
|
7785
|
+
return;
|
|
7786
|
+
}
|
|
7787
|
+
for (const i of items) {
|
|
7788
|
+
const title = i.name ?? i.display_name ?? i.key ?? i.workflow_id ?? i.id;
|
|
7789
|
+
line(`${import_picocolors17.default.bold(title)} ${import_picocolors17.default.dim(i.id)}`);
|
|
7790
|
+
if (i.description) line(" " + import_picocolors17.default.dim(i.description));
|
|
7791
|
+
if (i.is_enabled === false) line(" " + import_picocolors17.default.yellow("turned off"));
|
|
7792
|
+
}
|
|
7793
|
+
});
|
|
7794
|
+
})
|
|
7795
|
+
);
|
|
7796
|
+
cloud.command("add <agentId> <kind> [pairs...]").description(
|
|
7797
|
+
`Give an agent something (${kinds}). Pairs are key=value, e.g. name="Refunds"`
|
|
7798
|
+
).action(
|
|
7799
|
+
action(async ({ ctx, args }) => {
|
|
7800
|
+
const spec = COLLECTIONS[args[1]];
|
|
7801
|
+
if (!spec) throw new Error(`Unknown kind "${args[1]}". One of: ${kinds}`);
|
|
7802
|
+
const body = parsePairs(args[2] ?? [], spec.fields);
|
|
7803
|
+
const missing = spec.required.filter((f) => !body[f]);
|
|
7804
|
+
if (missing.length) {
|
|
7805
|
+
throw new Error(
|
|
7806
|
+
`A ${spec.label} needs ${missing.join(" and ")}. Accepted: ${spec.fields.join(", ")}`
|
|
7807
|
+
);
|
|
7808
|
+
}
|
|
7809
|
+
const res = await api(ctx, `/v1/agent-cloud/${encodeURIComponent(args[0])}/${spec.path}`, {
|
|
7810
|
+
method: "POST",
|
|
7811
|
+
body
|
|
7812
|
+
});
|
|
7813
|
+
ok(res, () => {
|
|
7814
|
+
line(import_picocolors17.default.green(`Added the ${spec.label}.`) + " " + import_picocolors17.default.dim(res?.id ?? ""));
|
|
7815
|
+
line(
|
|
7816
|
+
import_picocolors17.default.dim("Not live yet \u2014 run ") + import_picocolors17.default.bold(`workser agent-cloud publish ${args[0]}`) + import_picocolors17.default.dim(" when the setup is ready.")
|
|
7817
|
+
);
|
|
7818
|
+
});
|
|
7819
|
+
})
|
|
7820
|
+
);
|
|
7821
|
+
cloud.command("remove <agentId> <kind> <itemId>").description(`Take something away from an agent (${kinds})`).action(
|
|
7822
|
+
action(async ({ ctx, args }) => {
|
|
7823
|
+
const spec = COLLECTIONS[args[1]];
|
|
7824
|
+
if (!spec) throw new Error(`Unknown kind "${args[1]}". One of: ${kinds}`);
|
|
7825
|
+
const res = await api(
|
|
7826
|
+
ctx,
|
|
7827
|
+
`/v1/agent-cloud/${encodeURIComponent(args[0])}/${spec.path}/${encodeURIComponent(args[2])}`,
|
|
7828
|
+
{ method: "DELETE" }
|
|
7829
|
+
);
|
|
7830
|
+
ok(res, () => line(import_picocolors17.default.green(`Removed the ${spec.label}.`)));
|
|
7831
|
+
})
|
|
7832
|
+
);
|
|
7833
|
+
cloud.command("set <agentId> [pairs...]").description(
|
|
7834
|
+
"Change the brief or the model. Pairs: name, description, system_prompt, handle, default_provider, default_model"
|
|
7835
|
+
).action(
|
|
7836
|
+
action(async ({ ctx, args }) => {
|
|
7837
|
+
const body = parsePairs(args[1] ?? [], [
|
|
7838
|
+
"name",
|
|
7839
|
+
"description",
|
|
7840
|
+
"system_prompt",
|
|
7841
|
+
"handle",
|
|
7842
|
+
"default_provider",
|
|
7843
|
+
"default_model"
|
|
7844
|
+
]);
|
|
7845
|
+
if (!Object.keys(body).length) {
|
|
7846
|
+
throw new Error(
|
|
7847
|
+
'Nothing to change. Example: workser agent-cloud set <id> system_prompt="Always check stock first"'
|
|
7848
|
+
);
|
|
7849
|
+
}
|
|
7850
|
+
const res = await api(ctx, `/v1/agent-cloud/${encodeURIComponent(args[0])}`, {
|
|
7851
|
+
method: "PATCH",
|
|
7852
|
+
body
|
|
7853
|
+
});
|
|
7854
|
+
ok(res, () => {
|
|
7855
|
+
line(import_picocolors17.default.green("Saved."));
|
|
7856
|
+
line(
|
|
7857
|
+
import_picocolors17.default.dim("Not live yet \u2014 run ") + import_picocolors17.default.bold(`workser agent-cloud publish ${args[0]}`) + import_picocolors17.default.dim(".")
|
|
7858
|
+
);
|
|
7859
|
+
});
|
|
7860
|
+
})
|
|
7861
|
+
);
|
|
7862
|
+
cloud.command("publish <agentId>").description("Put the current setup live \u2014 nothing takes effect until this runs").option("--note <text>", "What changed, for the version history").action(
|
|
7863
|
+
action(async ({ ctx, args, opts }) => {
|
|
7864
|
+
const res = await api(ctx, `/v1/agent-cloud/${encodeURIComponent(args[0])}/publish`, {
|
|
7865
|
+
method: "POST",
|
|
7866
|
+
body: { changelog: opts.note }
|
|
7867
|
+
});
|
|
7868
|
+
ok(
|
|
7869
|
+
res,
|
|
7870
|
+
() => line(import_picocolors17.default.green(`Live${res?.version ? ` \u2014 version ${res.version}` : ""}.`))
|
|
7871
|
+
);
|
|
7872
|
+
})
|
|
7873
|
+
);
|
|
7874
|
+
cloud.command("try <agentId> <message>").description("Run the current setup WITHOUT publishing it").action(
|
|
7875
|
+
action(async ({ ctx, args }) => {
|
|
7876
|
+
const res = await api(ctx, `/v1/agent-cloud/${encodeURIComponent(args[0])}/test-runs`, {
|
|
7877
|
+
method: "POST",
|
|
7878
|
+
body: { input: { message: args[1] } }
|
|
7879
|
+
});
|
|
7880
|
+
ok(res, () => {
|
|
7881
|
+
line(import_picocolors17.default.green("Trying it \u2014 nothing has gone live."));
|
|
7882
|
+
if (res?.run_id) {
|
|
7883
|
+
line(
|
|
7884
|
+
import_picocolors17.default.dim("Watch it: ") + import_picocolors17.default.bold(`workser agent-cloud runs ${res.run_id}`)
|
|
7885
|
+
);
|
|
7886
|
+
}
|
|
7887
|
+
});
|
|
7888
|
+
})
|
|
7889
|
+
);
|
|
7890
|
+
cloud.command("machines").description("The pre-built machines an agent can run on").action(
|
|
7891
|
+
action(async ({ ctx }) => {
|
|
7892
|
+
const res = await api(ctx, "/v1/agent-cloud/catalog/machines");
|
|
7893
|
+
ok(res, () => {
|
|
7894
|
+
for (const m of res?.machines ?? []) {
|
|
7895
|
+
line(`${import_picocolors17.default.bold(m.label)} ${import_picocolors17.default.dim(m.alias)}`);
|
|
7896
|
+
line(" " + import_picocolors17.default.dim(m.description));
|
|
7897
|
+
}
|
|
7898
|
+
});
|
|
7899
|
+
})
|
|
7900
|
+
);
|
|
7901
|
+
cloud.command("models").description("Models this organisation can run an agent on, cheapest first").option("--all", "Include models that need your own provider key").action(
|
|
7902
|
+
action(async ({ ctx, opts }) => {
|
|
7903
|
+
const res = await api(ctx, "/v1/agent-cloud/catalog/models/live");
|
|
7904
|
+
const models = (res?.models ?? []).filter(
|
|
7905
|
+
(m) => opts.all || m.credit_tier === "PLATFORM_CREDITS"
|
|
7906
|
+
);
|
|
7907
|
+
ok(res, () => {
|
|
7908
|
+
if (!models.length) {
|
|
7909
|
+
warn("The live model list could not be read.");
|
|
7910
|
+
return;
|
|
7911
|
+
}
|
|
7912
|
+
for (const m of models.slice(0, 40)) {
|
|
7913
|
+
const price = typeof m.input_price_per_million_usd === "number" ? `$${m.input_price_per_million_usd.toFixed(2)}/M in` : "price unknown";
|
|
7914
|
+
const byok = m.credit_tier === "PLATFORM_CREDITS" ? "" : import_picocolors17.default.yellow(" needs your own key");
|
|
7915
|
+
line(`${import_picocolors17.default.bold(m.id)} ${import_picocolors17.default.dim(price)}${byok}`);
|
|
7916
|
+
}
|
|
7917
|
+
});
|
|
7918
|
+
})
|
|
7919
|
+
);
|
|
7920
|
+
}
|
|
7921
|
+
function printRun(run, compact = false) {
|
|
7922
|
+
const status = String(run?.status ?? "").toLowerCase();
|
|
7923
|
+
const colour2 = status === "completed" ? import_picocolors17.default.green : status === "failed" ? import_picocolors17.default.red : import_picocolors17.default.yellow;
|
|
7924
|
+
line(
|
|
7925
|
+
`${colour2(status || "unknown")} ${import_picocolors17.default.bold(run?.id ?? "")}` + (run?.duration_ms ? ` ${import_picocolors17.default.dim(formatDuration(run.duration_ms))}` : "")
|
|
7926
|
+
);
|
|
7927
|
+
const breakdown = run?.cost_breakdown;
|
|
7928
|
+
if (breakdown) {
|
|
7929
|
+
if (!breakdown.settled) {
|
|
7930
|
+
line(" " + import_picocolors17.default.dim("cost: still being worked out"));
|
|
7931
|
+
} else {
|
|
7932
|
+
line(" " + import_picocolors17.default.dim(`cost: $${Number(breakdown.total_usd).toFixed(4)}`));
|
|
7933
|
+
line(
|
|
7934
|
+
" " + import_picocolors17.default.dim(
|
|
7935
|
+
`model $${Number(breakdown.model_usd).toFixed(4)} \xB7 infrastructure $${Number(breakdown.infrastructure_usd).toFixed(4)}`
|
|
7936
|
+
)
|
|
7937
|
+
);
|
|
7938
|
+
}
|
|
7939
|
+
} else if (run?.cost_usd !== void 0 && run?.cost_usd !== null) {
|
|
7940
|
+
line(" " + import_picocolors17.default.dim(`model cost: $${Number(run.cost_usd).toFixed(4)}`));
|
|
7941
|
+
}
|
|
7942
|
+
if (!compact && run?.output) {
|
|
7943
|
+
line("");
|
|
7944
|
+
line(typeof run.output === "string" ? run.output : JSON.stringify(run.output, null, 2));
|
|
7945
|
+
}
|
|
7946
|
+
if (run?.error?.message) line(" " + import_picocolors17.default.red(run.error.message));
|
|
7947
|
+
}
|
|
7948
|
+
function formatDuration(ms) {
|
|
7949
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
7950
|
+
const seconds = Math.round(ms / 1e3);
|
|
7951
|
+
if (seconds < 60) return `${seconds}s`;
|
|
7952
|
+
const minutes = Math.floor(seconds / 60);
|
|
7953
|
+
return `${minutes}m ${seconds % 60}s`;
|
|
7954
|
+
}
|
|
7955
|
+
function parsePairs(pairs, allowed) {
|
|
7956
|
+
const out = {};
|
|
7957
|
+
for (const raw of pairs) {
|
|
7958
|
+
const at = raw.indexOf("=");
|
|
7959
|
+
if (at < 1) {
|
|
7960
|
+
throw new Error(`"${raw}" is not a key=value pair.`);
|
|
7961
|
+
}
|
|
7962
|
+
const key = raw.slice(0, at).trim();
|
|
7963
|
+
const value = raw.slice(at + 1);
|
|
7964
|
+
if (!allowed.includes(key)) {
|
|
7965
|
+
throw new Error(`"${key}" is not a field here. Accepted: ${allowed.join(", ")}`);
|
|
7966
|
+
}
|
|
7967
|
+
if (value) out[key] = value;
|
|
7968
|
+
}
|
|
7969
|
+
return out;
|
|
7970
|
+
}
|
|
7971
|
+
|
|
7972
|
+
// src/commands/verify.ts
|
|
7973
|
+
var import_picocolors18 = __toESM(require_picocolors(), 1);
|
|
7464
7974
|
function registerVerify(program3) {
|
|
7465
7975
|
program3.command("verify").description(
|
|
7466
7976
|
"Run the project's checks (typecheck/lint/build) \u2014 use before declaring a task done"
|
|
@@ -7482,23 +7992,23 @@ function registerVerify(program3) {
|
|
|
7482
7992
|
function printVerify(res) {
|
|
7483
7993
|
if (!res) return;
|
|
7484
7994
|
if (!res.checks?.length) {
|
|
7485
|
-
line(
|
|
7995
|
+
line(import_picocolors18.default.dim(res.note ?? "No checks detected."));
|
|
7486
7996
|
return;
|
|
7487
7997
|
}
|
|
7488
7998
|
for (const c of res.checks) {
|
|
7489
7999
|
line(
|
|
7490
|
-
` ${c.ok ?
|
|
8000
|
+
` ${c.ok ? import_picocolors18.default.green("\u2713") : import_picocolors18.default.red("\u2717")} ${c.name}${c.ok ? "" : import_picocolors18.default.dim(` (exit ${c.exitCode})`)}`
|
|
7491
8001
|
);
|
|
7492
8002
|
}
|
|
7493
8003
|
if (res.ok) success("All checks passed");
|
|
7494
8004
|
else
|
|
7495
8005
|
line(
|
|
7496
|
-
|
|
8006
|
+
import_picocolors18.default.red("Some checks failed \u2014 fix the errors above and re-run ") + import_picocolors18.default.bold("workser verify") + import_picocolors18.default.red(".")
|
|
7497
8007
|
);
|
|
7498
8008
|
}
|
|
7499
8009
|
|
|
7500
8010
|
// src/commands/checkpoint.ts
|
|
7501
|
-
var
|
|
8011
|
+
var import_picocolors19 = __toESM(require_picocolors(), 1);
|
|
7502
8012
|
function registerCheckpoint(program3) {
|
|
7503
8013
|
program3.command("checkpoint [label]").description(
|
|
7504
8014
|
"Save the current state of this folder so you can come back to it"
|
|
@@ -7515,8 +8025,8 @@ function registerCheckpoint(program3) {
|
|
|
7515
8025
|
ok(res, () => {
|
|
7516
8026
|
const p = res?.point;
|
|
7517
8027
|
success(`Saved a checkpoint${p?.label ? `: ${p.label}` : ""}`);
|
|
7518
|
-
if (p?.ref) line(
|
|
7519
|
-
line(
|
|
8028
|
+
if (p?.ref) line(import_picocolors19.default.dim(` ${p.ref.slice(0, 7)}`));
|
|
8029
|
+
line(import_picocolors19.default.dim(" Come back to it with `workser restore`."));
|
|
7520
8030
|
});
|
|
7521
8031
|
})
|
|
7522
8032
|
);
|
|
@@ -7542,12 +8052,12 @@ function registerCheckpoint(program3) {
|
|
|
7542
8052
|
);
|
|
7543
8053
|
if (res?.filesChanged) {
|
|
7544
8054
|
line(
|
|
7545
|
-
|
|
8055
|
+
import_picocolors19.default.dim(
|
|
7546
8056
|
` ${res.filesChanged} file${res.filesChanged === 1 ? "" : "s"} changed`
|
|
7547
8057
|
)
|
|
7548
8058
|
);
|
|
7549
8059
|
}
|
|
7550
|
-
line(
|
|
8060
|
+
line(import_picocolors19.default.dim(" This is reversible: `workser restore` again."));
|
|
7551
8061
|
});
|
|
7552
8062
|
})
|
|
7553
8063
|
);
|
|
@@ -7564,25 +8074,25 @@ function registerCheckpoint(program3) {
|
|
|
7564
8074
|
function printPoints(points) {
|
|
7565
8075
|
if (!points.length) {
|
|
7566
8076
|
info("No checkpoints yet for this folder.");
|
|
7567
|
-
line(
|
|
8077
|
+
line(import_picocolors19.default.dim(" Take one with `workser checkpoint`."));
|
|
7568
8078
|
return;
|
|
7569
8079
|
}
|
|
7570
|
-
line(
|
|
8080
|
+
line(import_picocolors19.default.bold("Checkpoints"));
|
|
7571
8081
|
for (const p of points) {
|
|
7572
8082
|
const when = p.at ? new Date(p.at).toLocaleString() : "";
|
|
7573
8083
|
line(
|
|
7574
|
-
` ${
|
|
8084
|
+
` ${import_picocolors19.default.dim(p.ref.slice(0, 7))} ${p.label}${when ? import_picocolors19.default.dim(` ${when}`) : ""}`
|
|
7575
8085
|
);
|
|
7576
8086
|
}
|
|
7577
8087
|
line(
|
|
7578
|
-
|
|
8088
|
+
import_picocolors19.default.dim(
|
|
7579
8089
|
"\nGo back with `workser restore <ref>`, or just `workser restore` for the newest."
|
|
7580
8090
|
)
|
|
7581
8091
|
);
|
|
7582
8092
|
}
|
|
7583
8093
|
|
|
7584
8094
|
// src/commands/sync.ts
|
|
7585
|
-
var
|
|
8095
|
+
var import_picocolors20 = __toESM(require_picocolors(), 1);
|
|
7586
8096
|
function registerSync(program3) {
|
|
7587
8097
|
program3.command("sync").description(
|
|
7588
8098
|
"Reconcile this folder with the copy Workser holds (pull, then push)"
|
|
@@ -7609,7 +8119,7 @@ function registerSync(program3) {
|
|
|
7609
8119
|
warn(res?.message ?? "Couldn't sync this folder.");
|
|
7610
8120
|
if (res?.state === "diverged") {
|
|
7611
8121
|
line(
|
|
7612
|
-
|
|
8122
|
+
import_picocolors20.default.dim(
|
|
7613
8123
|
" This folder and Workser's copy have both changed. Open Workser to resolve it."
|
|
7614
8124
|
)
|
|
7615
8125
|
);
|
|
@@ -7621,7 +8131,7 @@ function registerSync(program3) {
|
|
|
7621
8131
|
return;
|
|
7622
8132
|
}
|
|
7623
8133
|
success("Synced");
|
|
7624
|
-
if (res?.ref) line(
|
|
8134
|
+
if (res?.ref) line(import_picocolors20.default.dim(` ${String(res.ref).slice(0, 7)}`));
|
|
7625
8135
|
});
|
|
7626
8136
|
if (refused) process.exitCode = 1;
|
|
7627
8137
|
})
|
|
@@ -7629,7 +8139,7 @@ function registerSync(program3) {
|
|
|
7629
8139
|
}
|
|
7630
8140
|
|
|
7631
8141
|
// src/commands/workflow.ts
|
|
7632
|
-
var
|
|
8142
|
+
var import_picocolors21 = __toESM(require_picocolors(), 1);
|
|
7633
8143
|
function registerWorkflow(program3) {
|
|
7634
8144
|
const wf = program3.command("workflow").description("Create, run, and inspect workflow automations for the project");
|
|
7635
8145
|
wf.command("list").description("List the project's workflows").action(
|
|
@@ -7637,10 +8147,10 @@ function registerWorkflow(program3) {
|
|
|
7637
8147
|
const projectId = requireProject(ctx);
|
|
7638
8148
|
const items = await api(ctx, `/v1/projects/${projectId}/workflows`);
|
|
7639
8149
|
ok(items, () => {
|
|
7640
|
-
if (!items?.length) return line(
|
|
8150
|
+
if (!items?.length) return line(import_picocolors21.default.dim("No workflows yet. `workser workflow create`."));
|
|
7641
8151
|
for (const w of items) {
|
|
7642
|
-
const status = w.is_active ?
|
|
7643
|
-
line(`${w.id} ${
|
|
8152
|
+
const status = w.is_active ? import_picocolors21.default.green("active") : import_picocolors21.default.dim("inactive");
|
|
8153
|
+
line(`${w.id} ${import_picocolors21.default.bold(w.name ?? "Untitled")} ${status}`);
|
|
7644
8154
|
}
|
|
7645
8155
|
});
|
|
7646
8156
|
})
|
|
@@ -7652,7 +8162,7 @@ function registerWorkflow(program3) {
|
|
|
7652
8162
|
const res = await api(ctx, `/v1/projects/${projectId}/workflows`, {
|
|
7653
8163
|
body: { name: args[0], ...extra }
|
|
7654
8164
|
});
|
|
7655
|
-
ok(res, () => line(`Created workflow ${
|
|
8165
|
+
ok(res, () => line(`Created workflow ${import_picocolors21.default.bold(res.id)}.`));
|
|
7656
8166
|
})
|
|
7657
8167
|
);
|
|
7658
8168
|
wf.command("get <id>").description("Show a workflow's full definition").action(
|
|
@@ -7687,8 +8197,8 @@ function registerWorkflow(program3) {
|
|
|
7687
8197
|
action(async ({ ctx, args }) => {
|
|
7688
8198
|
const items = await api(ctx, `/v1/workflows/${args[0]}/executions`);
|
|
7689
8199
|
ok(items, () => {
|
|
7690
|
-
if (!items?.length) return line(
|
|
7691
|
-
for (const e of items) line(`${e.id} ${e.status ?? ""} ${
|
|
8200
|
+
if (!items?.length) return line(import_picocolors21.default.dim("No runs yet."));
|
|
8201
|
+
for (const e of items) line(`${e.id} ${e.status ?? ""} ${import_picocolors21.default.dim(e.started_at ?? "")}`);
|
|
7692
8202
|
});
|
|
7693
8203
|
})
|
|
7694
8204
|
);
|
|
@@ -7696,15 +8206,15 @@ function registerWorkflow(program3) {
|
|
|
7696
8206
|
action(async ({ ctx, args }) => {
|
|
7697
8207
|
const items = await api(ctx, `/v1/node-types`, { query: { q: args[0] } });
|
|
7698
8208
|
ok(items, () => {
|
|
7699
|
-
if (!items?.length) return line(
|
|
7700
|
-
for (const n of items) line(`${n.name ?? n.type} ${
|
|
8209
|
+
if (!items?.length) return line(import_picocolors21.default.dim("No matching node types."));
|
|
8210
|
+
for (const n of items) line(`${n.name ?? n.type} ${import_picocolors21.default.dim(n.category ?? "")}`);
|
|
7701
8211
|
});
|
|
7702
8212
|
})
|
|
7703
8213
|
);
|
|
7704
8214
|
}
|
|
7705
8215
|
|
|
7706
8216
|
// src/commands/connection.ts
|
|
7707
|
-
var
|
|
8217
|
+
var import_picocolors22 = __toESM(require_picocolors(), 1);
|
|
7708
8218
|
function registerConnection(program3) {
|
|
7709
8219
|
const connection = program3.command("connection").description("Connect and use third-party app connections (Gmail, Slack, Stripe, ...)");
|
|
7710
8220
|
connection.command("list").description("List connectable toolkits and this project's existing connections").option("--toolkit <slug>", "filter connections to one toolkit").action(
|
|
@@ -7717,8 +8227,8 @@ function registerConnection(program3) {
|
|
|
7717
8227
|
ok({ catalog, connections }, () => {
|
|
7718
8228
|
const connected = new Set((connections ?? []).map((c) => c.toolkit ?? c.composio_app));
|
|
7719
8229
|
for (const t of catalog ?? []) {
|
|
7720
|
-
const status = connected.has(t.slug) ?
|
|
7721
|
-
line(`${t.slug} ${
|
|
8230
|
+
const status = connected.has(t.slug) ? import_picocolors22.default.green("connected") : import_picocolors22.default.dim("not connected");
|
|
8231
|
+
line(`${t.slug} ${import_picocolors22.default.bold(t.name ?? t.slug)} ${status}`);
|
|
7722
8232
|
}
|
|
7723
8233
|
});
|
|
7724
8234
|
})
|
|
@@ -7730,9 +8240,9 @@ function registerConnection(program3) {
|
|
|
7730
8240
|
query: { q: args[0], toolkit: opts.toolkit, limit: opts.limit }
|
|
7731
8241
|
});
|
|
7732
8242
|
ok(items, () => {
|
|
7733
|
-
if (!items?.length) return line(
|
|
8243
|
+
if (!items?.length) return line(import_picocolors22.default.dim("No matching actions."));
|
|
7734
8244
|
for (const t of items) {
|
|
7735
|
-
line(`${t.slug} ${
|
|
8245
|
+
line(`${t.slug} ${import_picocolors22.default.dim(`[${t.toolkit}]`)} ${t.description ?? ""}`);
|
|
7736
8246
|
}
|
|
7737
8247
|
});
|
|
7738
8248
|
})
|
|
@@ -7749,7 +8259,7 @@ function registerConnection(program3) {
|
|
|
7749
8259
|
});
|
|
7750
8260
|
ok(
|
|
7751
8261
|
res,
|
|
7752
|
-
() => res.oauth_url ? line(`Open this URL to finish connecting: ${
|
|
8262
|
+
() => res.oauth_url ? line(`Open this URL to finish connecting: ${import_picocolors22.default.underline(res.oauth_url)}`) : line(`Connection ${res.connection_id} is ${res.status}.`)
|
|
7753
8263
|
);
|
|
7754
8264
|
})
|
|
7755
8265
|
);
|
|
@@ -7767,8 +8277,8 @@ function registerConnection(program3) {
|
|
|
7767
8277
|
const projectId = requireProject(ctx);
|
|
7768
8278
|
const items = await api(ctx, `/v1/projects/${projectId}/integrations/${args[0]}/tools`);
|
|
7769
8279
|
ok(items, () => {
|
|
7770
|
-
if (!items?.length) return line(
|
|
7771
|
-
for (const t of items) line(`${t.slug} ${
|
|
8280
|
+
if (!items?.length) return line(import_picocolors22.default.dim("No tools found."));
|
|
8281
|
+
for (const t of items) line(`${t.slug} ${import_picocolors22.default.dim(t.description ?? "")}`);
|
|
7772
8282
|
});
|
|
7773
8283
|
})
|
|
7774
8284
|
);
|
|
@@ -7784,7 +8294,7 @@ function registerConnection(program3) {
|
|
|
7784
8294
|
}
|
|
7785
8295
|
|
|
7786
8296
|
// src/commands/tool.ts
|
|
7787
|
-
var
|
|
8297
|
+
var import_picocolors23 = __toESM(require_picocolors(), 1);
|
|
7788
8298
|
function registerTool(program3) {
|
|
7789
8299
|
const tool = program3.command("tool").description(
|
|
7790
8300
|
"Computer-use tools: filesystem, shell, screenshot, input control, clipboard, notifications, basic browser"
|
|
@@ -7793,7 +8303,7 @@ function registerTool(program3) {
|
|
|
7793
8303
|
action(async ({ ctx }) => {
|
|
7794
8304
|
const tools = await api(ctx, "/v1/tool/list");
|
|
7795
8305
|
ok(tools, () => {
|
|
7796
|
-
if (!tools?.length) return line(
|
|
8306
|
+
if (!tools?.length) return line(import_picocolors23.default.dim("No tools available."));
|
|
7797
8307
|
const byCategory = /* @__PURE__ */ new Map();
|
|
7798
8308
|
for (const t of tools) {
|
|
7799
8309
|
const list = byCategory.get(t.category) ?? [];
|
|
@@ -7801,9 +8311,9 @@ function registerTool(program3) {
|
|
|
7801
8311
|
byCategory.set(t.category, list);
|
|
7802
8312
|
}
|
|
7803
8313
|
for (const [category, items] of byCategory) {
|
|
7804
|
-
line(
|
|
8314
|
+
line(import_picocolors23.default.bold(category) + ":");
|
|
7805
8315
|
for (const t of items) {
|
|
7806
|
-
line(` ${t.name} ${
|
|
8316
|
+
line(` ${t.name} ${import_picocolors23.default.dim(t.description ?? "")}`);
|
|
7807
8317
|
}
|
|
7808
8318
|
}
|
|
7809
8319
|
});
|
|
@@ -7821,7 +8331,7 @@ function registerTool(program3) {
|
|
|
7821
8331
|
}
|
|
7822
8332
|
|
|
7823
8333
|
// src/commands/memory.ts
|
|
7824
|
-
var
|
|
8334
|
+
var import_picocolors24 = __toESM(require_picocolors(), 1);
|
|
7825
8335
|
function registerMemory(program3) {
|
|
7826
8336
|
const memory = program3.command("memory").description("Durable, cross-conversation project memory (shared with cloud agents on the same project)");
|
|
7827
8337
|
memory.command("add <content>").description("Store something worth remembering across future conversations").option("--metadata <json>", "extra metadata for filtering, as a JSON string").option("--id <customId>", "custom id for dedup/updates").action(
|
|
@@ -7845,9 +8355,9 @@ function registerMemory(program3) {
|
|
|
7845
8355
|
});
|
|
7846
8356
|
ok(res, () => {
|
|
7847
8357
|
const results = res?.results ?? res ?? [];
|
|
7848
|
-
if (!results?.length) return line(
|
|
8358
|
+
if (!results?.length) return line(import_picocolors24.default.dim("No matching memories."));
|
|
7849
8359
|
for (const r of results) {
|
|
7850
|
-
line(`${
|
|
8360
|
+
line(`${import_picocolors24.default.dim(r.id ?? "?")} ${memoryText(r)}`);
|
|
7851
8361
|
}
|
|
7852
8362
|
});
|
|
7853
8363
|
})
|
|
@@ -7867,11 +8377,11 @@ function memoryText(r) {
|
|
|
7867
8377
|
if (typeof text === "string" && text.trim()) return text;
|
|
7868
8378
|
const title = r?.documents?.[0]?.title;
|
|
7869
8379
|
if (typeof title === "string" && title.trim()) return title;
|
|
7870
|
-
return
|
|
8380
|
+
return import_picocolors24.default.dim("(no readable text on this row)");
|
|
7871
8381
|
}
|
|
7872
8382
|
|
|
7873
8383
|
// src/commands/note.ts
|
|
7874
|
-
var
|
|
8384
|
+
var import_picocolors25 = __toESM(require_picocolors(), 1);
|
|
7875
8385
|
function registerNote(program3) {
|
|
7876
8386
|
program3.command("note <text>").description("Leave a fact the rest of the team will need").addHelpText(
|
|
7877
8387
|
"after",
|
|
@@ -7908,14 +8418,14 @@ function registerNote(program3) {
|
|
|
7908
8418
|
}
|
|
7909
8419
|
ok(res, () => {
|
|
7910
8420
|
success("Noted for the team.");
|
|
7911
|
-
line(
|
|
8421
|
+
line(import_picocolors25.default.dim(` ${text}`));
|
|
7912
8422
|
});
|
|
7913
8423
|
})
|
|
7914
8424
|
);
|
|
7915
8425
|
}
|
|
7916
8426
|
|
|
7917
8427
|
// src/commands/business.ts
|
|
7918
|
-
var
|
|
8428
|
+
var import_picocolors26 = __toESM(require_picocolors(), 1);
|
|
7919
8429
|
var RESOURCE_PATHS = {
|
|
7920
8430
|
"business-config": "business-config",
|
|
7921
8431
|
"business-settings": "business-settings",
|
|
@@ -7975,7 +8485,7 @@ function registerBusiness(program3) {
|
|
|
7975
8485
|
const projectId = requireProject(ctx);
|
|
7976
8486
|
const [resource] = args;
|
|
7977
8487
|
const res = await api(ctx, businessPath(projectId, resource), { body: JSON.parse(opts.body) });
|
|
7978
|
-
ok(res, () => line(`Created ${resource} ${
|
|
8488
|
+
ok(res, () => line(`Created ${resource} ${import_picocolors26.default.bold(res?.id ?? "")}.`));
|
|
7979
8489
|
})
|
|
7980
8490
|
);
|
|
7981
8491
|
biz.command("update <resource> <id>").description("Update a record by id (PATCH/PUT \u2014 matches the underlying route)").option("--body <json>", "changed fields as a JSON object string", "{}").action(
|
|
@@ -8017,7 +8527,7 @@ function businessPath(projectId, resource, subpath) {
|
|
|
8017
8527
|
}
|
|
8018
8528
|
|
|
8019
8529
|
// src/commands/artifact.ts
|
|
8020
|
-
var
|
|
8530
|
+
var import_picocolors27 = __toESM(require_picocolors(), 1);
|
|
8021
8531
|
import { existsSync as existsSync2, statSync } from "fs";
|
|
8022
8532
|
import { resolve as resolve3, basename as basename3 } from "path";
|
|
8023
8533
|
var KINDS = [
|
|
@@ -8114,7 +8624,7 @@ function registerArtifact(program3) {
|
|
|
8114
8624
|
ok(
|
|
8115
8625
|
res,
|
|
8116
8626
|
() => success(
|
|
8117
|
-
`Recorded ${
|
|
8627
|
+
`Recorded ${import_picocolors27.default.bold(res?.title ?? "artifact")}${res?.kind ? import_picocolors27.default.dim(` (${res.kind})`) : ""}`
|
|
8118
8628
|
)
|
|
8119
8629
|
);
|
|
8120
8630
|
})
|
|
@@ -8146,13 +8656,13 @@ function registerArtifact(program3) {
|
|
|
8146
8656
|
artifact.command("run").description("Show the task/conversation this agent run is attached to").action(
|
|
8147
8657
|
action(async ({ ctx }) => {
|
|
8148
8658
|
const res = await api(ctx, `/v1/runs/${runTarget(ctx)}`);
|
|
8149
|
-
ok(res, () =>
|
|
8659
|
+
ok(res, () => printRun2(res));
|
|
8150
8660
|
})
|
|
8151
8661
|
);
|
|
8152
8662
|
}
|
|
8153
8663
|
function printArtifacts(rows) {
|
|
8154
8664
|
if (!rows.length) {
|
|
8155
|
-
line(
|
|
8665
|
+
line(import_picocolors27.default.dim("Nothing produced yet."));
|
|
8156
8666
|
return;
|
|
8157
8667
|
}
|
|
8158
8668
|
const byStep = /* @__PURE__ */ new Map();
|
|
@@ -8162,26 +8672,26 @@ function printArtifacts(rows) {
|
|
|
8162
8672
|
byStep.set(r.subtask_id, list);
|
|
8163
8673
|
}
|
|
8164
8674
|
for (const [stepId, items] of byStep) {
|
|
8165
|
-
line(
|
|
8675
|
+
line(import_picocolors27.default.bold(`step ${stepId}`));
|
|
8166
8676
|
for (const a of items) {
|
|
8167
|
-
const flag = a.promoted_at ?
|
|
8677
|
+
const flag = a.promoted_at ? import_picocolors27.default.green(" *") : " ";
|
|
8168
8678
|
const where = a.local_path || a.cloud_url || "";
|
|
8169
8679
|
line(
|
|
8170
|
-
`${flag} ${
|
|
8680
|
+
`${flag} ${import_picocolors27.default.dim(`[${a.kind}]`)} ${a.title ?? "(untitled)"}` + (where ? import_picocolors27.default.dim(` ${where}`) : "")
|
|
8171
8681
|
);
|
|
8172
|
-
if (a.description) line(
|
|
8682
|
+
if (a.description) line(import_picocolors27.default.dim(` ${a.description}`));
|
|
8173
8683
|
}
|
|
8174
8684
|
line("");
|
|
8175
8685
|
}
|
|
8176
|
-
line(
|
|
8686
|
+
line(import_picocolors27.default.dim("* = handed over as a deliverable; the rest is working material."));
|
|
8177
8687
|
}
|
|
8178
|
-
function
|
|
8688
|
+
function printRun2(run) {
|
|
8179
8689
|
if (!run) return;
|
|
8180
|
-
line(` run ${
|
|
8690
|
+
line(` run ${import_picocolors27.default.bold(run.runId)}`);
|
|
8181
8691
|
if (run.taskId) line(` task ${run.taskId}`);
|
|
8182
8692
|
if (run.conversationId) line(` chat ${run.conversationId}`);
|
|
8183
8693
|
if (run.projectId) line(` project ${run.projectId}`);
|
|
8184
|
-
if (run.cwd) line(` folder ${
|
|
8694
|
+
if (run.cwd) line(` folder ${import_picocolors27.default.dim(run.cwd)}`);
|
|
8185
8695
|
}
|
|
8186
8696
|
|
|
8187
8697
|
// src/commands/image.ts
|
|
@@ -8259,7 +8769,7 @@ function registerImage(program3) {
|
|
|
8259
8769
|
);
|
|
8260
8770
|
const res = await api(
|
|
8261
8771
|
ctx,
|
|
8262
|
-
`/projects/${projectId}/images/generate`,
|
|
8772
|
+
`/v1/projects/${projectId}/images/generate`,
|
|
8263
8773
|
{
|
|
8264
8774
|
method: "POST",
|
|
8265
8775
|
body: {
|
|
@@ -8299,7 +8809,7 @@ function registerImage(program3) {
|
|
|
8299
8809
|
action(async ({ ctx, opts, args }) => {
|
|
8300
8810
|
const projectId = requireProject(ctx);
|
|
8301
8811
|
const source = await resolveMediaSource({ url: opts.url, file: opts.file });
|
|
8302
|
-
const res = await api(ctx, `/projects/${projectId}/images/understand`, {
|
|
8812
|
+
const res = await api(ctx, `/v1/projects/${projectId}/images/understand`, {
|
|
8303
8813
|
method: "POST",
|
|
8304
8814
|
body: { source, query: args[0], task: opts.task }
|
|
8305
8815
|
});
|
|
@@ -8332,7 +8842,7 @@ function registerVideo(program3) {
|
|
|
8332
8842
|
action(async ({ ctx, opts, args }) => {
|
|
8333
8843
|
const projectId = requireProject(ctx);
|
|
8334
8844
|
const source = await resolveMediaSource({ url: opts.url, file: opts.file });
|
|
8335
|
-
const res = await api(ctx, `/projects/${projectId}/video/understand`, {
|
|
8845
|
+
const res = await api(ctx, `/v1/projects/${projectId}/video/understand`, {
|
|
8336
8846
|
method: "POST",
|
|
8337
8847
|
body: { source, query: args[0], task: opts.task }
|
|
8338
8848
|
});
|
|
@@ -8352,7 +8862,7 @@ function registerAudio(program3) {
|
|
|
8352
8862
|
action(async ({ ctx, opts, args }) => {
|
|
8353
8863
|
const projectId = requireProject(ctx);
|
|
8354
8864
|
const source = await resolveMediaSource({ url: opts.url, file: opts.file });
|
|
8355
|
-
const res = await api(ctx, `/projects/${projectId}/audio/understand`, {
|
|
8865
|
+
const res = await api(ctx, `/v1/projects/${projectId}/audio/understand`, {
|
|
8356
8866
|
method: "POST",
|
|
8357
8867
|
body: { source, query: args[0], task: opts.task }
|
|
8358
8868
|
});
|
|
@@ -8362,7 +8872,7 @@ function registerAudio(program3) {
|
|
|
8362
8872
|
}
|
|
8363
8873
|
|
|
8364
8874
|
// src/commands/ask.ts
|
|
8365
|
-
var
|
|
8875
|
+
var import_picocolors28 = __toESM(require_picocolors(), 1);
|
|
8366
8876
|
var TYPES = [
|
|
8367
8877
|
"input",
|
|
8368
8878
|
"choice",
|
|
@@ -8440,7 +8950,7 @@ function registerAsk(program3) {
|
|
|
8440
8950
|
code: "bad_request"
|
|
8441
8951
|
});
|
|
8442
8952
|
}
|
|
8443
|
-
info(
|
|
8953
|
+
info(import_picocolors28.default.dim("Waiting for the user to answer\u2026"));
|
|
8444
8954
|
const res = await api(ctx, `/v1/runs/${runTarget(ctx)}/ask`, {
|
|
8445
8955
|
body: {
|
|
8446
8956
|
type,
|
|
@@ -8468,12 +8978,12 @@ function deriveTitle(message) {
|
|
|
8468
8978
|
function printAnswer(res) {
|
|
8469
8979
|
if (!res) return;
|
|
8470
8980
|
if (res.status === "answered") {
|
|
8471
|
-
line(` ${
|
|
8981
|
+
line(` ${import_picocolors28.default.green("answered")}`);
|
|
8472
8982
|
const value = extract(res.response);
|
|
8473
8983
|
if (value) line(` ${value}`);
|
|
8474
8984
|
return;
|
|
8475
8985
|
}
|
|
8476
|
-
line(` ${
|
|
8986
|
+
line(` ${import_picocolors28.default.yellow(res.status)} ${import_picocolors28.default.dim(res.reason ?? "")}`);
|
|
8477
8987
|
}
|
|
8478
8988
|
function extract(response) {
|
|
8479
8989
|
if (response == null) return "";
|
|
@@ -8492,7 +9002,7 @@ function extract(response) {
|
|
|
8492
9002
|
}
|
|
8493
9003
|
|
|
8494
9004
|
// src/commands/search.ts
|
|
8495
|
-
var
|
|
9005
|
+
var import_picocolors29 = __toESM(require_picocolors(), 1);
|
|
8496
9006
|
function registerSearch(program3) {
|
|
8497
9007
|
program3.command("search <query>").description("Search the web (Google-grounded, server-side)").option("-n, --max-results <n>", "max results", "5").action(
|
|
8498
9008
|
action(async ({ ctx, args, opts }) => {
|
|
@@ -8505,9 +9015,9 @@ function registerSearch(program3) {
|
|
|
8505
9015
|
line("");
|
|
8506
9016
|
}
|
|
8507
9017
|
const results = res?.results ?? [];
|
|
8508
|
-
if (!results.length) return line(
|
|
9018
|
+
if (!results.length) return line(import_picocolors29.default.dim("No results."));
|
|
8509
9019
|
for (const r of results) {
|
|
8510
|
-
line(`${r.title ||
|
|
9020
|
+
line(`${r.title || import_picocolors29.default.dim("(untitled)")} ${import_picocolors29.default.dim(r.url)}`);
|
|
8511
9021
|
}
|
|
8512
9022
|
});
|
|
8513
9023
|
})
|
|
@@ -8515,7 +9025,7 @@ function registerSearch(program3) {
|
|
|
8515
9025
|
}
|
|
8516
9026
|
|
|
8517
9027
|
// src/commands/board.ts
|
|
8518
|
-
var
|
|
9028
|
+
var import_picocolors30 = __toESM(require_picocolors(), 1);
|
|
8519
9029
|
|
|
8520
9030
|
// src/commands/record-step.ts
|
|
8521
9031
|
async function recordEntityStep(ctx, opts) {
|
|
@@ -8554,7 +9064,7 @@ function registerBoard(program3) {
|
|
|
8554
9064
|
}
|
|
8555
9065
|
ok(rows, () => {
|
|
8556
9066
|
if (!rows.length) {
|
|
8557
|
-
line(
|
|
9067
|
+
line(import_picocolors30.default.dim("No cards on the Board yet."));
|
|
8558
9068
|
return;
|
|
8559
9069
|
}
|
|
8560
9070
|
for (const r of rows) line(formatRow(r));
|
|
@@ -8569,7 +9079,7 @@ function registerBoard(program3) {
|
|
|
8569
9079
|
`/v1/projects/${projectId}/work-items/${args[0]}`
|
|
8570
9080
|
);
|
|
8571
9081
|
ok(row, () => {
|
|
8572
|
-
line(`${
|
|
9082
|
+
line(`${import_picocolors30.default.bold(row.title)} ${import_picocolors30.default.dim(row.id)}`);
|
|
8573
9083
|
line(`${statusTag(row.status)} priority ${row.priority}`);
|
|
8574
9084
|
if (row.ownerHuman) line(`owner: ${row.ownerHuman}`);
|
|
8575
9085
|
if (row.labels?.length) line(`labels: ${row.labels.join(", ")}`);
|
|
@@ -8610,7 +9120,7 @@ ${row.description}`);
|
|
|
8610
9120
|
refId: row?.id,
|
|
8611
9121
|
output: { workItem: row }
|
|
8612
9122
|
});
|
|
8613
|
-
ok(row, () => line(`Created work item ${
|
|
9123
|
+
ok(row, () => line(`Created work item ${import_picocolors30.default.bold(row?.id ?? "")} \u2014 ${title}`));
|
|
8614
9124
|
})
|
|
8615
9125
|
);
|
|
8616
9126
|
board.command("update <id>").description("Change fields on a card \u2014 pass only what changes").option("--title <text>", "new title").option("--description <text>", "new description").option("--status <value>", STATUSES.join(" | ")).option("--priority <value>", PRIORITIES.join(" | ")).option(
|
|
@@ -8644,7 +9154,7 @@ ${row.description}`);
|
|
|
8644
9154
|
);
|
|
8645
9155
|
}
|
|
8646
9156
|
const row = await patchItem(ctx, projectId, String(args[0]), body);
|
|
8647
|
-
ok(row, () => line(`Updated ${
|
|
9157
|
+
ok(row, () => line(`Updated ${import_picocolors30.default.bold(row.id)} \u2014 ${row.title} ${statusTag(row.status)}`));
|
|
8648
9158
|
})
|
|
8649
9159
|
);
|
|
8650
9160
|
board.command("move <id> <status>").description(
|
|
@@ -8655,14 +9165,14 @@ ${row.description}`);
|
|
|
8655
9165
|
const status = String(args[1]);
|
|
8656
9166
|
assertStatus(status);
|
|
8657
9167
|
const row = await patchItem(ctx, projectId, String(args[0]), { status });
|
|
8658
|
-
ok(row, () => line(`Moved ${
|
|
9168
|
+
ok(row, () => line(`Moved ${import_picocolors30.default.bold(row.title)} \u2192 ${statusTag(row.status)}`));
|
|
8659
9169
|
})
|
|
8660
9170
|
);
|
|
8661
9171
|
board.command("close <id>").description("Shorthand for `board move <id> done`").action(
|
|
8662
9172
|
action(async ({ ctx, args }) => {
|
|
8663
9173
|
const projectId = requireProject(ctx);
|
|
8664
9174
|
const row = await patchItem(ctx, projectId, String(args[0]), { status: "done" });
|
|
8665
|
-
ok(row, () => line(`Closed ${
|
|
9175
|
+
ok(row, () => line(`Closed ${import_picocolors30.default.bold(row.title)} ${statusTag(row.status)}`));
|
|
8666
9176
|
})
|
|
8667
9177
|
);
|
|
8668
9178
|
}
|
|
@@ -8695,23 +9205,23 @@ function assertPriority(value) {
|
|
|
8695
9205
|
}
|
|
8696
9206
|
}
|
|
8697
9207
|
function formatRow(r) {
|
|
8698
|
-
const labels = r.labels?.length ?
|
|
8699
|
-
const owner = r.ownerHuman ?
|
|
8700
|
-
return `${
|
|
9208
|
+
const labels = r.labels?.length ? import_picocolors30.default.dim(` [${r.labels.join(", ")}]`) : "";
|
|
9209
|
+
const owner = r.ownerHuman ? import_picocolors30.default.dim(` @${r.ownerHuman}`) : "";
|
|
9210
|
+
return `${import_picocolors30.default.dim(r.id)} ${statusTag(r.status)} ${r.title}${labels}${owner}`;
|
|
8701
9211
|
}
|
|
8702
9212
|
function statusTag(status) {
|
|
8703
9213
|
const label = status.padEnd(11);
|
|
8704
|
-
if (status === "done") return
|
|
8705
|
-
if (status === "in-progress") return
|
|
8706
|
-
if (status === "in-review") return
|
|
8707
|
-
return
|
|
9214
|
+
if (status === "done") return import_picocolors30.default.green(label);
|
|
9215
|
+
if (status === "in-progress") return import_picocolors30.default.yellow(label);
|
|
9216
|
+
if (status === "in-review") return import_picocolors30.default.cyan(label);
|
|
9217
|
+
return import_picocolors30.default.dim(label);
|
|
8708
9218
|
}
|
|
8709
9219
|
function collect2(value, previous) {
|
|
8710
9220
|
return [...previous, value];
|
|
8711
9221
|
}
|
|
8712
9222
|
|
|
8713
9223
|
// src/commands/task.ts
|
|
8714
|
-
var
|
|
9224
|
+
var import_picocolors31 = __toESM(require_picocolors(), 1);
|
|
8715
9225
|
|
|
8716
9226
|
// src/subtask-attachments.ts
|
|
8717
9227
|
var MAX_REF_NOTE = 500;
|
|
@@ -8773,6 +9283,7 @@ var STATUSES2 = [
|
|
|
8773
9283
|
];
|
|
8774
9284
|
var PRIORITIES2 = ["urgent", "high", "normal", "low"];
|
|
8775
9285
|
var SIZES = ["small", "standard"];
|
|
9286
|
+
var ESTIMATES = ["10m", "30m", "45m", "1h", "1h+"];
|
|
8776
9287
|
var ROLES = [
|
|
8777
9288
|
"pm",
|
|
8778
9289
|
"architect",
|
|
@@ -8825,7 +9336,7 @@ function registerTask(program3) {
|
|
|
8825
9336
|
}) ?? [];
|
|
8826
9337
|
ok(rows, () => {
|
|
8827
9338
|
if (!rows.length) {
|
|
8828
|
-
line(
|
|
9339
|
+
line(import_picocolors31.default.dim("No tasks on the board yet."));
|
|
8829
9340
|
return;
|
|
8830
9341
|
}
|
|
8831
9342
|
for (const r of rows) line(formatRow2(r));
|
|
@@ -8855,6 +9366,9 @@ function registerTask(program3) {
|
|
|
8855
9366
|
).option("--priority <value>", `how urgent (${PRIORITIES2.join(" | ")})`).option(
|
|
8856
9367
|
"--size <value>",
|
|
8857
9368
|
`small lets the channel start it without asking; standard asks (${SIZES.join(" | ")})`
|
|
9369
|
+
).option(
|
|
9370
|
+
"--estimate <value>",
|
|
9371
|
+
`roughly how long this should take, shown on the plan (${ESTIMATES.join(" | ")})`
|
|
8858
9372
|
).option(
|
|
8859
9373
|
"--status <value>",
|
|
8860
9374
|
`start it somewhere other than 'todo' \u2014 use 'backlog' for a later phase's work (${STATUSES2.join(" | ")})`
|
|
@@ -8865,6 +9379,8 @@ function registerTask(program3) {
|
|
|
8865
9379
|
if (opts.priority !== void 0)
|
|
8866
9380
|
assertOneOf("--priority", opts.priority, PRIORITIES2);
|
|
8867
9381
|
if (opts.size !== void 0) assertOneOf("--size", opts.size, SIZES);
|
|
9382
|
+
if (opts.estimate !== void 0)
|
|
9383
|
+
assertOneOf("--estimate", opts.estimate, ESTIMATES);
|
|
8868
9384
|
if (opts.status !== void 0)
|
|
8869
9385
|
assertOneOf("--status", opts.status, STATUSES2);
|
|
8870
9386
|
const hasChannelOrigin = Boolean(
|
|
@@ -8882,6 +9398,7 @@ function registerTask(program3) {
|
|
|
8882
9398
|
phase: opts.phase,
|
|
8883
9399
|
priority: opts.priority,
|
|
8884
9400
|
size: opts.size,
|
|
9401
|
+
estimate: opts.estimate,
|
|
8885
9402
|
// `backlog` for a later phase's work: written down so the owner can
|
|
8886
9403
|
// read the whole plan, with nothing for the runner to pick up.
|
|
8887
9404
|
status: opts.status,
|
|
@@ -8934,10 +9451,10 @@ function registerTask(program3) {
|
|
|
8934
9451
|
};
|
|
8935
9452
|
ok(result, () => {
|
|
8936
9453
|
line(
|
|
8937
|
-
`${
|
|
9454
|
+
`${import_picocolors31.default.green("opened")} ${import_picocolors31.default.bold(row.title)} ${import_picocolors31.default.dim(row.key ?? row.id)}`
|
|
8938
9455
|
);
|
|
8939
9456
|
if (channelMessage)
|
|
8940
|
-
line(
|
|
9457
|
+
line(import_picocolors31.default.dim("posted to the channel as Project Manager"));
|
|
8941
9458
|
if (channelMessageError) {
|
|
8942
9459
|
warn(
|
|
8943
9460
|
`Task opened, but its Project Manager card could not be posted: ${channelMessageError.message}`
|
|
@@ -9016,12 +9533,12 @@ function registerTask(program3) {
|
|
|
9016
9533
|
) : null;
|
|
9017
9534
|
ok(runner ?? row, () => {
|
|
9018
9535
|
line(
|
|
9019
|
-
`${
|
|
9536
|
+
`${import_picocolors31.default.green("added")} ${import_picocolors31.default.bold(row.title)} ${import_picocolors31.default.dim(row.key ?? row.id)}`
|
|
9020
9537
|
);
|
|
9021
|
-
if (row.role) line(
|
|
9538
|
+
if (row.role) line(import_picocolors31.default.dim(`role: ${row.role}`));
|
|
9022
9539
|
if (runner) {
|
|
9023
9540
|
line(
|
|
9024
|
-
|
|
9541
|
+
import_picocolors31.default.dim(
|
|
9025
9542
|
`runs on: ${[opts.agent, opts.model, opts.effort].filter(Boolean).join(" \xB7 ")}`
|
|
9026
9543
|
)
|
|
9027
9544
|
);
|
|
@@ -9039,7 +9556,7 @@ function registerTask(program3) {
|
|
|
9039
9556
|
const rows = row.subtasks ?? [];
|
|
9040
9557
|
ok(rows, () => {
|
|
9041
9558
|
if (!rows.length) {
|
|
9042
|
-
line(
|
|
9559
|
+
line(import_picocolors31.default.dim("No subtasks yet."));
|
|
9043
9560
|
return;
|
|
9044
9561
|
}
|
|
9045
9562
|
rows.forEach((r, i) => line(formatSubtask(r, i + 1)));
|
|
@@ -9087,7 +9604,7 @@ function registerTask(program3) {
|
|
|
9087
9604
|
}
|
|
9088
9605
|
}
|
|
9089
9606
|
);
|
|
9090
|
-
ok(row, () => line(`${
|
|
9607
|
+
ok(row, () => line(`${import_picocolors31.default.green("updated")} ${import_picocolors31.default.bold(row.title)}`));
|
|
9091
9608
|
})
|
|
9092
9609
|
);
|
|
9093
9610
|
subtask.command("remove <id>").description("Remove a subtask (only before the work starts)").action(
|
|
@@ -9095,7 +9612,7 @@ function registerTask(program3) {
|
|
|
9095
9612
|
await api(ctx, `/v1/project-tasks/${encodeURIComponent(args[0])}`, {
|
|
9096
9613
|
method: "DELETE"
|
|
9097
9614
|
});
|
|
9098
|
-
ok({ removed: args[0] }, () => line(
|
|
9615
|
+
ok({ removed: args[0] }, () => line(import_picocolors31.default.green("removed")));
|
|
9099
9616
|
})
|
|
9100
9617
|
);
|
|
9101
9618
|
task.command("move <id> <status>").description(
|
|
@@ -9110,7 +9627,7 @@ function registerTask(program3) {
|
|
|
9110
9627
|
);
|
|
9111
9628
|
ok(
|
|
9112
9629
|
row,
|
|
9113
|
-
() => line(`${
|
|
9630
|
+
() => line(`${import_picocolors31.default.green("moved")} ${import_picocolors31.default.bold(row.title)} \u2192 ${args[1]}`)
|
|
9114
9631
|
);
|
|
9115
9632
|
})
|
|
9116
9633
|
);
|
|
@@ -9126,18 +9643,18 @@ function registerTask(program3) {
|
|
|
9126
9643
|
);
|
|
9127
9644
|
ok(row, () => {
|
|
9128
9645
|
if (!row?.queued) {
|
|
9129
|
-
line(
|
|
9646
|
+
line(import_picocolors31.default.yellow("could not resume it \u2014 check the step id"));
|
|
9130
9647
|
return;
|
|
9131
9648
|
}
|
|
9132
9649
|
const started = row.started ?? 0;
|
|
9133
9650
|
if (started > 0) {
|
|
9134
9651
|
line(
|
|
9135
|
-
`${
|
|
9652
|
+
`${import_picocolors31.default.green("resumed")} \u2014 ${started} step${started === 1 ? "" : "s"} started`
|
|
9136
9653
|
);
|
|
9137
9654
|
return;
|
|
9138
9655
|
}
|
|
9139
9656
|
line(
|
|
9140
|
-
`${
|
|
9657
|
+
`${import_picocolors31.default.green("resumed")} \u2014 it is queued, but nothing started yet. Check the plan is approved and that no step is blocking the rest.`
|
|
9141
9658
|
);
|
|
9142
9659
|
});
|
|
9143
9660
|
})
|
|
@@ -9151,11 +9668,11 @@ function registerTask(program3) {
|
|
|
9151
9668
|
);
|
|
9152
9669
|
ok(row, () => {
|
|
9153
9670
|
if (row?.reopened) {
|
|
9154
|
-
line(`${
|
|
9671
|
+
line(`${import_picocolors31.default.green("sent back")} \u2014 it will be picked up again`);
|
|
9155
9672
|
return;
|
|
9156
9673
|
}
|
|
9157
9674
|
line(
|
|
9158
|
-
|
|
9675
|
+
import_picocolors31.default.yellow(
|
|
9159
9676
|
row?.reason === "already_open" ? "already waiting to be picked up \u2014 nothing to send back" : row?.reason === "still_working" ? "still working \u2014 let it finish before sending it back" : "could not send that step back"
|
|
9160
9677
|
)
|
|
9161
9678
|
);
|
|
@@ -9172,7 +9689,7 @@ function registerTask(program3) {
|
|
|
9172
9689
|
`/v1/project-tasks/${encodeURIComponent(id)}/dispatch-check`,
|
|
9173
9690
|
{ method: "POST" }
|
|
9174
9691
|
);
|
|
9175
|
-
ok(row, () => line(
|
|
9692
|
+
ok(row, () => line(import_picocolors31.default.green("approved \u2014 you may start")));
|
|
9176
9693
|
})
|
|
9177
9694
|
);
|
|
9178
9695
|
task.command("start [id]").description(
|
|
@@ -9187,13 +9704,13 @@ function registerTask(program3) {
|
|
|
9187
9704
|
const started = row?.started ?? null;
|
|
9188
9705
|
if (started && started > 0) {
|
|
9189
9706
|
line(
|
|
9190
|
-
|
|
9707
|
+
import_picocolors31.default.green(
|
|
9191
9708
|
`started ${started} step${started === 1 ? "" : "s"} \u2014 they are running now`
|
|
9192
9709
|
)
|
|
9193
9710
|
);
|
|
9194
9711
|
return;
|
|
9195
9712
|
}
|
|
9196
|
-
line(
|
|
9713
|
+
line(import_picocolors31.default.yellow(row?.note ?? "Nothing started."));
|
|
9197
9714
|
});
|
|
9198
9715
|
})
|
|
9199
9716
|
);
|
|
@@ -9208,7 +9725,7 @@ function registerTask(program3) {
|
|
|
9208
9725
|
);
|
|
9209
9726
|
ok({ awaiting: row2.approval_state === "awaiting", task: row2 }, () => {
|
|
9210
9727
|
line(
|
|
9211
|
-
row2.approval_state === "awaiting" ?
|
|
9728
|
+
row2.approval_state === "awaiting" ? import_picocolors31.default.yellow(
|
|
9212
9729
|
"The plan is waiting on the owner. They see it in the task."
|
|
9213
9730
|
) : `Already ${row2.approval_state}.`
|
|
9214
9731
|
);
|
|
@@ -9233,7 +9750,7 @@ function registerTask(program3) {
|
|
|
9233
9750
|
);
|
|
9234
9751
|
ok(
|
|
9235
9752
|
row,
|
|
9236
|
-
() => line(`${
|
|
9753
|
+
() => line(`${import_picocolors31.default.green(row.approval_state)} ${import_picocolors31.default.bold(row.title)}`)
|
|
9237
9754
|
);
|
|
9238
9755
|
})
|
|
9239
9756
|
);
|
|
@@ -9249,7 +9766,7 @@ function registerTask(program3) {
|
|
|
9249
9766
|
`/v1/project-tasks/${encodeURIComponent(id)}/move`,
|
|
9250
9767
|
{ body: { status: "ready" } }
|
|
9251
9768
|
);
|
|
9252
|
-
ok(row, () => line(`${
|
|
9769
|
+
ok(row, () => line(`${import_picocolors31.default.green("ready")} ${import_picocolors31.default.bold(row.title)}`));
|
|
9253
9770
|
})
|
|
9254
9771
|
);
|
|
9255
9772
|
}
|
|
@@ -9294,24 +9811,24 @@ function assertOneOf(flag, value, allowed) {
|
|
|
9294
9811
|
}
|
|
9295
9812
|
}
|
|
9296
9813
|
function formatRow2(r) {
|
|
9297
|
-
const key =
|
|
9298
|
-
const steps = r.subtaskTotal ?
|
|
9299
|
-
const gate = r.approval_state === "awaiting" ?
|
|
9814
|
+
const key = import_picocolors31.default.dim((r.key ?? r.id.slice(0, 8)).padEnd(10));
|
|
9815
|
+
const steps = r.subtaskTotal ? import_picocolors31.default.dim(` ${r.subtaskDone}/${r.subtaskTotal}`) : "";
|
|
9816
|
+
const gate = r.approval_state === "awaiting" ? import_picocolors31.default.yellow(" awaiting approval") : "";
|
|
9300
9817
|
return `${key} ${statusTag2(r.status)} ${r.title}${steps}${gate}`;
|
|
9301
9818
|
}
|
|
9302
9819
|
function formatSubtask(r, index) {
|
|
9303
|
-
const n =
|
|
9304
|
-
const role = r.role ?
|
|
9305
|
-
const scope = r.scope_paths?.length ?
|
|
9820
|
+
const n = import_picocolors31.default.dim(String(index).padStart(2, "0"));
|
|
9821
|
+
const role = r.role ? import_picocolors31.default.dim(` [${r.role}]`) : "";
|
|
9822
|
+
const scope = r.scope_paths?.length ? import_picocolors31.default.dim(` owns: ${r.scope_paths.join(", ")}`) : "";
|
|
9306
9823
|
const head = `${n} ${statusTag2(r.status)} ${r.title}${role}${scope}`;
|
|
9307
9824
|
const summary = (r.result_summary ?? "").trim();
|
|
9308
9825
|
if (!summary) return head;
|
|
9309
9826
|
const wrapped = summary.split("\n").map((l) => ` ${l}`).join("\n");
|
|
9310
9827
|
return `${head}
|
|
9311
|
-
${
|
|
9828
|
+
${import_picocolors31.default.dim(wrapped)}`;
|
|
9312
9829
|
}
|
|
9313
9830
|
function printTask(row, goal) {
|
|
9314
|
-
line(`${
|
|
9831
|
+
line(`${import_picocolors31.default.bold(row.title)} ${import_picocolors31.default.dim(row.key ?? row.id)}`);
|
|
9315
9832
|
line(`${statusTag2(row.status)} approval: ${row.approval_state}`);
|
|
9316
9833
|
if (row.summary) line(`
|
|
9317
9834
|
${row.summary}`);
|
|
@@ -9324,53 +9841,53 @@ touches: ${row.targets.map((t) => t.appName ?? t.ref ?? t.kind).join(", ")}`
|
|
|
9324
9841
|
}
|
|
9325
9842
|
if (row.subtasks?.length) {
|
|
9326
9843
|
line(`
|
|
9327
|
-
${
|
|
9844
|
+
${import_picocolors31.default.bold("subtasks")}`);
|
|
9328
9845
|
row.subtasks.forEach((s, i) => line(formatSubtask(s, i + 1)));
|
|
9329
9846
|
line(
|
|
9330
|
-
|
|
9847
|
+
import_picocolors31.default.dim(
|
|
9331
9848
|
`
|
|
9332
9849
|
Run \`workser artifact list\` to see what these subtasks produced,`
|
|
9333
9850
|
)
|
|
9334
9851
|
);
|
|
9335
9852
|
line(
|
|
9336
|
-
|
|
9853
|
+
import_picocolors31.default.dim(
|
|
9337
9854
|
`or \`workser artifact list --step <id>\` for one subtask's output alone.`
|
|
9338
9855
|
)
|
|
9339
9856
|
);
|
|
9340
9857
|
} else {
|
|
9341
|
-
line(
|
|
9858
|
+
line(import_picocolors31.default.dim("\nNo subtasks yet."));
|
|
9342
9859
|
}
|
|
9343
9860
|
}
|
|
9344
9861
|
function printGoalContext(row, goal) {
|
|
9345
9862
|
const mine = row.phase ?? null;
|
|
9346
9863
|
line(`
|
|
9347
|
-
${
|
|
9348
|
-
if (goal.outcome) line(
|
|
9864
|
+
${import_picocolors31.default.bold("part of")}: ${goal.title}`);
|
|
9865
|
+
if (goal.outcome) line(import_picocolors31.default.dim(`done means: ${goal.outcome}`));
|
|
9349
9866
|
const progress = goal.progress ?? [];
|
|
9350
9867
|
for (const p of progress) {
|
|
9351
9868
|
const where = p.total === 0 ? "not started" : `${p.done} of ${p.total} done`;
|
|
9352
|
-
const here = mine && p.name === mine ?
|
|
9353
|
-
const mark = p.state === "done" ?
|
|
9869
|
+
const here = mine && p.name === mine ? import_picocolors31.default.cyan(" <- this task") : "";
|
|
9870
|
+
const mark = p.state === "done" ? import_picocolors31.default.green("*") : import_picocolors31.default.dim("-");
|
|
9354
9871
|
line(` ${mark} ${p.name} \u2014 ${where}${here}`);
|
|
9355
9872
|
}
|
|
9356
9873
|
const next = progress.find((p) => p.state !== "done");
|
|
9357
9874
|
const running = progress.some((p) => p.state === "working");
|
|
9358
9875
|
if (next && !running) {
|
|
9359
9876
|
line(
|
|
9360
|
-
|
|
9877
|
+
import_picocolors31.default.dim(
|
|
9361
9878
|
`
|
|
9362
9879
|
Nothing is running. The next part waiting is "${next.name}" \u2014 offer it to them in a sentence rather than starting it unasked.`
|
|
9363
9880
|
)
|
|
9364
9881
|
);
|
|
9365
9882
|
} else if (!next) {
|
|
9366
9883
|
line(
|
|
9367
|
-
|
|
9884
|
+
import_picocolors31.default.dim(
|
|
9368
9885
|
"\nEvery part of this plan is done. Say so, and offer to wrap it up."
|
|
9369
9886
|
)
|
|
9370
9887
|
);
|
|
9371
9888
|
}
|
|
9372
9889
|
line(
|
|
9373
|
-
|
|
9890
|
+
import_picocolors31.default.dim(
|
|
9374
9891
|
"The plan is a reference for what was agreed, not a rule about what may run. Work can start on any part at any time if they ask for it."
|
|
9375
9892
|
)
|
|
9376
9893
|
);
|
|
@@ -9378,23 +9895,24 @@ Nothing is running. The next part waiting is "${next.name}" \u2014 offer it to t
|
|
|
9378
9895
|
function statusTag2(status) {
|
|
9379
9896
|
switch (status) {
|
|
9380
9897
|
case "ready":
|
|
9381
|
-
return
|
|
9898
|
+
return import_picocolors31.default.green("[ready]");
|
|
9382
9899
|
case "working":
|
|
9383
|
-
return
|
|
9900
|
+
return import_picocolors31.default.blue("[working]");
|
|
9384
9901
|
case "checking":
|
|
9385
|
-
return
|
|
9902
|
+
return import_picocolors31.default.cyan("[checking]");
|
|
9386
9903
|
case "accepted":
|
|
9387
|
-
return
|
|
9904
|
+
return import_picocolors31.default.green("[accepted]");
|
|
9388
9905
|
case "archived":
|
|
9389
|
-
return
|
|
9906
|
+
return import_picocolors31.default.dim("[archived]");
|
|
9390
9907
|
default:
|
|
9391
|
-
return
|
|
9908
|
+
return import_picocolors31.default.dim("[todo]");
|
|
9392
9909
|
}
|
|
9393
9910
|
}
|
|
9394
9911
|
|
|
9395
9912
|
// src/commands/goal.ts
|
|
9396
|
-
var
|
|
9913
|
+
var import_picocolors32 = __toESM(require_picocolors(), 1);
|
|
9397
9914
|
var STATUSES3 = ["proposed", "agreed", "working", "delivered", "abandoned"];
|
|
9915
|
+
var PACES = ["slice", "phase", "all"];
|
|
9398
9916
|
function registerGoal(program3) {
|
|
9399
9917
|
const goal = program3.command("goal").description("Business goals and the phases that deliver them");
|
|
9400
9918
|
goal.command("list").description("What this project is working towards").action(
|
|
@@ -9405,7 +9923,7 @@ function registerGoal(program3) {
|
|
|
9405
9923
|
}) ?? [];
|
|
9406
9924
|
ok(rows, () => {
|
|
9407
9925
|
if (!rows.length) {
|
|
9408
|
-
line(
|
|
9926
|
+
line(import_picocolors32.default.dim("No goals yet \u2014 every task here stands on its own."));
|
|
9409
9927
|
return;
|
|
9410
9928
|
}
|
|
9411
9929
|
for (const g of rows) line(formatGoal(g));
|
|
@@ -9432,6 +9950,9 @@ function registerGoal(program3) {
|
|
|
9432
9950
|
).option(
|
|
9433
9951
|
"--criteria <json>",
|
|
9434
9952
|
`what "done" means per phase, in the OWNER's words: '{"Checkout":["A customer can pay by card and gets a receipt"]}'`
|
|
9953
|
+
).option(
|
|
9954
|
+
"--pace <value>",
|
|
9955
|
+
`how much to do before checking in \u2014 slice (one task, then show), phase (the current phase, the default), all (${PACES.join(" | ")})`
|
|
9435
9956
|
).action(
|
|
9436
9957
|
action(async ({ ctx, args, opts }) => {
|
|
9437
9958
|
requireProject(ctx);
|
|
@@ -9464,11 +9985,17 @@ function registerGoal(program3) {
|
|
|
9464
9985
|
);
|
|
9465
9986
|
}
|
|
9466
9987
|
}
|
|
9988
|
+
if (opts.pace !== void 0 && !PACES.includes(opts.pace)) {
|
|
9989
|
+
throw new WorkserError(
|
|
9990
|
+
`Unknown --pace "${opts.pace}". Use one of: ${PACES.join(", ")}.`
|
|
9991
|
+
);
|
|
9992
|
+
}
|
|
9467
9993
|
const row = await api(ctx, "/v1/project-goals", {
|
|
9468
9994
|
body: {
|
|
9469
9995
|
projectId: ctx.projectId,
|
|
9470
9996
|
title: args[0],
|
|
9471
9997
|
outcome: opts.outcome,
|
|
9998
|
+
pace: opts.pace,
|
|
9472
9999
|
phases: phases.map((name) => ({
|
|
9473
10000
|
name,
|
|
9474
10001
|
criteria: (criteria[name] ?? []).map((text, i) => ({
|
|
@@ -9482,10 +10009,10 @@ function registerGoal(program3) {
|
|
|
9482
10009
|
}
|
|
9483
10010
|
});
|
|
9484
10011
|
ok(row, () => {
|
|
9485
|
-
success(`Proposed ${
|
|
10012
|
+
success(`Proposed ${import_picocolors32.default.bold(row?.title ?? "goal")}`);
|
|
9486
10013
|
printGoal(row);
|
|
9487
10014
|
line(
|
|
9488
|
-
|
|
10015
|
+
import_picocolors32.default.dim(
|
|
9489
10016
|
"\nNothing has been created yet. The owner agrees the shape first."
|
|
9490
10017
|
)
|
|
9491
10018
|
);
|
|
@@ -9514,7 +10041,7 @@ function registerGoal(program3) {
|
|
|
9514
10041
|
ok(
|
|
9515
10042
|
row,
|
|
9516
10043
|
() => line(
|
|
9517
|
-
row?.recorded ? met === true ?
|
|
10044
|
+
row?.recorded ? met === true ? import_picocolors32.default.green("recorded \u2014 met") : met === false ? import_picocolors32.default.yellow("recorded \u2014 not met") : import_picocolors32.default.dim("recorded \u2014 back to unchecked") : import_picocolors32.default.yellow(
|
|
9518
10045
|
"couldn't record it \u2014 check the goal id, the phase name and the criterion id"
|
|
9519
10046
|
)
|
|
9520
10047
|
)
|
|
@@ -9557,18 +10084,23 @@ function registerGoal(program3) {
|
|
|
9557
10084
|
}
|
|
9558
10085
|
ok({ goalId, phase, filed }, () => {
|
|
9559
10086
|
success(
|
|
9560
|
-
`Filed ${filed.length} ${filed.length === 1 ? "task" : "tasks"} under ${
|
|
10087
|
+
`Filed ${filed.length} ${filed.length === 1 ? "task" : "tasks"} under ${import_picocolors32.default.bold(phase)}`
|
|
9561
10088
|
);
|
|
9562
10089
|
});
|
|
9563
10090
|
})
|
|
9564
10091
|
);
|
|
9565
|
-
goal.command("update <id>").description("Change the shape, or move the goal along").option("--title <text>", "the owner's words for what they want").option("--outcome <text>", "what 'done' means").option("--phase <name...>", "replace the ordered phase list").option("--status <value>", `one of: ${STATUSES3.join(" | ")}`).action(
|
|
10092
|
+
goal.command("update <id>").description("Change the shape, or move the goal along").option("--title <text>", "the owner's words for what they want").option("--outcome <text>", "what 'done' means").option("--phase <name...>", "replace the ordered phase list").option("--status <value>", `one of: ${STATUSES3.join(" | ")}`).option("--pace <value>", `how much to do before checking in (${PACES.join(" | ")})`).action(
|
|
9566
10093
|
action(async ({ ctx, args, opts }) => {
|
|
9567
10094
|
if (opts.status && !STATUSES3.includes(opts.status)) {
|
|
9568
10095
|
throw new WorkserError(
|
|
9569
10096
|
`Unknown status "${opts.status}". Use one of: ${STATUSES3.join(", ")}.`
|
|
9570
10097
|
);
|
|
9571
10098
|
}
|
|
10099
|
+
if (opts.pace && !PACES.includes(opts.pace)) {
|
|
10100
|
+
throw new WorkserError(
|
|
10101
|
+
`Unknown --pace "${opts.pace}". Use one of: ${PACES.join(", ")}.`
|
|
10102
|
+
);
|
|
10103
|
+
}
|
|
9572
10104
|
const row = await api(
|
|
9573
10105
|
ctx,
|
|
9574
10106
|
`/v1/project-goals/${encodeURIComponent(String(args[0]))}`,
|
|
@@ -9578,7 +10110,8 @@ function registerGoal(program3) {
|
|
|
9578
10110
|
title: opts.title,
|
|
9579
10111
|
outcome: opts.outcome,
|
|
9580
10112
|
phases: opts.phase,
|
|
9581
|
-
status: opts.status
|
|
10113
|
+
status: opts.status,
|
|
10114
|
+
pace: opts.pace
|
|
9582
10115
|
}
|
|
9583
10116
|
}
|
|
9584
10117
|
);
|
|
@@ -9589,42 +10122,43 @@ function registerGoal(program3) {
|
|
|
9589
10122
|
function appScope(g) {
|
|
9590
10123
|
const n = g.appIds?.length ?? 0;
|
|
9591
10124
|
if (!n) return "";
|
|
9592
|
-
return
|
|
10125
|
+
return import_picocolors32.default.dim(` ${n} part${n === 1 ? "" : "s"} of the system`);
|
|
9593
10126
|
}
|
|
9594
10127
|
function formatGoal(g) {
|
|
9595
|
-
const where = g.currentPhase && g.status !== "delivered" ?
|
|
9596
|
-
const count = g.taskTotal != null ?
|
|
9597
|
-
return `${statusTag3(g.status)} ${g.title}${appScope(g)}${where}${count} ${
|
|
10128
|
+
const where = g.currentPhase && g.status !== "delivered" ? import_picocolors32.default.dim(` now: ${g.currentPhase}`) : "";
|
|
10129
|
+
const count = g.taskTotal != null ? import_picocolors32.default.dim(` ${g.taskDone}/${g.taskTotal} done`) : "";
|
|
10130
|
+
return `${statusTag3(g.status)} ${g.title}${appScope(g)}${where}${count} ${import_picocolors32.default.dim(g.id)}`;
|
|
9598
10131
|
}
|
|
9599
10132
|
function printGoal(g) {
|
|
9600
10133
|
if (!g) return;
|
|
9601
|
-
line(`${
|
|
10134
|
+
line(`${import_picocolors32.default.bold(g.title)} ${import_picocolors32.default.dim(g.id)}`);
|
|
9602
10135
|
line(statusTag3(g.status));
|
|
9603
10136
|
if (g.outcome) line(`
|
|
9604
10137
|
done means: ${g.outcome}`);
|
|
10138
|
+
if (g.pace) line(import_picocolors32.default.dim(`pace: ${paceLine(g.pace)}`));
|
|
9605
10139
|
const progress = g.progress ?? [];
|
|
9606
10140
|
if (!progress.length) {
|
|
9607
|
-
line(
|
|
10141
|
+
line(import_picocolors32.default.dim("\nNo phases agreed yet."));
|
|
9608
10142
|
return;
|
|
9609
10143
|
}
|
|
9610
10144
|
line(`
|
|
9611
|
-
${
|
|
10145
|
+
${import_picocolors32.default.bold("phases")}`);
|
|
9612
10146
|
for (const p of progress) {
|
|
9613
|
-
const bar2 = p.total > 0 ? `${p.done}/${p.total} done` :
|
|
9614
|
-
const mark = p.state === "done" ?
|
|
10147
|
+
const bar2 = p.total > 0 ? `${p.done}/${p.total} done` : import_picocolors32.default.dim("nothing filed yet");
|
|
10148
|
+
const mark = p.state === "done" ? import_picocolors32.default.green("done") : p.state === "working" ? import_picocolors32.default.blue("working") : import_picocolors32.default.dim("waiting");
|
|
9615
10149
|
line(
|
|
9616
|
-
` ${
|
|
10150
|
+
` ${import_picocolors32.default.dim(String(p.index).padStart(2, "0"))} ${p.name} ${mark} ${import_picocolors32.default.dim(bar2)}`
|
|
9617
10151
|
);
|
|
9618
10152
|
for (const c of p.criteria ?? []) {
|
|
9619
|
-
const tick = c.met === true ?
|
|
9620
|
-
line(` ${tick} ${c.text} ${
|
|
9621
|
-
if (c.note) line(
|
|
10153
|
+
const tick = c.met === true ? import_picocolors32.default.green("\u2713") : c.met === false ? import_picocolors32.default.red("\u2717") : import_picocolors32.default.dim("\xB7");
|
|
10154
|
+
line(` ${tick} ${c.text} ${import_picocolors32.default.dim(c.id)}`);
|
|
10155
|
+
if (c.note) line(import_picocolors32.default.dim(` ${c.note}`));
|
|
9622
10156
|
}
|
|
9623
10157
|
}
|
|
9624
10158
|
const current = progress.find((p) => p.name === g.currentPhase);
|
|
9625
10159
|
if (current) {
|
|
9626
10160
|
line(
|
|
9627
|
-
|
|
10161
|
+
import_picocolors32.default.dim(
|
|
9628
10162
|
`
|
|
9629
10163
|
${current.name} \u2014 ${current.done} of ${current.total} done (phase ${current.index} of ${progress.length}).`
|
|
9630
10164
|
)
|
|
@@ -9634,17 +10168,22 @@ ${current.name} \u2014 ${current.done} of ${current.total} done (phase ${current
|
|
|
9634
10168
|
function statusTag3(status) {
|
|
9635
10169
|
switch (status) {
|
|
9636
10170
|
case "agreed":
|
|
9637
|
-
return
|
|
10171
|
+
return import_picocolors32.default.cyan("[agreed]");
|
|
9638
10172
|
case "working":
|
|
9639
|
-
return
|
|
10173
|
+
return import_picocolors32.default.blue("[working]");
|
|
9640
10174
|
case "delivered":
|
|
9641
|
-
return
|
|
10175
|
+
return import_picocolors32.default.green("[delivered]");
|
|
9642
10176
|
case "abandoned":
|
|
9643
|
-
return
|
|
10177
|
+
return import_picocolors32.default.dim("[abandoned]");
|
|
9644
10178
|
default:
|
|
9645
|
-
return
|
|
10179
|
+
return import_picocolors32.default.yellow("[proposed]");
|
|
9646
10180
|
}
|
|
9647
10181
|
}
|
|
10182
|
+
function paceLine(pace) {
|
|
10183
|
+
if (pace === "slice") return "slice \u2014 do ONE task, then stop and show the owner";
|
|
10184
|
+
if (pace === "all") return "all \u2014 work through the phases; report at the end";
|
|
10185
|
+
return "phase \u2014 the current phase, task by task";
|
|
10186
|
+
}
|
|
9648
10187
|
|
|
9649
10188
|
// src/role-guard.ts
|
|
9650
10189
|
var READS = [
|
|
@@ -9826,7 +10365,7 @@ function stripLeadingGlobalOptions(argv) {
|
|
|
9826
10365
|
}
|
|
9827
10366
|
|
|
9828
10367
|
// src/commands/decision.ts
|
|
9829
|
-
var
|
|
10368
|
+
var import_picocolors33 = __toESM(require_picocolors(), 1);
|
|
9830
10369
|
function registerDecision(program3) {
|
|
9831
10370
|
const decision = program3.command("decision").description("Read and record the project's architecture decisions");
|
|
9832
10371
|
decision.command("list").description("Every decision on record \u2014 read this before changing how something works").option("--limit <n>", "cap the number returned (newest first)").action(
|
|
@@ -9839,11 +10378,11 @@ function registerDecision(program3) {
|
|
|
9839
10378
|
rows = applyLimit(rows, opts.limit);
|
|
9840
10379
|
ok(rows, () => {
|
|
9841
10380
|
if (!rows.length) {
|
|
9842
|
-
line(
|
|
10381
|
+
line(import_picocolors33.default.dim("No decisions recorded yet."));
|
|
9843
10382
|
return;
|
|
9844
10383
|
}
|
|
9845
10384
|
for (const r of rows) {
|
|
9846
|
-
line(`${
|
|
10385
|
+
line(`${import_picocolors33.default.dim(r.id)} ${import_picocolors33.default.dim(shortDate(r.createdAt))} ${r.title}`);
|
|
9847
10386
|
line(` ${truncate(r.decision, 100)}`);
|
|
9848
10387
|
}
|
|
9849
10388
|
});
|
|
@@ -9857,16 +10396,16 @@ function registerDecision(program3) {
|
|
|
9857
10396
|
`/v1/projects/${projectId}/architecture-decisions/${args[0]}`
|
|
9858
10397
|
);
|
|
9859
10398
|
ok(row, () => {
|
|
9860
|
-
line(`${
|
|
9861
|
-
line(
|
|
10399
|
+
line(`${import_picocolors33.default.bold(row.title)} ${import_picocolors33.default.dim(row.id)}`);
|
|
10400
|
+
line(import_picocolors33.default.dim(`${row.status} \xB7 ${shortDate(row.createdAt)}`));
|
|
9862
10401
|
line(`
|
|
9863
|
-
${
|
|
10402
|
+
${import_picocolors33.default.bold("Context")}
|
|
9864
10403
|
${row.context}`);
|
|
9865
10404
|
line(`
|
|
9866
|
-
${
|
|
10405
|
+
${import_picocolors33.default.bold("Decision")}
|
|
9867
10406
|
${row.decision}`);
|
|
9868
10407
|
if (row.consequences) line(`
|
|
9869
|
-
${
|
|
10408
|
+
${import_picocolors33.default.bold("Consequences")}
|
|
9870
10409
|
${row.consequences}`);
|
|
9871
10410
|
});
|
|
9872
10411
|
})
|
|
@@ -9895,7 +10434,7 @@ ${row.consequences}`);
|
|
|
9895
10434
|
refId: row?.id,
|
|
9896
10435
|
output: { decision: row }
|
|
9897
10436
|
});
|
|
9898
|
-
ok(row, () => line(`Recorded decision ${
|
|
10437
|
+
ok(row, () => line(`Recorded decision ${import_picocolors33.default.bold(row?.id ?? "")} \u2014 ${title}`));
|
|
9899
10438
|
})
|
|
9900
10439
|
);
|
|
9901
10440
|
const requirement = program3.command("requirement").description("Read and record the project's requirements");
|
|
@@ -9907,11 +10446,11 @@ ${row.consequences}`);
|
|
|
9907
10446
|
rows = applyLimit(rows, opts.limit);
|
|
9908
10447
|
ok(rows, () => {
|
|
9909
10448
|
if (!rows.length) {
|
|
9910
|
-
line(
|
|
10449
|
+
line(import_picocolors33.default.dim("No requirements recorded yet."));
|
|
9911
10450
|
return;
|
|
9912
10451
|
}
|
|
9913
10452
|
for (const r of rows) {
|
|
9914
|
-
line(`${
|
|
10453
|
+
line(`${import_picocolors33.default.dim(r.id)} ${r.status.padEnd(9)} ${r.title}`);
|
|
9915
10454
|
}
|
|
9916
10455
|
});
|
|
9917
10456
|
})
|
|
@@ -9924,8 +10463,8 @@ ${row.consequences}`);
|
|
|
9924
10463
|
`/v1/projects/${projectId}/requirements/${args[0]}`
|
|
9925
10464
|
);
|
|
9926
10465
|
ok(row, () => {
|
|
9927
|
-
line(`${
|
|
9928
|
-
line(
|
|
10466
|
+
line(`${import_picocolors33.default.bold(row.title)} ${import_picocolors33.default.dim(row.id)}`);
|
|
10467
|
+
line(import_picocolors33.default.dim(`${row.status} \xB7 ${shortDate(row.createdAt)}`));
|
|
9929
10468
|
line(`
|
|
9930
10469
|
${row.body}`);
|
|
9931
10470
|
});
|
|
@@ -9951,7 +10490,7 @@ ${row.body}`);
|
|
|
9951
10490
|
refId: row?.id,
|
|
9952
10491
|
output: { requirement: row }
|
|
9953
10492
|
});
|
|
9954
|
-
ok(row, () => line(`Recorded requirement ${
|
|
10493
|
+
ok(row, () => line(`Recorded requirement ${import_picocolors33.default.bold(row?.id ?? "")} \u2014 ${title}`));
|
|
9955
10494
|
})
|
|
9956
10495
|
);
|
|
9957
10496
|
requirement.command("update <id>").description(
|
|
@@ -9980,7 +10519,7 @@ ${row.body}`);
|
|
|
9980
10519
|
code: "bad_request"
|
|
9981
10520
|
});
|
|
9982
10521
|
}
|
|
9983
|
-
ok(row, () => line(`Updated requirement ${
|
|
10522
|
+
ok(row, () => line(`Updated requirement ${import_picocolors33.default.bold(row.id)} \u2014 ${row.title} (${row.status})`));
|
|
9984
10523
|
})
|
|
9985
10524
|
);
|
|
9986
10525
|
}
|
|
@@ -10003,7 +10542,7 @@ function shortDate(iso) {
|
|
|
10003
10542
|
}
|
|
10004
10543
|
|
|
10005
10544
|
// src/commands/doc.ts
|
|
10006
|
-
var
|
|
10545
|
+
var import_picocolors34 = __toESM(require_picocolors(), 1);
|
|
10007
10546
|
|
|
10008
10547
|
// src/mermaid-fences.ts
|
|
10009
10548
|
function hasDiagram(code) {
|
|
@@ -10048,13 +10587,13 @@ function registerDoc(program3) {
|
|
|
10048
10587
|
}) ?? [];
|
|
10049
10588
|
ok(rows, () => {
|
|
10050
10589
|
if (!rows.length) {
|
|
10051
|
-
line(
|
|
10590
|
+
line(import_picocolors34.default.dim("No documents yet."));
|
|
10052
10591
|
return;
|
|
10053
10592
|
}
|
|
10054
10593
|
for (const r of rows) {
|
|
10055
|
-
const link = r.workItemId ?
|
|
10056
|
-
const file = r.filePath ?
|
|
10057
|
-
line(`${
|
|
10594
|
+
const link = r.workItemId ? import_picocolors34.default.dim(` \u21B3 ${r.workItemId}`) : "";
|
|
10595
|
+
const file = r.filePath ? import_picocolors34.default.dim(` ${r.filePath}`) : "";
|
|
10596
|
+
line(`${import_picocolors34.default.dim(r.id)} ${r.title}${link}${file}`);
|
|
10058
10597
|
}
|
|
10059
10598
|
});
|
|
10060
10599
|
})
|
|
@@ -10068,17 +10607,17 @@ function registerDoc(program3) {
|
|
|
10068
10607
|
);
|
|
10069
10608
|
if (opts.markdown) {
|
|
10070
10609
|
ok({ id: row.id, title: row.title, filePath: row.filePath }, () => {
|
|
10071
|
-
line(`${
|
|
10610
|
+
line(`${import_picocolors34.default.bold(row.title)} ${import_picocolors34.default.dim(row.id)}`);
|
|
10072
10611
|
line(
|
|
10073
|
-
row.filePath ? `Read it at ${
|
|
10612
|
+
row.filePath ? `Read it at ${import_picocolors34.default.bold(row.filePath)} (relative to the project folder).` : import_picocolors34.default.dim("This document has no markdown mirror on disk yet.")
|
|
10074
10613
|
);
|
|
10075
10614
|
});
|
|
10076
10615
|
return;
|
|
10077
10616
|
}
|
|
10078
10617
|
ok(row, () => {
|
|
10079
|
-
line(`${
|
|
10080
|
-
if (row.workItemId) line(
|
|
10081
|
-
if (row.filePath) line(
|
|
10618
|
+
line(`${import_picocolors34.default.bold(row.title)} ${import_picocolors34.default.dim(row.id)}`);
|
|
10619
|
+
if (row.workItemId) line(import_picocolors34.default.dim(`linked to work item ${row.workItemId}`));
|
|
10620
|
+
if (row.filePath) line(import_picocolors34.default.dim(`markdown mirror: ${row.filePath}`));
|
|
10082
10621
|
line("");
|
|
10083
10622
|
line(row.contentJson);
|
|
10084
10623
|
});
|
|
@@ -10107,7 +10646,7 @@ function registerDoc(program3) {
|
|
|
10107
10646
|
refId: row?.id,
|
|
10108
10647
|
output: { document: row }
|
|
10109
10648
|
});
|
|
10110
|
-
ok(row, () => line(`Created document ${
|
|
10649
|
+
ok(row, () => line(`Created document ${import_picocolors34.default.bold(row?.id ?? "")} \u2014 ${title}`));
|
|
10111
10650
|
})
|
|
10112
10651
|
);
|
|
10113
10652
|
doc.command("diagram <id>").description(
|
|
@@ -10133,19 +10672,19 @@ function registerDoc(program3) {
|
|
|
10133
10672
|
diagrams: diagrams.map((code) => ({ kind: diagramKind(code), code }))
|
|
10134
10673
|
};
|
|
10135
10674
|
ok(payload, () => {
|
|
10136
|
-
line(`${
|
|
10675
|
+
line(`${import_picocolors34.default.bold(row.title)} ${import_picocolors34.default.dim(row.id)}`);
|
|
10137
10676
|
if (markdown === null) {
|
|
10138
10677
|
line(
|
|
10139
|
-
|
|
10678
|
+
import_picocolors34.default.dim(
|
|
10140
10679
|
row.filePath ? `Could not read ${row.filePath} from this folder.` : "This document has no markdown mirror on disk yet."
|
|
10141
10680
|
)
|
|
10142
10681
|
);
|
|
10143
10682
|
} else if (!diagrams.length) {
|
|
10144
|
-
line(
|
|
10683
|
+
line(import_picocolors34.default.dim("No diagrams in this document."));
|
|
10145
10684
|
} else {
|
|
10146
10685
|
for (const [i, code] of diagrams.entries()) {
|
|
10147
10686
|
const kind = diagramKind(code) ?? "diagram";
|
|
10148
|
-
line(`${
|
|
10687
|
+
line(`${import_picocolors34.default.dim(String(i + 1))} ${kind} ${import_picocolors34.default.dim(`${code.split("\n").length} lines`)}`);
|
|
10149
10688
|
}
|
|
10150
10689
|
}
|
|
10151
10690
|
});
|
|
@@ -10181,7 +10720,7 @@ function registerDoc(program3) {
|
|
|
10181
10720
|
code: "bad_request"
|
|
10182
10721
|
});
|
|
10183
10722
|
}
|
|
10184
|
-
ok(row, () => line(`Updated document ${
|
|
10723
|
+
ok(row, () => line(`Updated document ${import_picocolors34.default.bold(row.id)} \u2014 ${row.title}`));
|
|
10185
10724
|
})
|
|
10186
10725
|
);
|
|
10187
10726
|
}
|
|
@@ -10195,9 +10734,9 @@ function readMirror(cwd, filePath) {
|
|
|
10195
10734
|
}
|
|
10196
10735
|
|
|
10197
10736
|
// src/commands/design.ts
|
|
10198
|
-
var
|
|
10737
|
+
var import_picocolors35 = __toESM(require_picocolors(), 1);
|
|
10199
10738
|
function registerDesign(program3) {
|
|
10200
|
-
const design = program3.command("design").description("
|
|
10739
|
+
const design = program3.command("design").description("The project's brand, and pictures of the screens you draw");
|
|
10201
10740
|
design.command("show").description("Show this project's brand \u2014 read it before writing any UI").option("--raw", "print the generated token files verbatim instead of a summary").action(
|
|
10202
10741
|
action(async ({ ctx, opts }) => {
|
|
10203
10742
|
const projectId = requireProject(ctx);
|
|
@@ -10209,11 +10748,11 @@ function registerDesign(program3) {
|
|
|
10209
10748
|
if (opts.raw) {
|
|
10210
10749
|
ok(files, () => {
|
|
10211
10750
|
if (!files.length) {
|
|
10212
|
-
line(
|
|
10751
|
+
line(import_picocolors35.default.dim("No brand set for this project."));
|
|
10213
10752
|
return;
|
|
10214
10753
|
}
|
|
10215
10754
|
for (const f of files) {
|
|
10216
|
-
line(
|
|
10755
|
+
line(import_picocolors35.default.bold(f.path));
|
|
10217
10756
|
line(f.contents);
|
|
10218
10757
|
line("");
|
|
10219
10758
|
}
|
|
@@ -10230,27 +10769,62 @@ function registerDesign(program3) {
|
|
|
10230
10769
|
} : { hasBrand: false, colors: {}, fonts: {}, brand: {}, files: [] };
|
|
10231
10770
|
ok(summary, () => {
|
|
10232
10771
|
if (!tokens) {
|
|
10233
|
-
line(
|
|
10772
|
+
line(import_picocolors35.default.dim("No brand set for this project \u2014 choose sensible styling yourself."));
|
|
10234
10773
|
return;
|
|
10235
10774
|
}
|
|
10236
10775
|
for (const [name, value] of Object.entries(tokens.brand)) {
|
|
10237
|
-
line(`${
|
|
10776
|
+
line(`${import_picocolors35.default.dim(name.padEnd(12))} ${value}`);
|
|
10238
10777
|
}
|
|
10239
10778
|
for (const [name, value] of Object.entries(tokens.color)) {
|
|
10240
|
-
line(`${
|
|
10779
|
+
line(`${import_picocolors35.default.dim(`color.${name}`.padEnd(12))} ${value}`);
|
|
10241
10780
|
}
|
|
10242
10781
|
for (const [name, value] of Object.entries(tokens.font)) {
|
|
10243
|
-
line(`${
|
|
10782
|
+
line(`${import_picocolors35.default.dim(`font.${name}`.padEnd(12))} ${value}`);
|
|
10244
10783
|
}
|
|
10245
10784
|
line("");
|
|
10246
10785
|
line(
|
|
10247
|
-
|
|
10786
|
+
import_picocolors35.default.dim(
|
|
10248
10787
|
`Generated into the working tree as ${files.map((f) => f.path).join(", ")} \u2014 wire those in, never edit them.`
|
|
10249
10788
|
)
|
|
10250
10789
|
);
|
|
10251
10790
|
});
|
|
10252
10791
|
})
|
|
10253
10792
|
);
|
|
10793
|
+
design.command("shot").argument("<files...>", "the HTML screens to photograph, relative to the project folder").description("Render a design screen to a PNG beside it, for surfaces that can't run a page").option("--width <px>", "artboard width (default 1440)", (v) => Number(v)).option("--height <px>", "artboard height (default 900)", (v) => Number(v)).action(
|
|
10794
|
+
action(async ({ ctx, args, opts }) => {
|
|
10795
|
+
const projectId = requireProject(ctx);
|
|
10796
|
+
const res = await api(ctx, "/v1/design-shot", {
|
|
10797
|
+
method: "POST",
|
|
10798
|
+
body: {
|
|
10799
|
+
projectId,
|
|
10800
|
+
files: args,
|
|
10801
|
+
width: opts.width,
|
|
10802
|
+
height: opts.height
|
|
10803
|
+
}
|
|
10804
|
+
});
|
|
10805
|
+
ok(res, () => {
|
|
10806
|
+
for (const shot of res.shots ?? []) {
|
|
10807
|
+
if (shot.out) {
|
|
10808
|
+
line(`${import_picocolors35.default.green("\u2713")} ${shot.file} ${import_picocolors35.default.dim("\u2192")} ${shot.out}`);
|
|
10809
|
+
} else {
|
|
10810
|
+
line(`${import_picocolors35.default.red("\u2717")} ${shot.file} ${import_picocolors35.default.dim(shot.error ?? "no image")}`);
|
|
10811
|
+
}
|
|
10812
|
+
}
|
|
10813
|
+
for (const path of res.refused ?? []) {
|
|
10814
|
+
line(import_picocolors35.default.dim(`skipped ${path} \u2014 not a page inside this project`));
|
|
10815
|
+
}
|
|
10816
|
+
const made = (res.shots ?? []).filter((s) => s.out).length;
|
|
10817
|
+
if (made) {
|
|
10818
|
+
line("");
|
|
10819
|
+
line(
|
|
10820
|
+
import_picocolors35.default.dim(
|
|
10821
|
+
`Record each one so it shows up: workser artifact add <file>.png --kind design -d "<what this screen is>"`
|
|
10822
|
+
)
|
|
10823
|
+
);
|
|
10824
|
+
}
|
|
10825
|
+
});
|
|
10826
|
+
})
|
|
10827
|
+
);
|
|
10254
10828
|
}
|
|
10255
10829
|
function parseTokens(files) {
|
|
10256
10830
|
const doc = files.find((f) => f.path.endsWith("tokens.json"));
|
|
@@ -10275,7 +10849,7 @@ function unwrap(group) {
|
|
|
10275
10849
|
}
|
|
10276
10850
|
|
|
10277
10851
|
// src/commands/api.ts
|
|
10278
|
-
var
|
|
10852
|
+
var import_picocolors36 = __toESM(require_picocolors(), 1);
|
|
10279
10853
|
import { readdirSync, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
|
|
10280
10854
|
import { join as join3, relative, sep } from "path";
|
|
10281
10855
|
|
|
@@ -10389,10 +10963,10 @@ function registerApi(program3) {
|
|
|
10389
10963
|
const appId = requireApp2(opts.app);
|
|
10390
10964
|
const res = await api(ctx, `/v1/apps/${encodeURIComponent(appId)}/api/requests`);
|
|
10391
10965
|
ok(res, () => {
|
|
10392
|
-
for (const note of res?.notes ?? []) line(
|
|
10966
|
+
for (const note of res?.notes ?? []) line(import_picocolors36.default.dim(note));
|
|
10393
10967
|
for (const r of res?.requests ?? []) {
|
|
10394
10968
|
line(
|
|
10395
|
-
`${
|
|
10969
|
+
`${import_picocolors36.default.dim(r.method.padEnd(6))}${r.path}${r.note ? import_picocolors36.default.dim(` ${r.note}`) : ""}`
|
|
10396
10970
|
);
|
|
10397
10971
|
}
|
|
10398
10972
|
});
|
|
@@ -10426,14 +11000,14 @@ function registerApi(program3) {
|
|
|
10426
11000
|
);
|
|
10427
11001
|
ok(res, () => {
|
|
10428
11002
|
if (!res?.ok) {
|
|
10429
|
-
line(
|
|
11003
|
+
line(import_picocolors36.default.red(res?.error ?? "The service did not answer."));
|
|
10430
11004
|
return;
|
|
10431
11005
|
}
|
|
10432
11006
|
const code = `${res.status}${res.statusText ? ` ${res.statusText}` : ""}`;
|
|
10433
|
-
const colour2 = res.status && res.status < 300 ?
|
|
10434
|
-
line(`${colour2(code)} ${
|
|
11007
|
+
const colour2 = res.status && res.status < 300 ? import_picocolors36.default.green : res.status && res.status < 500 ? import_picocolors36.default.yellow : import_picocolors36.default.red;
|
|
11008
|
+
line(`${colour2(code)} ${import_picocolors36.default.dim(`${res.durationMs}ms ${res.url}`)}`);
|
|
10435
11009
|
if (res.body) line(res.body);
|
|
10436
|
-
if (res.truncated) line(
|
|
11010
|
+
if (res.truncated) line(import_picocolors36.default.dim("(answer truncated)"));
|
|
10437
11011
|
});
|
|
10438
11012
|
if (!res?.ok) process.exitCode = 1;
|
|
10439
11013
|
})
|
|
@@ -10453,15 +11027,15 @@ function registerApi(program3) {
|
|
|
10453
11027
|
for (const r of report.routes) {
|
|
10454
11028
|
const known = report.missing.some((m) => m.path === r.path);
|
|
10455
11029
|
line(
|
|
10456
|
-
`${known ?
|
|
11030
|
+
`${known ? import_picocolors36.default.yellow("undocumented") : import_picocolors36.default.green("documented ")} ${r.path}${import_picocolors36.default.dim(` ${r.file}`)}`
|
|
10457
11031
|
);
|
|
10458
11032
|
}
|
|
10459
11033
|
for (const p of report.stale) {
|
|
10460
|
-
line(`${
|
|
11034
|
+
line(`${import_picocolors36.default.dim("in spec only ")} ${p}`);
|
|
10461
11035
|
}
|
|
10462
11036
|
line("");
|
|
10463
11037
|
if (report.ok && specFile) success(summary);
|
|
10464
|
-
else line(
|
|
11038
|
+
else line(import_picocolors36.default.yellow(summary));
|
|
10465
11039
|
});
|
|
10466
11040
|
if (opts.check && !report.ok) {
|
|
10467
11041
|
throw new WorkserError(summary, { code: "bad_request" });
|
|
@@ -10532,7 +11106,7 @@ function listRepoFiles(root, maxDepth = 8) {
|
|
|
10532
11106
|
}
|
|
10533
11107
|
|
|
10534
11108
|
// src/commands/analysis.ts
|
|
10535
|
-
var
|
|
11109
|
+
var import_picocolors37 = __toESM(require_picocolors(), 1);
|
|
10536
11110
|
import { readFileSync as readFileSync4 } from "fs";
|
|
10537
11111
|
function registerAnalysis(program3) {
|
|
10538
11112
|
const cmd = program3.command("analysis").description("Run Python analysis locally, recorded in the task");
|
|
@@ -10542,14 +11116,14 @@ function registerAnalysis(program3) {
|
|
|
10542
11116
|
const res = await api(ctx, path);
|
|
10543
11117
|
ok(res, () => {
|
|
10544
11118
|
line(
|
|
10545
|
-
`${res?.available ?
|
|
11119
|
+
`${res?.available ? import_picocolors37.default.green("python") : import_picocolors37.default.red("python")} ${res?.version ?? "not found"} ${import_picocolors37.default.dim(res?.python ?? "")}`
|
|
10546
11120
|
);
|
|
10547
11121
|
for (const lib of res?.libraries ?? []) {
|
|
10548
11122
|
line(
|
|
10549
|
-
`${lib.present ?
|
|
11123
|
+
`${lib.present ? import_picocolors37.default.green(lib.name) : import_picocolors37.default.yellow(lib.name)}${import_picocolors37.default.dim(lib.present ? "" : " missing")}`
|
|
10550
11124
|
);
|
|
10551
11125
|
}
|
|
10552
|
-
for (const note of res?.notes ?? []) line(
|
|
11126
|
+
for (const note of res?.notes ?? []) line(import_picocolors37.default.dim(note));
|
|
10553
11127
|
});
|
|
10554
11128
|
if (!res?.available) process.exitCode = 1;
|
|
10555
11129
|
})
|
|
@@ -10571,15 +11145,15 @@ function registerAnalysis(program3) {
|
|
|
10571
11145
|
);
|
|
10572
11146
|
ok(res, () => {
|
|
10573
11147
|
if (res?.stdout) line(res.stdout.replace(/\n$/, ""));
|
|
10574
|
-
if (res?.stderr) line(
|
|
10575
|
-
if (res?.truncated) line(
|
|
11148
|
+
if (res?.stderr) line(import_picocolors37.default.dim(res.stderr.replace(/\n$/, "")));
|
|
11149
|
+
if (res?.truncated) line(import_picocolors37.default.dim("(output truncated)"));
|
|
10576
11150
|
const took = `${Math.round((res?.durationMs ?? 0) / 100) / 10}s`;
|
|
10577
11151
|
line(
|
|
10578
|
-
res?.ok ?
|
|
11152
|
+
res?.ok ? import_picocolors37.default.green(`\u2713 ${res.summary ?? "It finished."}`) + import_picocolors37.default.dim(` ${took}`) : import_picocolors37.default.yellow(res?.summary ?? "It did not finish.") + import_picocolors37.default.dim(` ${took}`)
|
|
10579
11153
|
);
|
|
10580
11154
|
if (res && !res.sandboxed) {
|
|
10581
11155
|
line(
|
|
10582
|
-
|
|
11156
|
+
import_picocolors37.default.dim(
|
|
10583
11157
|
"This platform has no OS sandbox, so the script ran with your own file access."
|
|
10584
11158
|
)
|
|
10585
11159
|
);
|
|
@@ -10607,7 +11181,7 @@ function readCode(file, inline) {
|
|
|
10607
11181
|
}
|
|
10608
11182
|
|
|
10609
11183
|
// src/commands/scan.ts
|
|
10610
|
-
var
|
|
11184
|
+
var import_picocolors38 = __toESM(require_picocolors(), 1);
|
|
10611
11185
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
10612
11186
|
import { existsSync as existsSync3, readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync3 } from "fs";
|
|
10613
11187
|
import { join as join4, relative as relative2, sep as sep2 } from "path";
|
|
@@ -10891,22 +11465,22 @@ function runPermissions(cwd, findings, checked, skipped) {
|
|
|
10891
11465
|
}
|
|
10892
11466
|
function print2(report, summary) {
|
|
10893
11467
|
for (const s of report.skipped) {
|
|
10894
|
-
line(`${
|
|
11468
|
+
line(`${import_picocolors38.default.yellow("not checked")} ${s.check}${import_picocolors38.default.dim(` \u2014 ${s.reason}`)}`);
|
|
10895
11469
|
}
|
|
10896
11470
|
for (const f of report.findings) {
|
|
10897
|
-
const where = f.file ?
|
|
11471
|
+
const where = f.file ? import_picocolors38.default.dim(` ${f.file}${f.line ? `:${f.line}` : ""}`) : "";
|
|
10898
11472
|
line(`${severityTag(f.severity)} ${f.title}${where}`);
|
|
10899
|
-
line(` ${
|
|
11473
|
+
line(` ${import_picocolors38.default.dim(f.fix)}`);
|
|
10900
11474
|
}
|
|
10901
11475
|
if (report.findings.length || report.skipped.length) line("");
|
|
10902
11476
|
if (report.ok && !report.skipped.length) success(summary);
|
|
10903
|
-
else if (report.ok) line(
|
|
10904
|
-
else line(
|
|
11477
|
+
else if (report.ok) line(import_picocolors38.default.yellow(summary));
|
|
11478
|
+
else line(import_picocolors38.default.red(summary));
|
|
10905
11479
|
}
|
|
10906
11480
|
function severityTag(severity) {
|
|
10907
|
-
if (severity === "high") return
|
|
10908
|
-
if (severity === "medium") return
|
|
10909
|
-
return
|
|
11481
|
+
if (severity === "high") return import_picocolors38.default.red("serious ");
|
|
11482
|
+
if (severity === "medium") return import_picocolors38.default.yellow("worth fixing");
|
|
11483
|
+
return import_picocolors38.default.dim("minor ");
|
|
10910
11484
|
}
|
|
10911
11485
|
function git(cwd, args) {
|
|
10912
11486
|
try {
|
|
@@ -10967,7 +11541,7 @@ function listRepoFiles2(root, maxDepth = 8) {
|
|
|
10967
11541
|
}
|
|
10968
11542
|
|
|
10969
11543
|
// src/commands/health.ts
|
|
10970
|
-
var
|
|
11544
|
+
var import_picocolors39 = __toESM(require_picocolors(), 1);
|
|
10971
11545
|
function registerHealth(program3) {
|
|
10972
11546
|
program3.command("health").description("Check that the published apps in this project are still answering").option("--app <webAppId>", "check one app rather than all of them").action(
|
|
10973
11547
|
action(async ({ ctx, opts }) => {
|
|
@@ -10981,16 +11555,16 @@ function registerHealth(program3) {
|
|
|
10981
11555
|
}
|
|
10982
11556
|
function print3(res) {
|
|
10983
11557
|
if (!res?.checks?.length) {
|
|
10984
|
-
line(
|
|
11558
|
+
line(import_picocolors39.default.dim(res?.note ?? "Nothing to check."));
|
|
10985
11559
|
return;
|
|
10986
11560
|
}
|
|
10987
11561
|
for (const c of res.checks) {
|
|
10988
|
-
const mark = c.ok ?
|
|
10989
|
-
const timing =
|
|
10990
|
-
const detail = c.ok ? timing :
|
|
10991
|
-
line(` ${mark} ${c.appName} ${
|
|
11562
|
+
const mark = c.ok ? import_picocolors39.default.green("up ") : import_picocolors39.default.red("down");
|
|
11563
|
+
const timing = import_picocolors39.default.dim(`${c.ms}ms`);
|
|
11564
|
+
const detail = c.ok ? timing : import_picocolors39.default.dim(`${c.error ?? "no answer"}${c.failures > 1 ? ` \xB7 ${c.failures} in a row` : ""}`);
|
|
11565
|
+
line(` ${mark} ${c.appName} ${import_picocolors39.default.dim(`(${c.environment})`)} ${c.url} ${detail}`);
|
|
10992
11566
|
if (c.incidentOpened) {
|
|
10993
|
-
line(
|
|
11567
|
+
line(import_picocolors39.default.yellow(` An incident has been opened on the board for this.`));
|
|
10994
11568
|
}
|
|
10995
11569
|
}
|
|
10996
11570
|
const down = res.checks.filter((c) => !c.ok);
|
|
@@ -11003,14 +11577,14 @@ function print3(res) {
|
|
|
11003
11577
|
}
|
|
11004
11578
|
const production = down.filter((c) => c.environment === "production").length;
|
|
11005
11579
|
line(
|
|
11006
|
-
|
|
11580
|
+
import_picocolors39.default.red(
|
|
11007
11581
|
`${down.length} of ${res.checks.length} not answering` + (production ? ` \u2014 ${production} customer-facing.` : " (preview only).")
|
|
11008
11582
|
)
|
|
11009
11583
|
);
|
|
11010
11584
|
}
|
|
11011
11585
|
|
|
11012
11586
|
// src/commands/urls.ts
|
|
11013
|
-
var
|
|
11587
|
+
var import_picocolors40 = __toESM(require_picocolors(), 1);
|
|
11014
11588
|
function registerUrls(program3) {
|
|
11015
11589
|
program3.command("urls").description("The stable preview and production addresses of every app in this project").option("--app <webAppId>", "just one app").action(
|
|
11016
11590
|
action(async ({ ctx, opts }) => {
|
|
@@ -11024,20 +11598,20 @@ function registerUrls(program3) {
|
|
|
11024
11598
|
const summary = urlsSummary(rows);
|
|
11025
11599
|
ok({ rows, summary }, () => {
|
|
11026
11600
|
for (const row of rows) {
|
|
11027
|
-
const label =
|
|
11028
|
-
const value = row.url ?
|
|
11601
|
+
const label = import_picocolors40.default.dim(row.environment.padEnd(10));
|
|
11602
|
+
const value = row.url ? import_picocolors40.default.cyan(row.url) : import_picocolors40.default.dim(row.note ?? "not published");
|
|
11029
11603
|
line(` ${row.appName.padEnd(22)} ${label} ${value}`);
|
|
11030
11604
|
}
|
|
11031
11605
|
line("");
|
|
11032
11606
|
if (rows.some((r) => r.url)) success(summary);
|
|
11033
|
-
else line(
|
|
11607
|
+
else line(import_picocolors40.default.yellow(summary));
|
|
11034
11608
|
});
|
|
11035
11609
|
})
|
|
11036
11610
|
);
|
|
11037
11611
|
}
|
|
11038
11612
|
|
|
11039
11613
|
// src/commands/deployments.ts
|
|
11040
|
-
var
|
|
11614
|
+
var import_picocolors41 = __toESM(require_picocolors(), 1);
|
|
11041
11615
|
function registerDeployments(program3) {
|
|
11042
11616
|
const cmd = program3.command("deployments").description("Deployment history, and putting a build in front of customers");
|
|
11043
11617
|
cmd.command("list").description("What has been built, newest first").option("--app <webAppId>", "just one app (default: every app in the project)").option("--env <environment>", "preview or production").option("--limit <n>", "how many to show", "20").action(
|
|
@@ -11055,7 +11629,7 @@ function registerDeployments(program3) {
|
|
|
11055
11629
|
ok(res, () => {
|
|
11056
11630
|
if (!items.length) {
|
|
11057
11631
|
return line(
|
|
11058
|
-
|
|
11632
|
+
import_picocolors41.default.dim(
|
|
11059
11633
|
environment ? `Nothing has been deployed to ${environment} yet.` : "Nothing has been deployed yet. `workser deploy` builds the first one."
|
|
11060
11634
|
)
|
|
11061
11635
|
);
|
|
@@ -11075,13 +11649,13 @@ function registerDeployments(program3) {
|
|
|
11075
11649
|
).catch(() => null) : null;
|
|
11076
11650
|
ok({ ...dep, logs }, () => {
|
|
11077
11651
|
line(formatDeployment(dep));
|
|
11078
|
-
if (dep?.error_message) line(
|
|
11652
|
+
if (dep?.error_message) line(import_picocolors41.default.red(` ${dep.error_message}`));
|
|
11079
11653
|
const events = logs?.events ?? [];
|
|
11080
11654
|
for (const e of events) {
|
|
11081
|
-
line(` ${
|
|
11655
|
+
line(` ${import_picocolors41.default.dim(String(e.type ?? "log"))} ${e.text ?? ""}`);
|
|
11082
11656
|
}
|
|
11083
11657
|
if (opts.logs && !events.length) {
|
|
11084
|
-
line(
|
|
11658
|
+
line(import_picocolors41.default.dim(" That build produced no output."));
|
|
11085
11659
|
}
|
|
11086
11660
|
});
|
|
11087
11661
|
})
|
|
@@ -11125,16 +11699,16 @@ function printPromoted(res, version) {
|
|
|
11125
11699
|
const what = version === null ? "the latest build" : `version ${version}`;
|
|
11126
11700
|
const url = res.url ?? res.vercel_url;
|
|
11127
11701
|
success(`Production is being rebuilt from ${what}.`);
|
|
11128
|
-
if (url) line(
|
|
11129
|
-
line(
|
|
11702
|
+
if (url) line(import_picocolors41.default.dim(`It will be at ${url}`));
|
|
11703
|
+
line(import_picocolors41.default.dim("`workser deploy status` follows it."));
|
|
11130
11704
|
}
|
|
11131
11705
|
function formatDeployment(d) {
|
|
11132
11706
|
if (!d) return "";
|
|
11133
|
-
const version = d.version !== void 0 ?
|
|
11134
|
-
const env =
|
|
11707
|
+
const version = d.version !== void 0 ? import_picocolors41.default.yellow(`v${d.version}`) : import_picocolors41.default.dim("v?");
|
|
11708
|
+
const env = import_picocolors41.default.dim((d.environment ?? "?").padEnd(10));
|
|
11135
11709
|
const app = d.webAppName ? `${d.webAppName} ` : "";
|
|
11136
|
-
const when =
|
|
11137
|
-
const url = d.url ? " " +
|
|
11710
|
+
const when = import_picocolors41.default.dim(formatTime2(d.created_at));
|
|
11711
|
+
const url = d.url ? " " + import_picocolors41.default.cyan(d.url) : "";
|
|
11138
11712
|
return `${version} ${env} ${colorStatus(d.status ?? "")} ${app}${when}${url}`;
|
|
11139
11713
|
}
|
|
11140
11714
|
function formatTime2(t) {
|
|
@@ -11144,7 +11718,7 @@ function formatTime2(t) {
|
|
|
11144
11718
|
}
|
|
11145
11719
|
|
|
11146
11720
|
// src/commands/usage.ts
|
|
11147
|
-
var
|
|
11721
|
+
var import_picocolors42 = __toESM(require_picocolors(), 1);
|
|
11148
11722
|
|
|
11149
11723
|
// src/usage.ts
|
|
11150
11724
|
var NEAR_LIMIT_FRACTION = 0.8;
|
|
@@ -11239,7 +11813,7 @@ function registerUsage(program3) {
|
|
|
11239
11813
|
function print4(report) {
|
|
11240
11814
|
const dims = report.dimensions ?? [];
|
|
11241
11815
|
if (!dims.length) {
|
|
11242
|
-
return line(
|
|
11816
|
+
return line(import_picocolors42.default.dim("Nothing to measure for this project yet."));
|
|
11243
11817
|
}
|
|
11244
11818
|
const width = Math.max(...dims.map((d) => d.label.length));
|
|
11245
11819
|
for (const d of dims) {
|
|
@@ -11248,23 +11822,23 @@ function print4(report) {
|
|
|
11248
11822
|
line("");
|
|
11249
11823
|
const summary = usageSummary(report);
|
|
11250
11824
|
const worst = dims.map(usageState);
|
|
11251
|
-
if (worst.includes("over")) line(
|
|
11825
|
+
if (worst.includes("over")) line(import_picocolors42.default.red(summary));
|
|
11252
11826
|
else if (worst.includes("near") || worst.includes("unknown"))
|
|
11253
|
-
line(
|
|
11827
|
+
line(import_picocolors42.default.yellow(summary));
|
|
11254
11828
|
else success(summary);
|
|
11255
11829
|
}
|
|
11256
11830
|
function gauge(d, _labelWidth) {
|
|
11257
11831
|
const drawn = bar(d);
|
|
11258
|
-
return drawn ? ` ${
|
|
11832
|
+
return drawn ? ` ${import_picocolors42.default.dim(drawn)}` : "";
|
|
11259
11833
|
}
|
|
11260
11834
|
function colour(d) {
|
|
11261
11835
|
switch (usageState(d)) {
|
|
11262
11836
|
case "over":
|
|
11263
|
-
return d.kind === "hard" ?
|
|
11837
|
+
return d.kind === "hard" ? import_picocolors42.default.red : import_picocolors42.default.yellow;
|
|
11264
11838
|
case "near":
|
|
11265
|
-
return
|
|
11839
|
+
return import_picocolors42.default.yellow;
|
|
11266
11840
|
case "unknown":
|
|
11267
|
-
return
|
|
11841
|
+
return import_picocolors42.default.dim;
|
|
11268
11842
|
default:
|
|
11269
11843
|
return (s) => s;
|
|
11270
11844
|
}
|
|
@@ -11272,7 +11846,7 @@ function colour(d) {
|
|
|
11272
11846
|
|
|
11273
11847
|
// src/index.ts
|
|
11274
11848
|
var pkg = {
|
|
11275
|
-
version: true ? "0.6.
|
|
11849
|
+
version: true ? "0.6.18" : "0.0.0-dev"
|
|
11276
11850
|
};
|
|
11277
11851
|
var program2 = new Command();
|
|
11278
11852
|
program2.name("workser").description(
|
|
@@ -11305,6 +11879,7 @@ registerDomain(program2);
|
|
|
11305
11879
|
registerOpen(program2);
|
|
11306
11880
|
registerDoctor(program2);
|
|
11307
11881
|
registerAgent(program2);
|
|
11882
|
+
registerAgentCloud(program2);
|
|
11308
11883
|
registerVerify(program2);
|
|
11309
11884
|
registerApi(program2);
|
|
11310
11885
|
registerAnalysis(program2);
|