@workser/cli 0.6.16 → 0.6.17

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 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/verify.ts
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(import_picocolors17.default.dim(res.note ?? "No checks detected."));
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 ? import_picocolors17.default.green("\u2713") : import_picocolors17.default.red("\u2717")} ${c.name}${c.ok ? "" : import_picocolors17.default.dim(` (exit ${c.exitCode})`)}`
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
- import_picocolors17.default.red("Some checks failed \u2014 fix the errors above and re-run ") + import_picocolors17.default.bold("workser verify") + import_picocolors17.default.red(".")
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 import_picocolors18 = __toESM(require_picocolors(), 1);
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(import_picocolors18.default.dim(` ${p.ref.slice(0, 7)}`));
7519
- line(import_picocolors18.default.dim(" Come back to it with `workser restore`."));
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
- import_picocolors18.default.dim(
8055
+ import_picocolors19.default.dim(
7546
8056
  ` ${res.filesChanged} file${res.filesChanged === 1 ? "" : "s"} changed`
7547
8057
  )
7548
8058
  );
7549
8059
  }
7550
- line(import_picocolors18.default.dim(" This is reversible: `workser restore` again."));
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(import_picocolors18.default.dim(" Take one with `workser checkpoint`."));
8077
+ line(import_picocolors19.default.dim(" Take one with `workser checkpoint`."));
7568
8078
  return;
7569
8079
  }
7570
- line(import_picocolors18.default.bold("Checkpoints"));
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
- ` ${import_picocolors18.default.dim(p.ref.slice(0, 7))} ${p.label}${when ? import_picocolors18.default.dim(` ${when}`) : ""}`
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
- import_picocolors18.default.dim(
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 import_picocolors19 = __toESM(require_picocolors(), 1);
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
- import_picocolors19.default.dim(
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(import_picocolors19.default.dim(` ${String(res.ref).slice(0, 7)}`));
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 import_picocolors20 = __toESM(require_picocolors(), 1);
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(import_picocolors20.default.dim("No workflows yet. `workser workflow create`."));
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 ? import_picocolors20.default.green("active") : import_picocolors20.default.dim("inactive");
7643
- line(`${w.id} ${import_picocolors20.default.bold(w.name ?? "Untitled")} ${status}`);
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 ${import_picocolors20.default.bold(res.id)}.`));
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(import_picocolors20.default.dim("No runs yet."));
7691
- for (const e of items) line(`${e.id} ${e.status ?? ""} ${import_picocolors20.default.dim(e.started_at ?? "")}`);
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(import_picocolors20.default.dim("No matching node types."));
7700
- for (const n of items) line(`${n.name ?? n.type} ${import_picocolors20.default.dim(n.category ?? "")}`);
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 import_picocolors21 = __toESM(require_picocolors(), 1);
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) ? import_picocolors21.default.green("connected") : import_picocolors21.default.dim("not connected");
7721
- line(`${t.slug} ${import_picocolors21.default.bold(t.name ?? t.slug)} ${status}`);
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(import_picocolors21.default.dim("No matching actions."));
8243
+ if (!items?.length) return line(import_picocolors22.default.dim("No matching actions."));
7734
8244
  for (const t of items) {
7735
- line(`${t.slug} ${import_picocolors21.default.dim(`[${t.toolkit}]`)} ${t.description ?? ""}`);
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: ${import_picocolors21.default.underline(res.oauth_url)}`) : line(`Connection ${res.connection_id} is ${res.status}.`)
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(import_picocolors21.default.dim("No tools found."));
7771
- for (const t of items) line(`${t.slug} ${import_picocolors21.default.dim(t.description ?? "")}`);
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 import_picocolors22 = __toESM(require_picocolors(), 1);
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(import_picocolors22.default.dim("No tools available."));
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(import_picocolors22.default.bold(category) + ":");
8314
+ line(import_picocolors23.default.bold(category) + ":");
7805
8315
  for (const t of items) {
7806
- line(` ${t.name} ${import_picocolors22.default.dim(t.description ?? "")}`);
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 import_picocolors23 = __toESM(require_picocolors(), 1);
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(import_picocolors23.default.dim("No matching memories."));
8358
+ if (!results?.length) return line(import_picocolors24.default.dim("No matching memories."));
7849
8359
  for (const r of results) {
7850
- line(`${import_picocolors23.default.dim(r.id ?? "?")} ${memoryText(r)}`);
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 import_picocolors23.default.dim("(no readable text on this row)");
8380
+ return import_picocolors24.default.dim("(no readable text on this row)");
7871
8381
  }
7872
8382
 
7873
8383
  // src/commands/note.ts
7874
- var import_picocolors24 = __toESM(require_picocolors(), 1);
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(import_picocolors24.default.dim(` ${text}`));
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 import_picocolors25 = __toESM(require_picocolors(), 1);
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} ${import_picocolors25.default.bold(res?.id ?? "")}.`));
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 import_picocolors26 = __toESM(require_picocolors(), 1);
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 ${import_picocolors26.default.bold(res?.title ?? "artifact")}${res?.kind ? import_picocolors26.default.dim(` (${res.kind})`) : ""}`
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, () => printRun(res));
8659
+ ok(res, () => printRun2(res));
8150
8660
  })
8151
8661
  );
8152
8662
  }
8153
8663
  function printArtifacts(rows) {
8154
8664
  if (!rows.length) {
8155
- line(import_picocolors26.default.dim("Nothing produced yet."));
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(import_picocolors26.default.bold(`step ${stepId}`));
8675
+ line(import_picocolors27.default.bold(`step ${stepId}`));
8166
8676
  for (const a of items) {
8167
- const flag = a.promoted_at ? import_picocolors26.default.green(" *") : " ";
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} ${import_picocolors26.default.dim(`[${a.kind}]`)} ${a.title ?? "(untitled)"}` + (where ? import_picocolors26.default.dim(` ${where}`) : "")
8680
+ `${flag} ${import_picocolors27.default.dim(`[${a.kind}]`)} ${a.title ?? "(untitled)"}` + (where ? import_picocolors27.default.dim(` ${where}`) : "")
8171
8681
  );
8172
- if (a.description) line(import_picocolors26.default.dim(` ${a.description}`));
8682
+ if (a.description) line(import_picocolors27.default.dim(` ${a.description}`));
8173
8683
  }
8174
8684
  line("");
8175
8685
  }
8176
- line(import_picocolors26.default.dim("* = handed over as a deliverable; the rest is working material."));
8686
+ line(import_picocolors27.default.dim("* = handed over as a deliverable; the rest is working material."));
8177
8687
  }
8178
- function printRun(run) {
8688
+ function printRun2(run) {
8179
8689
  if (!run) return;
8180
- line(` run ${import_picocolors26.default.bold(run.runId)}`);
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 ${import_picocolors26.default.dim(run.cwd)}`);
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 import_picocolors27 = __toESM(require_picocolors(), 1);
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(import_picocolors27.default.dim("Waiting for the user to answer\u2026"));
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(` ${import_picocolors27.default.green("answered")}`);
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(` ${import_picocolors27.default.yellow(res.status)} ${import_picocolors27.default.dim(res.reason ?? "")}`);
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 import_picocolors28 = __toESM(require_picocolors(), 1);
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(import_picocolors28.default.dim("No results."));
9018
+ if (!results.length) return line(import_picocolors29.default.dim("No results."));
8509
9019
  for (const r of results) {
8510
- line(`${r.title || import_picocolors28.default.dim("(untitled)")} ${import_picocolors28.default.dim(r.url)}`);
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 import_picocolors29 = __toESM(require_picocolors(), 1);
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(import_picocolors29.default.dim("No cards on the Board yet."));
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(`${import_picocolors29.default.bold(row.title)} ${import_picocolors29.default.dim(row.id)}`);
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 ${import_picocolors29.default.bold(row?.id ?? "")} \u2014 ${title}`));
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 ${import_picocolors29.default.bold(row.id)} \u2014 ${row.title} ${statusTag(row.status)}`));
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 ${import_picocolors29.default.bold(row.title)} \u2192 ${statusTag(row.status)}`));
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 ${import_picocolors29.default.bold(row.title)} ${statusTag(row.status)}`));
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 ? import_picocolors29.default.dim(` [${r.labels.join(", ")}]`) : "";
8699
- const owner = r.ownerHuman ? import_picocolors29.default.dim(` @${r.ownerHuman}`) : "";
8700
- return `${import_picocolors29.default.dim(r.id)} ${statusTag(r.status)} ${r.title}${labels}${owner}`;
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 import_picocolors29.default.green(label);
8705
- if (status === "in-progress") return import_picocolors29.default.yellow(label);
8706
- if (status === "in-review") return import_picocolors29.default.cyan(label);
8707
- return import_picocolors29.default.dim(label);
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 import_picocolors30 = __toESM(require_picocolors(), 1);
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(import_picocolors30.default.dim("No tasks on the board yet."));
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
- `${import_picocolors30.default.green("opened")} ${import_picocolors30.default.bold(row.title)} ${import_picocolors30.default.dim(row.key ?? row.id)}`
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(import_picocolors30.default.dim("posted to the channel as Project Manager"));
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
- `${import_picocolors30.default.green("added")} ${import_picocolors30.default.bold(row.title)} ${import_picocolors30.default.dim(row.key ?? row.id)}`
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(import_picocolors30.default.dim(`role: ${row.role}`));
9538
+ if (row.role) line(import_picocolors31.default.dim(`role: ${row.role}`));
9022
9539
  if (runner) {
9023
9540
  line(
9024
- import_picocolors30.default.dim(
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(import_picocolors30.default.dim("No subtasks yet."));
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(`${import_picocolors30.default.green("updated")} ${import_picocolors30.default.bold(row.title)}`));
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(import_picocolors30.default.green("removed")));
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(`${import_picocolors30.default.green("moved")} ${import_picocolors30.default.bold(row.title)} \u2192 ${args[1]}`)
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(import_picocolors30.default.yellow("could not resume it \u2014 check the step id"));
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
- `${import_picocolors30.default.green("resumed")} \u2014 ${started} step${started === 1 ? "" : "s"} started`
9652
+ `${import_picocolors31.default.green("resumed")} \u2014 ${started} step${started === 1 ? "" : "s"} started`
9136
9653
  );
9137
9654
  return;
9138
9655
  }
9139
9656
  line(
9140
- `${import_picocolors30.default.green("resumed")} \u2014 it is queued, but nothing started yet. Check the plan is approved and that no step is blocking the rest.`
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(`${import_picocolors30.default.green("sent back")} \u2014 it will be picked up again`);
9671
+ line(`${import_picocolors31.default.green("sent back")} \u2014 it will be picked up again`);
9155
9672
  return;
9156
9673
  }
9157
9674
  line(
9158
- import_picocolors30.default.yellow(
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(import_picocolors30.default.green("approved \u2014 you may start")));
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
- import_picocolors30.default.green(
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(import_picocolors30.default.yellow(row?.note ?? "Nothing started."));
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" ? import_picocolors30.default.yellow(
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(`${import_picocolors30.default.green(row.approval_state)} ${import_picocolors30.default.bold(row.title)}`)
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(`${import_picocolors30.default.green("ready")} ${import_picocolors30.default.bold(row.title)}`));
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 = import_picocolors30.default.dim((r.key ?? r.id.slice(0, 8)).padEnd(10));
9298
- const steps = r.subtaskTotal ? import_picocolors30.default.dim(` ${r.subtaskDone}/${r.subtaskTotal}`) : "";
9299
- const gate = r.approval_state === "awaiting" ? import_picocolors30.default.yellow(" awaiting approval") : "";
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 = import_picocolors30.default.dim(String(index).padStart(2, "0"));
9304
- const role = r.role ? import_picocolors30.default.dim(` [${r.role}]`) : "";
9305
- const scope = r.scope_paths?.length ? import_picocolors30.default.dim(` owns: ${r.scope_paths.join(", ")}`) : "";
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
- ${import_picocolors30.default.dim(wrapped)}`;
9828
+ ${import_picocolors31.default.dim(wrapped)}`;
9312
9829
  }
9313
9830
  function printTask(row, goal) {
9314
- line(`${import_picocolors30.default.bold(row.title)} ${import_picocolors30.default.dim(row.key ?? row.id)}`);
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
- ${import_picocolors30.default.bold("subtasks")}`);
9844
+ ${import_picocolors31.default.bold("subtasks")}`);
9328
9845
  row.subtasks.forEach((s, i) => line(formatSubtask(s, i + 1)));
9329
9846
  line(
9330
- import_picocolors30.default.dim(
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
- import_picocolors30.default.dim(
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(import_picocolors30.default.dim("\nNo subtasks yet."));
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
- ${import_picocolors30.default.bold("part of")}: ${goal.title}`);
9348
- if (goal.outcome) line(import_picocolors30.default.dim(`done means: ${goal.outcome}`));
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 ? import_picocolors30.default.cyan(" <- this task") : "";
9353
- const mark = p.state === "done" ? import_picocolors30.default.green("*") : import_picocolors30.default.dim("-");
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
- import_picocolors30.default.dim(
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
- import_picocolors30.default.dim(
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
- import_picocolors30.default.dim(
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,22 +9895,22 @@ 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 import_picocolors30.default.green("[ready]");
9898
+ return import_picocolors31.default.green("[ready]");
9382
9899
  case "working":
9383
- return import_picocolors30.default.blue("[working]");
9900
+ return import_picocolors31.default.blue("[working]");
9384
9901
  case "checking":
9385
- return import_picocolors30.default.cyan("[checking]");
9902
+ return import_picocolors31.default.cyan("[checking]");
9386
9903
  case "accepted":
9387
- return import_picocolors30.default.green("[accepted]");
9904
+ return import_picocolors31.default.green("[accepted]");
9388
9905
  case "archived":
9389
- return import_picocolors30.default.dim("[archived]");
9906
+ return import_picocolors31.default.dim("[archived]");
9390
9907
  default:
9391
- return import_picocolors30.default.dim("[todo]");
9908
+ return import_picocolors31.default.dim("[todo]");
9392
9909
  }
9393
9910
  }
9394
9911
 
9395
9912
  // src/commands/goal.ts
9396
- var import_picocolors31 = __toESM(require_picocolors(), 1);
9913
+ var import_picocolors32 = __toESM(require_picocolors(), 1);
9397
9914
  var STATUSES3 = ["proposed", "agreed", "working", "delivered", "abandoned"];
9398
9915
  function registerGoal(program3) {
9399
9916
  const goal = program3.command("goal").description("Business goals and the phases that deliver them");
@@ -9405,7 +9922,7 @@ function registerGoal(program3) {
9405
9922
  }) ?? [];
9406
9923
  ok(rows, () => {
9407
9924
  if (!rows.length) {
9408
- line(import_picocolors31.default.dim("No goals yet \u2014 every task here stands on its own."));
9925
+ line(import_picocolors32.default.dim("No goals yet \u2014 every task here stands on its own."));
9409
9926
  return;
9410
9927
  }
9411
9928
  for (const g of rows) line(formatGoal(g));
@@ -9482,10 +9999,10 @@ function registerGoal(program3) {
9482
9999
  }
9483
10000
  });
9484
10001
  ok(row, () => {
9485
- success(`Proposed ${import_picocolors31.default.bold(row?.title ?? "goal")}`);
10002
+ success(`Proposed ${import_picocolors32.default.bold(row?.title ?? "goal")}`);
9486
10003
  printGoal(row);
9487
10004
  line(
9488
- import_picocolors31.default.dim(
10005
+ import_picocolors32.default.dim(
9489
10006
  "\nNothing has been created yet. The owner agrees the shape first."
9490
10007
  )
9491
10008
  );
@@ -9514,7 +10031,7 @@ function registerGoal(program3) {
9514
10031
  ok(
9515
10032
  row,
9516
10033
  () => line(
9517
- row?.recorded ? met === true ? import_picocolors31.default.green("recorded \u2014 met") : met === false ? import_picocolors31.default.yellow("recorded \u2014 not met") : import_picocolors31.default.dim("recorded \u2014 back to unchecked") : import_picocolors31.default.yellow(
10034
+ 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
10035
  "couldn't record it \u2014 check the goal id, the phase name and the criterion id"
9519
10036
  )
9520
10037
  )
@@ -9557,7 +10074,7 @@ function registerGoal(program3) {
9557
10074
  }
9558
10075
  ok({ goalId, phase, filed }, () => {
9559
10076
  success(
9560
- `Filed ${filed.length} ${filed.length === 1 ? "task" : "tasks"} under ${import_picocolors31.default.bold(phase)}`
10077
+ `Filed ${filed.length} ${filed.length === 1 ? "task" : "tasks"} under ${import_picocolors32.default.bold(phase)}`
9561
10078
  );
9562
10079
  });
9563
10080
  })
@@ -9589,42 +10106,42 @@ function registerGoal(program3) {
9589
10106
  function appScope(g) {
9590
10107
  const n = g.appIds?.length ?? 0;
9591
10108
  if (!n) return "";
9592
- return import_picocolors31.default.dim(` ${n} part${n === 1 ? "" : "s"} of the system`);
10109
+ return import_picocolors32.default.dim(` ${n} part${n === 1 ? "" : "s"} of the system`);
9593
10110
  }
9594
10111
  function formatGoal(g) {
9595
- const where = g.currentPhase && g.status !== "delivered" ? import_picocolors31.default.dim(` now: ${g.currentPhase}`) : "";
9596
- const count = g.taskTotal != null ? import_picocolors31.default.dim(` ${g.taskDone}/${g.taskTotal} done`) : "";
9597
- return `${statusTag3(g.status)} ${g.title}${appScope(g)}${where}${count} ${import_picocolors31.default.dim(g.id)}`;
10112
+ const where = g.currentPhase && g.status !== "delivered" ? import_picocolors32.default.dim(` now: ${g.currentPhase}`) : "";
10113
+ const count = g.taskTotal != null ? import_picocolors32.default.dim(` ${g.taskDone}/${g.taskTotal} done`) : "";
10114
+ return `${statusTag3(g.status)} ${g.title}${appScope(g)}${where}${count} ${import_picocolors32.default.dim(g.id)}`;
9598
10115
  }
9599
10116
  function printGoal(g) {
9600
10117
  if (!g) return;
9601
- line(`${import_picocolors31.default.bold(g.title)} ${import_picocolors31.default.dim(g.id)}`);
10118
+ line(`${import_picocolors32.default.bold(g.title)} ${import_picocolors32.default.dim(g.id)}`);
9602
10119
  line(statusTag3(g.status));
9603
10120
  if (g.outcome) line(`
9604
10121
  done means: ${g.outcome}`);
9605
10122
  const progress = g.progress ?? [];
9606
10123
  if (!progress.length) {
9607
- line(import_picocolors31.default.dim("\nNo phases agreed yet."));
10124
+ line(import_picocolors32.default.dim("\nNo phases agreed yet."));
9608
10125
  return;
9609
10126
  }
9610
10127
  line(`
9611
- ${import_picocolors31.default.bold("phases")}`);
10128
+ ${import_picocolors32.default.bold("phases")}`);
9612
10129
  for (const p of progress) {
9613
- const bar2 = p.total > 0 ? `${p.done}/${p.total} done` : import_picocolors31.default.dim("nothing filed yet");
9614
- const mark = p.state === "done" ? import_picocolors31.default.green("done") : p.state === "working" ? import_picocolors31.default.blue("working") : import_picocolors31.default.dim("waiting");
10130
+ const bar2 = p.total > 0 ? `${p.done}/${p.total} done` : import_picocolors32.default.dim("nothing filed yet");
10131
+ const mark = p.state === "done" ? import_picocolors32.default.green("done") : p.state === "working" ? import_picocolors32.default.blue("working") : import_picocolors32.default.dim("waiting");
9615
10132
  line(
9616
- ` ${import_picocolors31.default.dim(String(p.index).padStart(2, "0"))} ${p.name} ${mark} ${import_picocolors31.default.dim(bar2)}`
10133
+ ` ${import_picocolors32.default.dim(String(p.index).padStart(2, "0"))} ${p.name} ${mark} ${import_picocolors32.default.dim(bar2)}`
9617
10134
  );
9618
10135
  for (const c of p.criteria ?? []) {
9619
- const tick = c.met === true ? import_picocolors31.default.green("\u2713") : c.met === false ? import_picocolors31.default.red("\u2717") : import_picocolors31.default.dim("\xB7");
9620
- line(` ${tick} ${c.text} ${import_picocolors31.default.dim(c.id)}`);
9621
- if (c.note) line(import_picocolors31.default.dim(` ${c.note}`));
10136
+ const tick = c.met === true ? import_picocolors32.default.green("\u2713") : c.met === false ? import_picocolors32.default.red("\u2717") : import_picocolors32.default.dim("\xB7");
10137
+ line(` ${tick} ${c.text} ${import_picocolors32.default.dim(c.id)}`);
10138
+ if (c.note) line(import_picocolors32.default.dim(` ${c.note}`));
9622
10139
  }
9623
10140
  }
9624
10141
  const current = progress.find((p) => p.name === g.currentPhase);
9625
10142
  if (current) {
9626
10143
  line(
9627
- import_picocolors31.default.dim(
10144
+ import_picocolors32.default.dim(
9628
10145
  `
9629
10146
  ${current.name} \u2014 ${current.done} of ${current.total} done (phase ${current.index} of ${progress.length}).`
9630
10147
  )
@@ -9634,15 +10151,15 @@ ${current.name} \u2014 ${current.done} of ${current.total} done (phase ${current
9634
10151
  function statusTag3(status) {
9635
10152
  switch (status) {
9636
10153
  case "agreed":
9637
- return import_picocolors31.default.cyan("[agreed]");
10154
+ return import_picocolors32.default.cyan("[agreed]");
9638
10155
  case "working":
9639
- return import_picocolors31.default.blue("[working]");
10156
+ return import_picocolors32.default.blue("[working]");
9640
10157
  case "delivered":
9641
- return import_picocolors31.default.green("[delivered]");
10158
+ return import_picocolors32.default.green("[delivered]");
9642
10159
  case "abandoned":
9643
- return import_picocolors31.default.dim("[abandoned]");
10160
+ return import_picocolors32.default.dim("[abandoned]");
9644
10161
  default:
9645
- return import_picocolors31.default.yellow("[proposed]");
10162
+ return import_picocolors32.default.yellow("[proposed]");
9646
10163
  }
9647
10164
  }
9648
10165
 
@@ -9826,7 +10343,7 @@ function stripLeadingGlobalOptions(argv) {
9826
10343
  }
9827
10344
 
9828
10345
  // src/commands/decision.ts
9829
- var import_picocolors32 = __toESM(require_picocolors(), 1);
10346
+ var import_picocolors33 = __toESM(require_picocolors(), 1);
9830
10347
  function registerDecision(program3) {
9831
10348
  const decision = program3.command("decision").description("Read and record the project's architecture decisions");
9832
10349
  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 +10356,11 @@ function registerDecision(program3) {
9839
10356
  rows = applyLimit(rows, opts.limit);
9840
10357
  ok(rows, () => {
9841
10358
  if (!rows.length) {
9842
- line(import_picocolors32.default.dim("No decisions recorded yet."));
10359
+ line(import_picocolors33.default.dim("No decisions recorded yet."));
9843
10360
  return;
9844
10361
  }
9845
10362
  for (const r of rows) {
9846
- line(`${import_picocolors32.default.dim(r.id)} ${import_picocolors32.default.dim(shortDate(r.createdAt))} ${r.title}`);
10363
+ line(`${import_picocolors33.default.dim(r.id)} ${import_picocolors33.default.dim(shortDate(r.createdAt))} ${r.title}`);
9847
10364
  line(` ${truncate(r.decision, 100)}`);
9848
10365
  }
9849
10366
  });
@@ -9857,16 +10374,16 @@ function registerDecision(program3) {
9857
10374
  `/v1/projects/${projectId}/architecture-decisions/${args[0]}`
9858
10375
  );
9859
10376
  ok(row, () => {
9860
- line(`${import_picocolors32.default.bold(row.title)} ${import_picocolors32.default.dim(row.id)}`);
9861
- line(import_picocolors32.default.dim(`${row.status} \xB7 ${shortDate(row.createdAt)}`));
10377
+ line(`${import_picocolors33.default.bold(row.title)} ${import_picocolors33.default.dim(row.id)}`);
10378
+ line(import_picocolors33.default.dim(`${row.status} \xB7 ${shortDate(row.createdAt)}`));
9862
10379
  line(`
9863
- ${import_picocolors32.default.bold("Context")}
10380
+ ${import_picocolors33.default.bold("Context")}
9864
10381
  ${row.context}`);
9865
10382
  line(`
9866
- ${import_picocolors32.default.bold("Decision")}
10383
+ ${import_picocolors33.default.bold("Decision")}
9867
10384
  ${row.decision}`);
9868
10385
  if (row.consequences) line(`
9869
- ${import_picocolors32.default.bold("Consequences")}
10386
+ ${import_picocolors33.default.bold("Consequences")}
9870
10387
  ${row.consequences}`);
9871
10388
  });
9872
10389
  })
@@ -9895,7 +10412,7 @@ ${row.consequences}`);
9895
10412
  refId: row?.id,
9896
10413
  output: { decision: row }
9897
10414
  });
9898
- ok(row, () => line(`Recorded decision ${import_picocolors32.default.bold(row?.id ?? "")} \u2014 ${title}`));
10415
+ ok(row, () => line(`Recorded decision ${import_picocolors33.default.bold(row?.id ?? "")} \u2014 ${title}`));
9899
10416
  })
9900
10417
  );
9901
10418
  const requirement = program3.command("requirement").description("Read and record the project's requirements");
@@ -9907,11 +10424,11 @@ ${row.consequences}`);
9907
10424
  rows = applyLimit(rows, opts.limit);
9908
10425
  ok(rows, () => {
9909
10426
  if (!rows.length) {
9910
- line(import_picocolors32.default.dim("No requirements recorded yet."));
10427
+ line(import_picocolors33.default.dim("No requirements recorded yet."));
9911
10428
  return;
9912
10429
  }
9913
10430
  for (const r of rows) {
9914
- line(`${import_picocolors32.default.dim(r.id)} ${r.status.padEnd(9)} ${r.title}`);
10431
+ line(`${import_picocolors33.default.dim(r.id)} ${r.status.padEnd(9)} ${r.title}`);
9915
10432
  }
9916
10433
  });
9917
10434
  })
@@ -9924,8 +10441,8 @@ ${row.consequences}`);
9924
10441
  `/v1/projects/${projectId}/requirements/${args[0]}`
9925
10442
  );
9926
10443
  ok(row, () => {
9927
- line(`${import_picocolors32.default.bold(row.title)} ${import_picocolors32.default.dim(row.id)}`);
9928
- line(import_picocolors32.default.dim(`${row.status} \xB7 ${shortDate(row.createdAt)}`));
10444
+ line(`${import_picocolors33.default.bold(row.title)} ${import_picocolors33.default.dim(row.id)}`);
10445
+ line(import_picocolors33.default.dim(`${row.status} \xB7 ${shortDate(row.createdAt)}`));
9929
10446
  line(`
9930
10447
  ${row.body}`);
9931
10448
  });
@@ -9951,7 +10468,7 @@ ${row.body}`);
9951
10468
  refId: row?.id,
9952
10469
  output: { requirement: row }
9953
10470
  });
9954
- ok(row, () => line(`Recorded requirement ${import_picocolors32.default.bold(row?.id ?? "")} \u2014 ${title}`));
10471
+ ok(row, () => line(`Recorded requirement ${import_picocolors33.default.bold(row?.id ?? "")} \u2014 ${title}`));
9955
10472
  })
9956
10473
  );
9957
10474
  requirement.command("update <id>").description(
@@ -9980,7 +10497,7 @@ ${row.body}`);
9980
10497
  code: "bad_request"
9981
10498
  });
9982
10499
  }
9983
- ok(row, () => line(`Updated requirement ${import_picocolors32.default.bold(row.id)} \u2014 ${row.title} (${row.status})`));
10500
+ ok(row, () => line(`Updated requirement ${import_picocolors33.default.bold(row.id)} \u2014 ${row.title} (${row.status})`));
9984
10501
  })
9985
10502
  );
9986
10503
  }
@@ -10003,7 +10520,7 @@ function shortDate(iso) {
10003
10520
  }
10004
10521
 
10005
10522
  // src/commands/doc.ts
10006
- var import_picocolors33 = __toESM(require_picocolors(), 1);
10523
+ var import_picocolors34 = __toESM(require_picocolors(), 1);
10007
10524
 
10008
10525
  // src/mermaid-fences.ts
10009
10526
  function hasDiagram(code) {
@@ -10048,13 +10565,13 @@ function registerDoc(program3) {
10048
10565
  }) ?? [];
10049
10566
  ok(rows, () => {
10050
10567
  if (!rows.length) {
10051
- line(import_picocolors33.default.dim("No documents yet."));
10568
+ line(import_picocolors34.default.dim("No documents yet."));
10052
10569
  return;
10053
10570
  }
10054
10571
  for (const r of rows) {
10055
- const link = r.workItemId ? import_picocolors33.default.dim(` \u21B3 ${r.workItemId}`) : "";
10056
- const file = r.filePath ? import_picocolors33.default.dim(` ${r.filePath}`) : "";
10057
- line(`${import_picocolors33.default.dim(r.id)} ${r.title}${link}${file}`);
10572
+ const link = r.workItemId ? import_picocolors34.default.dim(` \u21B3 ${r.workItemId}`) : "";
10573
+ const file = r.filePath ? import_picocolors34.default.dim(` ${r.filePath}`) : "";
10574
+ line(`${import_picocolors34.default.dim(r.id)} ${r.title}${link}${file}`);
10058
10575
  }
10059
10576
  });
10060
10577
  })
@@ -10068,17 +10585,17 @@ function registerDoc(program3) {
10068
10585
  );
10069
10586
  if (opts.markdown) {
10070
10587
  ok({ id: row.id, title: row.title, filePath: row.filePath }, () => {
10071
- line(`${import_picocolors33.default.bold(row.title)} ${import_picocolors33.default.dim(row.id)}`);
10588
+ line(`${import_picocolors34.default.bold(row.title)} ${import_picocolors34.default.dim(row.id)}`);
10072
10589
  line(
10073
- row.filePath ? `Read it at ${import_picocolors33.default.bold(row.filePath)} (relative to the project folder).` : import_picocolors33.default.dim("This document has no markdown mirror on disk yet.")
10590
+ 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
10591
  );
10075
10592
  });
10076
10593
  return;
10077
10594
  }
10078
10595
  ok(row, () => {
10079
- line(`${import_picocolors33.default.bold(row.title)} ${import_picocolors33.default.dim(row.id)}`);
10080
- if (row.workItemId) line(import_picocolors33.default.dim(`linked to work item ${row.workItemId}`));
10081
- if (row.filePath) line(import_picocolors33.default.dim(`markdown mirror: ${row.filePath}`));
10596
+ line(`${import_picocolors34.default.bold(row.title)} ${import_picocolors34.default.dim(row.id)}`);
10597
+ if (row.workItemId) line(import_picocolors34.default.dim(`linked to work item ${row.workItemId}`));
10598
+ if (row.filePath) line(import_picocolors34.default.dim(`markdown mirror: ${row.filePath}`));
10082
10599
  line("");
10083
10600
  line(row.contentJson);
10084
10601
  });
@@ -10107,7 +10624,7 @@ function registerDoc(program3) {
10107
10624
  refId: row?.id,
10108
10625
  output: { document: row }
10109
10626
  });
10110
- ok(row, () => line(`Created document ${import_picocolors33.default.bold(row?.id ?? "")} \u2014 ${title}`));
10627
+ ok(row, () => line(`Created document ${import_picocolors34.default.bold(row?.id ?? "")} \u2014 ${title}`));
10111
10628
  })
10112
10629
  );
10113
10630
  doc.command("diagram <id>").description(
@@ -10133,19 +10650,19 @@ function registerDoc(program3) {
10133
10650
  diagrams: diagrams.map((code) => ({ kind: diagramKind(code), code }))
10134
10651
  };
10135
10652
  ok(payload, () => {
10136
- line(`${import_picocolors33.default.bold(row.title)} ${import_picocolors33.default.dim(row.id)}`);
10653
+ line(`${import_picocolors34.default.bold(row.title)} ${import_picocolors34.default.dim(row.id)}`);
10137
10654
  if (markdown === null) {
10138
10655
  line(
10139
- import_picocolors33.default.dim(
10656
+ import_picocolors34.default.dim(
10140
10657
  row.filePath ? `Could not read ${row.filePath} from this folder.` : "This document has no markdown mirror on disk yet."
10141
10658
  )
10142
10659
  );
10143
10660
  } else if (!diagrams.length) {
10144
- line(import_picocolors33.default.dim("No diagrams in this document."));
10661
+ line(import_picocolors34.default.dim("No diagrams in this document."));
10145
10662
  } else {
10146
10663
  for (const [i, code] of diagrams.entries()) {
10147
10664
  const kind = diagramKind(code) ?? "diagram";
10148
- line(`${import_picocolors33.default.dim(String(i + 1))} ${kind} ${import_picocolors33.default.dim(`${code.split("\n").length} lines`)}`);
10665
+ line(`${import_picocolors34.default.dim(String(i + 1))} ${kind} ${import_picocolors34.default.dim(`${code.split("\n").length} lines`)}`);
10149
10666
  }
10150
10667
  }
10151
10668
  });
@@ -10181,7 +10698,7 @@ function registerDoc(program3) {
10181
10698
  code: "bad_request"
10182
10699
  });
10183
10700
  }
10184
- ok(row, () => line(`Updated document ${import_picocolors33.default.bold(row.id)} \u2014 ${row.title}`));
10701
+ ok(row, () => line(`Updated document ${import_picocolors34.default.bold(row.id)} \u2014 ${row.title}`));
10185
10702
  })
10186
10703
  );
10187
10704
  }
@@ -10195,9 +10712,9 @@ function readMirror(cwd, filePath) {
10195
10712
  }
10196
10713
 
10197
10714
  // src/commands/design.ts
10198
- var import_picocolors34 = __toESM(require_picocolors(), 1);
10715
+ var import_picocolors35 = __toESM(require_picocolors(), 1);
10199
10716
  function registerDesign(program3) {
10200
- const design = program3.command("design").description("Read the project's brand (colours, fonts, logo)");
10717
+ const design = program3.command("design").description("The project's brand, and pictures of the screens you draw");
10201
10718
  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
10719
  action(async ({ ctx, opts }) => {
10203
10720
  const projectId = requireProject(ctx);
@@ -10209,11 +10726,11 @@ function registerDesign(program3) {
10209
10726
  if (opts.raw) {
10210
10727
  ok(files, () => {
10211
10728
  if (!files.length) {
10212
- line(import_picocolors34.default.dim("No brand set for this project."));
10729
+ line(import_picocolors35.default.dim("No brand set for this project."));
10213
10730
  return;
10214
10731
  }
10215
10732
  for (const f of files) {
10216
- line(import_picocolors34.default.bold(f.path));
10733
+ line(import_picocolors35.default.bold(f.path));
10217
10734
  line(f.contents);
10218
10735
  line("");
10219
10736
  }
@@ -10230,27 +10747,62 @@ function registerDesign(program3) {
10230
10747
  } : { hasBrand: false, colors: {}, fonts: {}, brand: {}, files: [] };
10231
10748
  ok(summary, () => {
10232
10749
  if (!tokens) {
10233
- line(import_picocolors34.default.dim("No brand set for this project \u2014 choose sensible styling yourself."));
10750
+ line(import_picocolors35.default.dim("No brand set for this project \u2014 choose sensible styling yourself."));
10234
10751
  return;
10235
10752
  }
10236
10753
  for (const [name, value] of Object.entries(tokens.brand)) {
10237
- line(`${import_picocolors34.default.dim(name.padEnd(12))} ${value}`);
10754
+ line(`${import_picocolors35.default.dim(name.padEnd(12))} ${value}`);
10238
10755
  }
10239
10756
  for (const [name, value] of Object.entries(tokens.color)) {
10240
- line(`${import_picocolors34.default.dim(`color.${name}`.padEnd(12))} ${value}`);
10757
+ line(`${import_picocolors35.default.dim(`color.${name}`.padEnd(12))} ${value}`);
10241
10758
  }
10242
10759
  for (const [name, value] of Object.entries(tokens.font)) {
10243
- line(`${import_picocolors34.default.dim(`font.${name}`.padEnd(12))} ${value}`);
10760
+ line(`${import_picocolors35.default.dim(`font.${name}`.padEnd(12))} ${value}`);
10244
10761
  }
10245
10762
  line("");
10246
10763
  line(
10247
- import_picocolors34.default.dim(
10764
+ import_picocolors35.default.dim(
10248
10765
  `Generated into the working tree as ${files.map((f) => f.path).join(", ")} \u2014 wire those in, never edit them.`
10249
10766
  )
10250
10767
  );
10251
10768
  });
10252
10769
  })
10253
10770
  );
10771
+ 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(
10772
+ action(async ({ ctx, args, opts }) => {
10773
+ const projectId = requireProject(ctx);
10774
+ const res = await api(ctx, "/v1/design-shot", {
10775
+ method: "POST",
10776
+ body: {
10777
+ projectId,
10778
+ files: args,
10779
+ width: opts.width,
10780
+ height: opts.height
10781
+ }
10782
+ });
10783
+ ok(res, () => {
10784
+ for (const shot of res.shots ?? []) {
10785
+ if (shot.out) {
10786
+ line(`${import_picocolors35.default.green("\u2713")} ${shot.file} ${import_picocolors35.default.dim("\u2192")} ${shot.out}`);
10787
+ } else {
10788
+ line(`${import_picocolors35.default.red("\u2717")} ${shot.file} ${import_picocolors35.default.dim(shot.error ?? "no image")}`);
10789
+ }
10790
+ }
10791
+ for (const path of res.refused ?? []) {
10792
+ line(import_picocolors35.default.dim(`skipped ${path} \u2014 not a page inside this project`));
10793
+ }
10794
+ const made = (res.shots ?? []).filter((s) => s.out).length;
10795
+ if (made) {
10796
+ line("");
10797
+ line(
10798
+ import_picocolors35.default.dim(
10799
+ `Record each one so it shows up: workser artifact add <file>.png --kind design -d "<what this screen is>"`
10800
+ )
10801
+ );
10802
+ }
10803
+ });
10804
+ })
10805
+ );
10254
10806
  }
10255
10807
  function parseTokens(files) {
10256
10808
  const doc = files.find((f) => f.path.endsWith("tokens.json"));
@@ -10275,7 +10827,7 @@ function unwrap(group) {
10275
10827
  }
10276
10828
 
10277
10829
  // src/commands/api.ts
10278
- var import_picocolors35 = __toESM(require_picocolors(), 1);
10830
+ var import_picocolors36 = __toESM(require_picocolors(), 1);
10279
10831
  import { readdirSync, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
10280
10832
  import { join as join3, relative, sep } from "path";
10281
10833
 
@@ -10389,10 +10941,10 @@ function registerApi(program3) {
10389
10941
  const appId = requireApp2(opts.app);
10390
10942
  const res = await api(ctx, `/v1/apps/${encodeURIComponent(appId)}/api/requests`);
10391
10943
  ok(res, () => {
10392
- for (const note of res?.notes ?? []) line(import_picocolors35.default.dim(note));
10944
+ for (const note of res?.notes ?? []) line(import_picocolors36.default.dim(note));
10393
10945
  for (const r of res?.requests ?? []) {
10394
10946
  line(
10395
- `${import_picocolors35.default.dim(r.method.padEnd(6))}${r.path}${r.note ? import_picocolors35.default.dim(` ${r.note}`) : ""}`
10947
+ `${import_picocolors36.default.dim(r.method.padEnd(6))}${r.path}${r.note ? import_picocolors36.default.dim(` ${r.note}`) : ""}`
10396
10948
  );
10397
10949
  }
10398
10950
  });
@@ -10426,14 +10978,14 @@ function registerApi(program3) {
10426
10978
  );
10427
10979
  ok(res, () => {
10428
10980
  if (!res?.ok) {
10429
- line(import_picocolors35.default.red(res?.error ?? "The service did not answer."));
10981
+ line(import_picocolors36.default.red(res?.error ?? "The service did not answer."));
10430
10982
  return;
10431
10983
  }
10432
10984
  const code = `${res.status}${res.statusText ? ` ${res.statusText}` : ""}`;
10433
- const colour2 = res.status && res.status < 300 ? import_picocolors35.default.green : res.status && res.status < 500 ? import_picocolors35.default.yellow : import_picocolors35.default.red;
10434
- line(`${colour2(code)} ${import_picocolors35.default.dim(`${res.durationMs}ms ${res.url}`)}`);
10985
+ const colour2 = res.status && res.status < 300 ? import_picocolors36.default.green : res.status && res.status < 500 ? import_picocolors36.default.yellow : import_picocolors36.default.red;
10986
+ line(`${colour2(code)} ${import_picocolors36.default.dim(`${res.durationMs}ms ${res.url}`)}`);
10435
10987
  if (res.body) line(res.body);
10436
- if (res.truncated) line(import_picocolors35.default.dim("(answer truncated)"));
10988
+ if (res.truncated) line(import_picocolors36.default.dim("(answer truncated)"));
10437
10989
  });
10438
10990
  if (!res?.ok) process.exitCode = 1;
10439
10991
  })
@@ -10453,15 +11005,15 @@ function registerApi(program3) {
10453
11005
  for (const r of report.routes) {
10454
11006
  const known = report.missing.some((m) => m.path === r.path);
10455
11007
  line(
10456
- `${known ? import_picocolors35.default.yellow("undocumented") : import_picocolors35.default.green("documented ")} ${r.path}${import_picocolors35.default.dim(` ${r.file}`)}`
11008
+ `${known ? import_picocolors36.default.yellow("undocumented") : import_picocolors36.default.green("documented ")} ${r.path}${import_picocolors36.default.dim(` ${r.file}`)}`
10457
11009
  );
10458
11010
  }
10459
11011
  for (const p of report.stale) {
10460
- line(`${import_picocolors35.default.dim("in spec only ")} ${p}`);
11012
+ line(`${import_picocolors36.default.dim("in spec only ")} ${p}`);
10461
11013
  }
10462
11014
  line("");
10463
11015
  if (report.ok && specFile) success(summary);
10464
- else line(import_picocolors35.default.yellow(summary));
11016
+ else line(import_picocolors36.default.yellow(summary));
10465
11017
  });
10466
11018
  if (opts.check && !report.ok) {
10467
11019
  throw new WorkserError(summary, { code: "bad_request" });
@@ -10532,7 +11084,7 @@ function listRepoFiles(root, maxDepth = 8) {
10532
11084
  }
10533
11085
 
10534
11086
  // src/commands/analysis.ts
10535
- var import_picocolors36 = __toESM(require_picocolors(), 1);
11087
+ var import_picocolors37 = __toESM(require_picocolors(), 1);
10536
11088
  import { readFileSync as readFileSync4 } from "fs";
10537
11089
  function registerAnalysis(program3) {
10538
11090
  const cmd = program3.command("analysis").description("Run Python analysis locally, recorded in the task");
@@ -10542,14 +11094,14 @@ function registerAnalysis(program3) {
10542
11094
  const res = await api(ctx, path);
10543
11095
  ok(res, () => {
10544
11096
  line(
10545
- `${res?.available ? import_picocolors36.default.green("python") : import_picocolors36.default.red("python")} ${res?.version ?? "not found"} ${import_picocolors36.default.dim(res?.python ?? "")}`
11097
+ `${res?.available ? import_picocolors37.default.green("python") : import_picocolors37.default.red("python")} ${res?.version ?? "not found"} ${import_picocolors37.default.dim(res?.python ?? "")}`
10546
11098
  );
10547
11099
  for (const lib of res?.libraries ?? []) {
10548
11100
  line(
10549
- `${lib.present ? import_picocolors36.default.green(lib.name) : import_picocolors36.default.yellow(lib.name)}${import_picocolors36.default.dim(lib.present ? "" : " missing")}`
11101
+ `${lib.present ? import_picocolors37.default.green(lib.name) : import_picocolors37.default.yellow(lib.name)}${import_picocolors37.default.dim(lib.present ? "" : " missing")}`
10550
11102
  );
10551
11103
  }
10552
- for (const note of res?.notes ?? []) line(import_picocolors36.default.dim(note));
11104
+ for (const note of res?.notes ?? []) line(import_picocolors37.default.dim(note));
10553
11105
  });
10554
11106
  if (!res?.available) process.exitCode = 1;
10555
11107
  })
@@ -10571,15 +11123,15 @@ function registerAnalysis(program3) {
10571
11123
  );
10572
11124
  ok(res, () => {
10573
11125
  if (res?.stdout) line(res.stdout.replace(/\n$/, ""));
10574
- if (res?.stderr) line(import_picocolors36.default.dim(res.stderr.replace(/\n$/, "")));
10575
- if (res?.truncated) line(import_picocolors36.default.dim("(output truncated)"));
11126
+ if (res?.stderr) line(import_picocolors37.default.dim(res.stderr.replace(/\n$/, "")));
11127
+ if (res?.truncated) line(import_picocolors37.default.dim("(output truncated)"));
10576
11128
  const took = `${Math.round((res?.durationMs ?? 0) / 100) / 10}s`;
10577
11129
  line(
10578
- res?.ok ? import_picocolors36.default.green(`\u2713 ${res.summary ?? "It finished."}`) + import_picocolors36.default.dim(` ${took}`) : import_picocolors36.default.yellow(res?.summary ?? "It did not finish.") + import_picocolors36.default.dim(` ${took}`)
11130
+ 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
11131
  );
10580
11132
  if (res && !res.sandboxed) {
10581
11133
  line(
10582
- import_picocolors36.default.dim(
11134
+ import_picocolors37.default.dim(
10583
11135
  "This platform has no OS sandbox, so the script ran with your own file access."
10584
11136
  )
10585
11137
  );
@@ -10607,7 +11159,7 @@ function readCode(file, inline) {
10607
11159
  }
10608
11160
 
10609
11161
  // src/commands/scan.ts
10610
- var import_picocolors37 = __toESM(require_picocolors(), 1);
11162
+ var import_picocolors38 = __toESM(require_picocolors(), 1);
10611
11163
  import { spawnSync as spawnSync2 } from "child_process";
10612
11164
  import { existsSync as existsSync3, readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync3 } from "fs";
10613
11165
  import { join as join4, relative as relative2, sep as sep2 } from "path";
@@ -10891,22 +11443,22 @@ function runPermissions(cwd, findings, checked, skipped) {
10891
11443
  }
10892
11444
  function print2(report, summary) {
10893
11445
  for (const s of report.skipped) {
10894
- line(`${import_picocolors37.default.yellow("not checked")} ${s.check}${import_picocolors37.default.dim(` \u2014 ${s.reason}`)}`);
11446
+ line(`${import_picocolors38.default.yellow("not checked")} ${s.check}${import_picocolors38.default.dim(` \u2014 ${s.reason}`)}`);
10895
11447
  }
10896
11448
  for (const f of report.findings) {
10897
- const where = f.file ? import_picocolors37.default.dim(` ${f.file}${f.line ? `:${f.line}` : ""}`) : "";
11449
+ const where = f.file ? import_picocolors38.default.dim(` ${f.file}${f.line ? `:${f.line}` : ""}`) : "";
10898
11450
  line(`${severityTag(f.severity)} ${f.title}${where}`);
10899
- line(` ${import_picocolors37.default.dim(f.fix)}`);
11451
+ line(` ${import_picocolors38.default.dim(f.fix)}`);
10900
11452
  }
10901
11453
  if (report.findings.length || report.skipped.length) line("");
10902
11454
  if (report.ok && !report.skipped.length) success(summary);
10903
- else if (report.ok) line(import_picocolors37.default.yellow(summary));
10904
- else line(import_picocolors37.default.red(summary));
11455
+ else if (report.ok) line(import_picocolors38.default.yellow(summary));
11456
+ else line(import_picocolors38.default.red(summary));
10905
11457
  }
10906
11458
  function severityTag(severity) {
10907
- if (severity === "high") return import_picocolors37.default.red("serious ");
10908
- if (severity === "medium") return import_picocolors37.default.yellow("worth fixing");
10909
- return import_picocolors37.default.dim("minor ");
11459
+ if (severity === "high") return import_picocolors38.default.red("serious ");
11460
+ if (severity === "medium") return import_picocolors38.default.yellow("worth fixing");
11461
+ return import_picocolors38.default.dim("minor ");
10910
11462
  }
10911
11463
  function git(cwd, args) {
10912
11464
  try {
@@ -10967,7 +11519,7 @@ function listRepoFiles2(root, maxDepth = 8) {
10967
11519
  }
10968
11520
 
10969
11521
  // src/commands/health.ts
10970
- var import_picocolors38 = __toESM(require_picocolors(), 1);
11522
+ var import_picocolors39 = __toESM(require_picocolors(), 1);
10971
11523
  function registerHealth(program3) {
10972
11524
  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
11525
  action(async ({ ctx, opts }) => {
@@ -10981,16 +11533,16 @@ function registerHealth(program3) {
10981
11533
  }
10982
11534
  function print3(res) {
10983
11535
  if (!res?.checks?.length) {
10984
- line(import_picocolors38.default.dim(res?.note ?? "Nothing to check."));
11536
+ line(import_picocolors39.default.dim(res?.note ?? "Nothing to check."));
10985
11537
  return;
10986
11538
  }
10987
11539
  for (const c of res.checks) {
10988
- const mark = c.ok ? import_picocolors38.default.green("up ") : import_picocolors38.default.red("down");
10989
- const timing = import_picocolors38.default.dim(`${c.ms}ms`);
10990
- const detail = c.ok ? timing : import_picocolors38.default.dim(`${c.error ?? "no answer"}${c.failures > 1 ? ` \xB7 ${c.failures} in a row` : ""}`);
10991
- line(` ${mark} ${c.appName} ${import_picocolors38.default.dim(`(${c.environment})`)} ${c.url} ${detail}`);
11540
+ const mark = c.ok ? import_picocolors39.default.green("up ") : import_picocolors39.default.red("down");
11541
+ const timing = import_picocolors39.default.dim(`${c.ms}ms`);
11542
+ const detail = c.ok ? timing : import_picocolors39.default.dim(`${c.error ?? "no answer"}${c.failures > 1 ? ` \xB7 ${c.failures} in a row` : ""}`);
11543
+ line(` ${mark} ${c.appName} ${import_picocolors39.default.dim(`(${c.environment})`)} ${c.url} ${detail}`);
10992
11544
  if (c.incidentOpened) {
10993
- line(import_picocolors38.default.yellow(` An incident has been opened on the board for this.`));
11545
+ line(import_picocolors39.default.yellow(` An incident has been opened on the board for this.`));
10994
11546
  }
10995
11547
  }
10996
11548
  const down = res.checks.filter((c) => !c.ok);
@@ -11003,14 +11555,14 @@ function print3(res) {
11003
11555
  }
11004
11556
  const production = down.filter((c) => c.environment === "production").length;
11005
11557
  line(
11006
- import_picocolors38.default.red(
11558
+ import_picocolors39.default.red(
11007
11559
  `${down.length} of ${res.checks.length} not answering` + (production ? ` \u2014 ${production} customer-facing.` : " (preview only).")
11008
11560
  )
11009
11561
  );
11010
11562
  }
11011
11563
 
11012
11564
  // src/commands/urls.ts
11013
- var import_picocolors39 = __toESM(require_picocolors(), 1);
11565
+ var import_picocolors40 = __toESM(require_picocolors(), 1);
11014
11566
  function registerUrls(program3) {
11015
11567
  program3.command("urls").description("The stable preview and production addresses of every app in this project").option("--app <webAppId>", "just one app").action(
11016
11568
  action(async ({ ctx, opts }) => {
@@ -11024,20 +11576,20 @@ function registerUrls(program3) {
11024
11576
  const summary = urlsSummary(rows);
11025
11577
  ok({ rows, summary }, () => {
11026
11578
  for (const row of rows) {
11027
- const label = import_picocolors39.default.dim(row.environment.padEnd(10));
11028
- const value = row.url ? import_picocolors39.default.cyan(row.url) : import_picocolors39.default.dim(row.note ?? "not published");
11579
+ const label = import_picocolors40.default.dim(row.environment.padEnd(10));
11580
+ const value = row.url ? import_picocolors40.default.cyan(row.url) : import_picocolors40.default.dim(row.note ?? "not published");
11029
11581
  line(` ${row.appName.padEnd(22)} ${label} ${value}`);
11030
11582
  }
11031
11583
  line("");
11032
11584
  if (rows.some((r) => r.url)) success(summary);
11033
- else line(import_picocolors39.default.yellow(summary));
11585
+ else line(import_picocolors40.default.yellow(summary));
11034
11586
  });
11035
11587
  })
11036
11588
  );
11037
11589
  }
11038
11590
 
11039
11591
  // src/commands/deployments.ts
11040
- var import_picocolors40 = __toESM(require_picocolors(), 1);
11592
+ var import_picocolors41 = __toESM(require_picocolors(), 1);
11041
11593
  function registerDeployments(program3) {
11042
11594
  const cmd = program3.command("deployments").description("Deployment history, and putting a build in front of customers");
11043
11595
  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 +11607,7 @@ function registerDeployments(program3) {
11055
11607
  ok(res, () => {
11056
11608
  if (!items.length) {
11057
11609
  return line(
11058
- import_picocolors40.default.dim(
11610
+ import_picocolors41.default.dim(
11059
11611
  environment ? `Nothing has been deployed to ${environment} yet.` : "Nothing has been deployed yet. `workser deploy` builds the first one."
11060
11612
  )
11061
11613
  );
@@ -11075,13 +11627,13 @@ function registerDeployments(program3) {
11075
11627
  ).catch(() => null) : null;
11076
11628
  ok({ ...dep, logs }, () => {
11077
11629
  line(formatDeployment(dep));
11078
- if (dep?.error_message) line(import_picocolors40.default.red(` ${dep.error_message}`));
11630
+ if (dep?.error_message) line(import_picocolors41.default.red(` ${dep.error_message}`));
11079
11631
  const events = logs?.events ?? [];
11080
11632
  for (const e of events) {
11081
- line(` ${import_picocolors40.default.dim(String(e.type ?? "log"))} ${e.text ?? ""}`);
11633
+ line(` ${import_picocolors41.default.dim(String(e.type ?? "log"))} ${e.text ?? ""}`);
11082
11634
  }
11083
11635
  if (opts.logs && !events.length) {
11084
- line(import_picocolors40.default.dim(" That build produced no output."));
11636
+ line(import_picocolors41.default.dim(" That build produced no output."));
11085
11637
  }
11086
11638
  });
11087
11639
  })
@@ -11125,16 +11677,16 @@ function printPromoted(res, version) {
11125
11677
  const what = version === null ? "the latest build" : `version ${version}`;
11126
11678
  const url = res.url ?? res.vercel_url;
11127
11679
  success(`Production is being rebuilt from ${what}.`);
11128
- if (url) line(import_picocolors40.default.dim(`It will be at ${url}`));
11129
- line(import_picocolors40.default.dim("`workser deploy status` follows it."));
11680
+ if (url) line(import_picocolors41.default.dim(`It will be at ${url}`));
11681
+ line(import_picocolors41.default.dim("`workser deploy status` follows it."));
11130
11682
  }
11131
11683
  function formatDeployment(d) {
11132
11684
  if (!d) return "";
11133
- const version = d.version !== void 0 ? import_picocolors40.default.yellow(`v${d.version}`) : import_picocolors40.default.dim("v?");
11134
- const env = import_picocolors40.default.dim((d.environment ?? "?").padEnd(10));
11685
+ const version = d.version !== void 0 ? import_picocolors41.default.yellow(`v${d.version}`) : import_picocolors41.default.dim("v?");
11686
+ const env = import_picocolors41.default.dim((d.environment ?? "?").padEnd(10));
11135
11687
  const app = d.webAppName ? `${d.webAppName} ` : "";
11136
- const when = import_picocolors40.default.dim(formatTime2(d.created_at));
11137
- const url = d.url ? " " + import_picocolors40.default.cyan(d.url) : "";
11688
+ const when = import_picocolors41.default.dim(formatTime2(d.created_at));
11689
+ const url = d.url ? " " + import_picocolors41.default.cyan(d.url) : "";
11138
11690
  return `${version} ${env} ${colorStatus(d.status ?? "")} ${app}${when}${url}`;
11139
11691
  }
11140
11692
  function formatTime2(t) {
@@ -11144,7 +11696,7 @@ function formatTime2(t) {
11144
11696
  }
11145
11697
 
11146
11698
  // src/commands/usage.ts
11147
- var import_picocolors41 = __toESM(require_picocolors(), 1);
11699
+ var import_picocolors42 = __toESM(require_picocolors(), 1);
11148
11700
 
11149
11701
  // src/usage.ts
11150
11702
  var NEAR_LIMIT_FRACTION = 0.8;
@@ -11239,7 +11791,7 @@ function registerUsage(program3) {
11239
11791
  function print4(report) {
11240
11792
  const dims = report.dimensions ?? [];
11241
11793
  if (!dims.length) {
11242
- return line(import_picocolors41.default.dim("Nothing to measure for this project yet."));
11794
+ return line(import_picocolors42.default.dim("Nothing to measure for this project yet."));
11243
11795
  }
11244
11796
  const width = Math.max(...dims.map((d) => d.label.length));
11245
11797
  for (const d of dims) {
@@ -11248,23 +11800,23 @@ function print4(report) {
11248
11800
  line("");
11249
11801
  const summary = usageSummary(report);
11250
11802
  const worst = dims.map(usageState);
11251
- if (worst.includes("over")) line(import_picocolors41.default.red(summary));
11803
+ if (worst.includes("over")) line(import_picocolors42.default.red(summary));
11252
11804
  else if (worst.includes("near") || worst.includes("unknown"))
11253
- line(import_picocolors41.default.yellow(summary));
11805
+ line(import_picocolors42.default.yellow(summary));
11254
11806
  else success(summary);
11255
11807
  }
11256
11808
  function gauge(d, _labelWidth) {
11257
11809
  const drawn = bar(d);
11258
- return drawn ? ` ${import_picocolors41.default.dim(drawn)}` : "";
11810
+ return drawn ? ` ${import_picocolors42.default.dim(drawn)}` : "";
11259
11811
  }
11260
11812
  function colour(d) {
11261
11813
  switch (usageState(d)) {
11262
11814
  case "over":
11263
- return d.kind === "hard" ? import_picocolors41.default.red : import_picocolors41.default.yellow;
11815
+ return d.kind === "hard" ? import_picocolors42.default.red : import_picocolors42.default.yellow;
11264
11816
  case "near":
11265
- return import_picocolors41.default.yellow;
11817
+ return import_picocolors42.default.yellow;
11266
11818
  case "unknown":
11267
- return import_picocolors41.default.dim;
11819
+ return import_picocolors42.default.dim;
11268
11820
  default:
11269
11821
  return (s) => s;
11270
11822
  }
@@ -11272,7 +11824,7 @@ function colour(d) {
11272
11824
 
11273
11825
  // src/index.ts
11274
11826
  var pkg = {
11275
- version: true ? "0.6.16" : "0.0.0-dev"
11827
+ version: true ? "0.6.17" : "0.0.0-dev"
11276
11828
  };
11277
11829
  var program2 = new Command();
11278
11830
  program2.name("workser").description(
@@ -11305,6 +11857,7 @@ registerDomain(program2);
11305
11857
  registerOpen(program2);
11306
11858
  registerDoctor(program2);
11307
11859
  registerAgent(program2);
11860
+ registerAgentCloud(program2);
11308
11861
  registerVerify(program2);
11309
11862
  registerApi(program2);
11310
11863
  registerAnalysis(program2);