@workser/cli 0.6.27 → 0.6.28
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 +583 -288
- package/package.json +1 -1
- package/skills/workser/SKILL.md +16 -20
- package/skills/workser/reference/agent-cloud.md +17 -14
- package/skills/workser/reference/images.md +12 -1
- package/skills/workser/reference/line.md +80 -0
- package/skills/workser/reference/storage.md +37 -1
package/dist/index.js
CHANGED
|
@@ -3857,26 +3857,28 @@ publishes an agent that never answers anybody. Pictures, video, voice and
|
|
|
3857
3857
|
transcription are abilities, not models you set, and one call from the app's
|
|
3858
3858
|
own code needs no agent at all: \`workser help agent-cloud-media\`.
|
|
3859
3859
|
|
|
3860
|
-
##
|
|
3860
|
+
## Every plan can use Agent Cloud \u2014 runs use credits
|
|
3861
3861
|
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3862
|
+
Creating, teaching and publishing an agent are available on free, trial and paid
|
|
3863
|
+
plans. A \`try\` or live \`run\` spends real money on model usage and hosted runtime,
|
|
3864
|
+
so it starts only when the organisation's shared AI-credit wallet clears the
|
|
3865
|
+
minimum balance shown in the refusal.
|
|
3865
3866
|
|
|
3866
|
-
**When you hit
|
|
3867
|
+
**When you hit a 402, hand the credit top-up over \u2014 do not just describe it.** Workser
|
|
3867
3868
|
files the refusal on the conversation as a clickable step and artifact, so the
|
|
3868
|
-
person gets something actionable. Say what you were doing, that
|
|
3869
|
-
|
|
3869
|
+
person gets something actionable. Say what you were doing, that the wallet needs
|
|
3870
|
+
credits, and stop. The same rule applies when the owner supplies their own model
|
|
3871
|
+
key because the hosted runtime and fallback path still cost money.
|
|
3870
3872
|
|
|
3871
3873
|
Do NOT:
|
|
3872
3874
|
|
|
3873
|
-
- retry the call, or try a different agent \u2014 the
|
|
3875
|
+
- retry the call, or try a different agent \u2014 the wallet is shared
|
|
3874
3876
|
- try to work around it by running the job yourself as a coding agent; that is
|
|
3875
3877
|
a different product and it will not be there when the user closes the window
|
|
3876
|
-
- guess at prices, discounts or
|
|
3878
|
+
- guess at prices, discounts or free usage
|
|
3877
3879
|
|
|
3878
3880
|
If the user asks how much: it is per minute of run time plus the model, and the
|
|
3879
|
-
|
|
3881
|
+
Agent Cloud usage view has the current figures. You do not have them.
|
|
3880
3882
|
|
|
3881
3883
|
## When to reach for this
|
|
3882
3884
|
|
|
@@ -3897,7 +3899,7 @@ workflow\`.
|
|
|
3897
3899
|
## If Agent Cloud is ruled out, there is an order
|
|
3898
3900
|
|
|
3899
3901
|
Propose Agent Cloud first, every time. If it genuinely does not fit \u2014 the owner
|
|
3900
|
-
|
|
3902
|
+
does not want a managed runtime, or wants their own code in their own framework \u2014 go
|
|
3901
3903
|
down this list in order, and say which rung you took and why you skipped the
|
|
3902
3904
|
ones above it:
|
|
3903
3905
|
|
|
@@ -3952,9 +3954,10 @@ watching sees the agent think. See the \`workser-sdk\` skill, \`reference/agents
|
|
|
3952
3954
|
what to do, what to leave alone, when to ask. Vague instructions are the
|
|
3953
3955
|
single biggest cause of an agent that "doesn't work".
|
|
3954
3956
|
|
|
3955
|
-
3. **
|
|
3956
|
-
|
|
3957
|
-
|
|
3957
|
+
3. **Every plan can run agents once the shared wallet has enough credits.** A
|
|
3958
|
+
\`402\` with \`spend_limit_reached\` means the wallet needs a top-up (or the owner
|
|
3959
|
+
reached their own spend cap). Tell them exactly what it says and hand over
|
|
3960
|
+
the credit action; never suggest a subscription upgrade for this refusal.
|
|
3958
3961
|
|
|
3959
3962
|
4. **Say who it is for.** An agent acting for one of the app's customers needs
|
|
3960
3963
|
\`referenceUserId\`, or its memory and audit trail belong to nobody.
|
|
@@ -5045,7 +5048,8 @@ that URL directly in the app.
|
|
|
5045
5048
|
|
|
5046
5049
|
\`\`\`bash
|
|
5047
5050
|
workser image generate "flat illustration of a farm delivery van, brand colors" --json
|
|
5048
|
-
workser image gen "same van, from the side" -r https://\u2026
|
|
5051
|
+
workser image gen "same van, from the side" -r https://\u2026 --json # use .data.url
|
|
5052
|
+
workser image gen "van, rear view" -o /tmp/van.png --json # only if you must
|
|
5049
5053
|
\`\`\`
|
|
5050
5054
|
|
|
5051
5055
|
## Notes that matter (generation)
|
|
@@ -5056,6 +5060,16 @@ workser image gen "same van, from the side" -r https://\u2026 -o ./public/van.pn
|
|
|
5056
5060
|
question comes back as text rather than an image. Check that you actually got an
|
|
5057
5061
|
image before wiring the URL into a page; an empty result is not a transport error
|
|
5058
5062
|
to retry.
|
|
5063
|
+
- **The URL is the deliverable \u2014 don't download it into the app folder.** This
|
|
5064
|
+
example used to write to \`./public/van.png\`, which is the single most common way
|
|
5065
|
+
generated art ends up committed to the user's repository: in every deploy bundle
|
|
5066
|
+
for ever, unreplaceable without a redeploy, against a 25MB publish cap. The
|
|
5067
|
+
returned URL is already public and already served. Reference it.
|
|
5068
|
+
|
|
5069
|
+
When a file genuinely has to exist \u2014 an asset the build reads, something to hand
|
|
5070
|
+
the user \u2014 \`-o\` into a temp path and \`workser storage put\` it into the bucket
|
|
5071
|
+
(or whatever store the owner chose; the repo is never it). See
|
|
5072
|
+
\`reference/storage.md\`.
|
|
5059
5073
|
- **\`--output\` writes only the first image.** If you asked for several, the rest
|
|
5060
5074
|
exist only as URLs.
|
|
5061
5075
|
- **Placeholder art is not a deliverable.** Generating a hero image to unblock a
|
|
@@ -5163,6 +5177,87 @@ deployment keeps using whatever it was built with until it's redeployed \u2014
|
|
|
5163
5177
|
run \`workser deploy\` (\`--prod\` for the production key) to pick up the new
|
|
5164
5178
|
value. \`key rotate\` prints the new secret exactly once; it is never shown
|
|
5165
5179
|
again or stored anywhere in the clear.
|
|
5180
|
+
`
|
|
5181
|
+
},
|
|
5182
|
+
{
|
|
5183
|
+
topic: "line",
|
|
5184
|
+
title: "LINE Official Account",
|
|
5185
|
+
summary: "Connect a LINE OA once, then send, reply, broadcast, build rich menus and read insight \u2014 from the CLI or from an agent.",
|
|
5186
|
+
commands: ["line"],
|
|
5187
|
+
source: "skills/workser/reference/line.md",
|
|
5188
|
+
body: `# LINE Official Account
|
|
5189
|
+
|
|
5190
|
+
Connect the business's LINE account to this project **once**. After that the same
|
|
5191
|
+
account is reachable from here, from Workser Code, and from any Agent Cloud agent
|
|
5192
|
+
in this project \u2014 including the one a LINE message starts.
|
|
5193
|
+
|
|
5194
|
+
\`\`\`
|
|
5195
|
+
workser line status # is anything connected?
|
|
5196
|
+
workser line connect --token <channelAccessToken> [--secret <channelSecret>]
|
|
5197
|
+
workser line verify # ask LINE if the token still works
|
|
5198
|
+
workser line disconnect
|
|
5199
|
+
|
|
5200
|
+
workser line ops [--group messaging|richmenu|audience|insight|people|group|quota|content|account]
|
|
5201
|
+
workser line call <operation> --params '<json>' # any of the 70 operations
|
|
5202
|
+
|
|
5203
|
+
workser line send <to> "<text>" # push to a user, group or room id
|
|
5204
|
+
workser line reply <replyToken> "<text>" # answer a message \u2014 free, single-use
|
|
5205
|
+
workser line broadcast "<text>" # EVERY follower, one message each
|
|
5206
|
+
workser line quota # allowance left this month
|
|
5207
|
+
workser line profile <userId>
|
|
5208
|
+
\`\`\`
|
|
5209
|
+
|
|
5210
|
+
## Getting the token
|
|
5211
|
+
|
|
5212
|
+
LINE Developers console \u2192 your Messaging API channel \u2192 **Messaging API** tab \u2192
|
|
5213
|
+
*Channel access token* (long-lived). \`--secret\` is the **Basic settings** \u2192
|
|
5214
|
+
*Channel secret*, and is only needed if you want LINE's own signature check on
|
|
5215
|
+
incoming webhooks.
|
|
5216
|
+
|
|
5217
|
+
\`connect\` calls LINE immediately to prove the token works, so a mistyped token
|
|
5218
|
+
fails here rather than an hour later as a customer message nobody answered.
|
|
5219
|
+
|
|
5220
|
+
## \`call\` is the whole API
|
|
5221
|
+
|
|
5222
|
+
\`ops\` prints every operation with a one-line summary. The \`\u25CF\` marks the ones that
|
|
5223
|
+
send something, spend quota, or change the account.
|
|
5224
|
+
|
|
5225
|
+
\`\`\`
|
|
5226
|
+
workser line call push --params '{"to":"U4af\u2026","messages":[{"type":"text","text":"Your order shipped"}]}'
|
|
5227
|
+
workser line call richmenu_list
|
|
5228
|
+
workser line call insight_followers --params '{"date":"20260909"}'
|
|
5229
|
+
workser line call webhook_endpoint_set --params '{"endpoint":"https://\u2026"}'
|
|
5230
|
+
\`\`\`
|
|
5231
|
+
|
|
5232
|
+
Parameters are flat \u2014 path, query and body fields all go in \`--params\` together and
|
|
5233
|
+
the server sorts them. Fields it has never heard of are **forwarded to LINE
|
|
5234
|
+
untouched**, so a flex component LINE shipped last week works today.
|
|
5235
|
+
|
|
5236
|
+
## Reply beats push
|
|
5237
|
+
|
|
5238
|
+
\`reply\` uses the token that came with the incoming message. It is **free** and does
|
|
5239
|
+
not touch the monthly quota; \`push\` costs one message per recipient. The token is
|
|
5240
|
+
single-use and expires within a minute or so, so reply first and fall back to push.
|
|
5241
|
+
|
|
5242
|
+
\`broadcast\` sends to every follower and spends one message each. On a large account
|
|
5243
|
+
that is the most expensive call in the list \u2014 say what it will cost before running it.
|
|
5244
|
+
|
|
5245
|
+
## Rich menus, in order
|
|
5246
|
+
|
|
5247
|
+
A rich menu does nothing until it has both a picture and a place to appear:
|
|
5248
|
+
|
|
5249
|
+
1. \`richmenu_create\` \u2014 the layout and tappable areas. Returns an id.
|
|
5250
|
+
2. \`richmenu_upload_image\` \u2014 \`content\` is the file **base64-encoded**, with
|
|
5251
|
+
\`content_type\`. The image must match the declared size exactly.
|
|
5252
|
+
3. \`richmenu_set_default\` (everybody) or \`richmenu_link_user\` (one person).
|
|
5253
|
+
|
|
5254
|
+
\`richmenu_validate\` checks a layout without creating it.
|
|
5255
|
+
|
|
5256
|
+
## When it is an agent doing this
|
|
5257
|
+
|
|
5258
|
+
An Agent Cloud agent in a project with a connected LINE account gets these as tools
|
|
5259
|
+
automatically \u2014 there is nothing to bind. Sends go through the agent's approval gate;
|
|
5260
|
+
reads do not. See \`workser help agent-cloud\`.
|
|
5166
5261
|
`
|
|
5167
5262
|
},
|
|
5168
5263
|
{
|
|
@@ -5533,6 +5628,40 @@ workser storage put <local> <key> # upload a file into the bucket
|
|
|
5533
5628
|
workser storage get <key> [dest] # download an object (or print its URL)
|
|
5534
5629
|
\`\`\`
|
|
5535
5630
|
|
|
5631
|
+
## This is where media goes \u2014 the folder is for code
|
|
5632
|
+
|
|
5633
|
+
Every project has this bucket, provisioned and paid for, served over a CDN, and
|
|
5634
|
+
visible to the owner on the Files screen. It is the **default** home for generated
|
|
5635
|
+
art, product photography, PDFs, exports, avatars and anything a user uploads.
|
|
5636
|
+
|
|
5637
|
+
**Default, not mandate.** An owner who wants Cloudinary, their own S3, or anything
|
|
5638
|
+
else is entitled to it \u2014 build it and don't argue. What is not yours to do is pick
|
|
5639
|
+
the alternative for them, or drift into one because it was quicker. If you think
|
|
5640
|
+
there is a real reason to go outside, say so and let them answer, then
|
|
5641
|
+
\`workser decision create\` it so the next agent doesn't quietly reverse it.
|
|
5642
|
+
|
|
5643
|
+
**The repo is not one of the options.** Whichever provider the owner chose, files
|
|
5644
|
+
under \`public/\`, \`assets/\` or \`static/\` cost them four things, none recoverable
|
|
5645
|
+
later:
|
|
5646
|
+
|
|
5647
|
+
- **They are committed.** Publishing runs \`git add -A\` over the app folder, so
|
|
5648
|
+
every image enters the repository's history. Deleting it afterwards does not
|
|
5649
|
+
remove it.
|
|
5650
|
+
- **They ride in every deploy.** The source bundle has a 25MB cap; enough media
|
|
5651
|
+
and publishing stops working outright, with an error about the bundle rather
|
|
5652
|
+
than about the images.
|
|
5653
|
+
- **They cannot change without a redeploy.** A photo the owner wants swapped
|
|
5654
|
+
becomes a code change and a build. From the bucket it is one \`storage put\`.
|
|
5655
|
+
- **They are invisible.** The Files screen lists the bucket. Nothing there shows
|
|
5656
|
+
what is sitting in the repo, so the owner cannot find, replace or delete it.
|
|
5657
|
+
|
|
5658
|
+
Small build-time assets \u2014 a logo, a favicon, an icon, an SVG the bundler inlines \u2014
|
|
5659
|
+
are the exception. Anything that is content, or that a user produced, is not.
|
|
5660
|
+
|
|
5661
|
+
\`\`\`bash
|
|
5662
|
+
workser storage put ./out/hero.png products/hero.png --json # \u2192 .data.url
|
|
5663
|
+
\`\`\`
|
|
5664
|
+
|
|
5536
5665
|
## Notes that matter
|
|
5537
5666
|
|
|
5538
5667
|
- **One bucket per project, shared by its apps.** Namespace your keys by app or
|
|
@@ -5542,7 +5671,9 @@ workser storage get <key> [dest] # download an object (or print its URL)
|
|
|
5542
5671
|
- **This is not where app uploads should go through you.** At runtime the app uses
|
|
5543
5672
|
\`workser.storage\` from \`@workser/app\`, and for anything large it should request a
|
|
5544
5673
|
presigned upload URL so the bytes never pass through Workser. See the
|
|
5545
|
-
\`workser-sdk\` skill.
|
|
5674
|
+
\`workser-sdk\` skill. Writing an upload handler that saves into the app's own
|
|
5675
|
+
filesystem is the same mistake as above, plus one more: on a serverless host the
|
|
5676
|
+
file is gone at the end of the request.
|
|
5546
5677
|
|
|
5547
5678
|
## Not the same as \`workser neon storage\`
|
|
5548
5679
|
|
|
@@ -7537,7 +7668,12 @@ function registerVersions(program3) {
|
|
|
7537
7668
|
}
|
|
7538
7669
|
const items = await api(ctx, `/v1/projects/${projectId}/versions`, {
|
|
7539
7670
|
query: {
|
|
7540
|
-
|
|
7671
|
+
// `--app` wins; otherwise the app this folder is linked to (`ctx.appId`,
|
|
7672
|
+
// from `.workser-app`). Standing in an app folder and being told
|
|
7673
|
+
// "needs a webAppId" was the CLI refusing to read the marker it had
|
|
7674
|
+
// already read for `status`. Outside any app folder this stays unset
|
|
7675
|
+
// and the server's own refusal (never the primary-app guess) applies.
|
|
7676
|
+
...opts.app || ctx.appId ? { webAppId: String(opts.app ?? ctx.appId) } : {},
|
|
7541
7677
|
...parsed.value ? { environment: parsed.value } : {}
|
|
7542
7678
|
}
|
|
7543
7679
|
});
|
|
@@ -7579,7 +7715,12 @@ function registerLogs(program3) {
|
|
|
7579
7715
|
throw new WorkserError(parsed.error, { code: "bad_input" });
|
|
7580
7716
|
}
|
|
7581
7717
|
const scope = {
|
|
7582
|
-
|
|
7718
|
+
// `--app` wins; otherwise the app this folder is linked to (`ctx.appId`,
|
|
7719
|
+
// from `.workser-app`). Standing in an app folder and being told
|
|
7720
|
+
// "needs a webAppId" was the CLI refusing to read the marker it had
|
|
7721
|
+
// already read for `status`. Outside any app folder this stays unset
|
|
7722
|
+
// and the server's own refusal (never the primary-app guess) applies.
|
|
7723
|
+
...opts.app || ctx.appId ? { webAppId: String(opts.app ?? ctx.appId) } : {},
|
|
7583
7724
|
...parsed.value ? { environment: parsed.value } : {}
|
|
7584
7725
|
};
|
|
7585
7726
|
const first = await api(ctx, `/v1/projects/${projectId}/logs`, {
|
|
@@ -7750,7 +7891,7 @@ function registerDoctor(program3) {
|
|
|
7750
7891
|
const endpointSource = opts.endpoint ? "--endpoint" : process.env.WORKSER_DAEMON_URL ? "$WORKSER_DAEMON_URL" : session.endpoint ? "session" : process.env.WORKSER_API_URL ? "$WORKSER_API_URL" : `cloud-default: ${env}`;
|
|
7751
7892
|
const projectSource = opts.project ? "--project" : link?.projectId ? ".workser link" : session.defaultProjectId ? "session" : void 0;
|
|
7752
7893
|
const git2 = gitVersion();
|
|
7753
|
-
const
|
|
7894
|
+
const report2 = {
|
|
7754
7895
|
endpoint: ctx.endpoint,
|
|
7755
7896
|
endpointSource,
|
|
7756
7897
|
env,
|
|
@@ -7770,7 +7911,7 @@ function registerDoctor(program3) {
|
|
|
7770
7911
|
cwd: ctx.cwd,
|
|
7771
7912
|
workspace: session.workspaceName ?? null
|
|
7772
7913
|
};
|
|
7773
|
-
ok(
|
|
7914
|
+
ok(report2, () => {
|
|
7774
7915
|
line(import_picocolors15.default.bold("workser doctor"));
|
|
7775
7916
|
line(` endpoint: ${ctx.endpoint} ${import_picocolors15.default.dim(`(${endpointSource})`)}`);
|
|
7776
7917
|
line(
|
|
@@ -8738,8 +8879,161 @@ function registerConnection(program3) {
|
|
|
8738
8879
|
);
|
|
8739
8880
|
}
|
|
8740
8881
|
|
|
8741
|
-
// src/commands/
|
|
8882
|
+
// src/commands/line.ts
|
|
8742
8883
|
var import_picocolors23 = __toESM(require_picocolors(), 1);
|
|
8884
|
+
function registerLine(program3) {
|
|
8885
|
+
const cmd = program3.command("line").description("Connect a LINE Official Account and use the LINE Messaging API");
|
|
8886
|
+
cmd.command("status").description("Show this project's LINE connection").action(
|
|
8887
|
+
action(async ({ ctx }) => {
|
|
8888
|
+
const projectId = requireProject(ctx);
|
|
8889
|
+
const res = await api(ctx, `/v1/projects/${projectId}/line`);
|
|
8890
|
+
ok(res, () => {
|
|
8891
|
+
const c = res?.connection;
|
|
8892
|
+
if (!c) return line(import_picocolors23.default.dim("No LINE account connected. Run `workser line connect`."));
|
|
8893
|
+
const state = c.status === "connected" ? import_picocolors23.default.green(c.status) : import_picocolors23.default.yellow(c.status);
|
|
8894
|
+
line(`${import_picocolors23.default.bold(c.display_name ?? "LINE")} ${state}`);
|
|
8895
|
+
if (c.public_config?.basic_id) line(import_picocolors23.default.dim(` ${c.public_config.basic_id}`));
|
|
8896
|
+
if (c.last_error) line(import_picocolors23.default.red(` ${c.last_error}`));
|
|
8897
|
+
});
|
|
8898
|
+
})
|
|
8899
|
+
);
|
|
8900
|
+
cmd.command("connect").description("Connect a LINE Official Account with its channel access token").requiredOption("--token <channelAccessToken>", "Messaging API \u2192 Channel access token").option("--secret <channelSecret>", "Basic settings \u2192 Channel secret (for webhook signatures)").action(
|
|
8901
|
+
action(async ({ ctx, opts }) => {
|
|
8902
|
+
const projectId = requireProject(ctx);
|
|
8903
|
+
const res = await api(ctx, `/v1/projects/${projectId}/line/connect`, {
|
|
8904
|
+
body: { channel_access_token: opts.token, channel_secret: opts.secret }
|
|
8905
|
+
});
|
|
8906
|
+
ok(
|
|
8907
|
+
res,
|
|
8908
|
+
() => line(`Connected ${import_picocolors23.default.bold(res?.connection?.display_name ?? "LINE")}.`)
|
|
8909
|
+
);
|
|
8910
|
+
})
|
|
8911
|
+
);
|
|
8912
|
+
cmd.command("verify").description("Ask LINE whether the stored token still works").action(
|
|
8913
|
+
action(async ({ ctx }) => {
|
|
8914
|
+
const projectId = requireProject(ctx);
|
|
8915
|
+
const res = await api(ctx, `/v1/projects/${projectId}/line/verify`, { body: {} });
|
|
8916
|
+
ok(res, () => {
|
|
8917
|
+
const c = res?.connection;
|
|
8918
|
+
line(
|
|
8919
|
+
c?.status === "connected" ? import_picocolors23.default.green("The token still works.") : import_picocolors23.default.red(c?.last_error ?? "LINE refused the stored token.")
|
|
8920
|
+
);
|
|
8921
|
+
});
|
|
8922
|
+
})
|
|
8923
|
+
);
|
|
8924
|
+
cmd.command("disconnect").description("Disconnect LINE from this project").action(
|
|
8925
|
+
action(async ({ ctx }) => {
|
|
8926
|
+
const projectId = requireProject(ctx);
|
|
8927
|
+
const res = await api(ctx, `/v1/projects/${projectId}/line`, { method: "DELETE" });
|
|
8928
|
+
ok(res, () => line("Disconnected."));
|
|
8929
|
+
})
|
|
8930
|
+
);
|
|
8931
|
+
cmd.command("ops").description("List every LINE operation, optionally filtered by group").option("--group <name>", "messaging, richmenu, audience, insight, people, group, quota, content, account, validation").action(
|
|
8932
|
+
action(async ({ ctx, opts }) => {
|
|
8933
|
+
const projectId = requireProject(ctx);
|
|
8934
|
+
const res = await api(ctx, `/v1/projects/${projectId}/line/operations`);
|
|
8935
|
+
const all = res?.operations ?? [];
|
|
8936
|
+
const items = opts.group ? all.filter((o) => o.group === opts.group) : all;
|
|
8937
|
+
ok(items, () => {
|
|
8938
|
+
if (!items.length) return line(import_picocolors23.default.dim("No operations matched."));
|
|
8939
|
+
let group = "";
|
|
8940
|
+
for (const o of items) {
|
|
8941
|
+
if (o.group !== group) {
|
|
8942
|
+
group = o.group;
|
|
8943
|
+
line(import_picocolors23.default.dim(`
|
|
8944
|
+
${group}`));
|
|
8945
|
+
}
|
|
8946
|
+
const mark = o.writes ? import_picocolors23.default.yellow(" \u25CF") : " ";
|
|
8947
|
+
line(`${mark} ${import_picocolors23.default.bold(o.id.padEnd(28))} ${o.summary}`);
|
|
8948
|
+
}
|
|
8949
|
+
line(import_picocolors23.default.dim("\n\u25CF sends something, spends quota, or changes the account."));
|
|
8950
|
+
});
|
|
8951
|
+
})
|
|
8952
|
+
);
|
|
8953
|
+
cmd.command("call <operation>").description("Run any LINE operation \u2014 see `workser line ops`").option("--params <json>", "the operation's parameters as a JSON string", "{}").action(
|
|
8954
|
+
action(async ({ ctx, args, opts }) => {
|
|
8955
|
+
const projectId = requireProject(ctx);
|
|
8956
|
+
const res = await callLine(ctx, projectId, args[0], parseParams(opts.params));
|
|
8957
|
+
ok(res, () => line(JSON.stringify(res?.data ?? res, null, 2)));
|
|
8958
|
+
})
|
|
8959
|
+
);
|
|
8960
|
+
cmd.command("send <to> <text>").description("Send a text message to a user, group or room id").action(
|
|
8961
|
+
action(async ({ ctx, args }) => {
|
|
8962
|
+
const projectId = requireProject(ctx);
|
|
8963
|
+
const res = await callLine(ctx, projectId, "push", {
|
|
8964
|
+
to: args[0],
|
|
8965
|
+
messages: [{ type: "text", text: args[1] }]
|
|
8966
|
+
});
|
|
8967
|
+
ok(res, () => report(res, "Sent."));
|
|
8968
|
+
})
|
|
8969
|
+
);
|
|
8970
|
+
cmd.command("reply <replyToken> <text>").description("Answer a message using its reply token (free, and single-use)").action(
|
|
8971
|
+
action(async ({ ctx, args }) => {
|
|
8972
|
+
const projectId = requireProject(ctx);
|
|
8973
|
+
const res = await callLine(ctx, projectId, "reply", {
|
|
8974
|
+
replyToken: args[0],
|
|
8975
|
+
messages: [{ type: "text", text: args[1] }]
|
|
8976
|
+
});
|
|
8977
|
+
ok(res, () => report(res, "Replied."));
|
|
8978
|
+
})
|
|
8979
|
+
);
|
|
8980
|
+
cmd.command("broadcast <text>").description("Send a text message to EVERY follower \u2014 spends one message each").action(
|
|
8981
|
+
action(async ({ ctx, args }) => {
|
|
8982
|
+
const projectId = requireProject(ctx);
|
|
8983
|
+
const res = await callLine(ctx, projectId, "broadcast", {
|
|
8984
|
+
messages: [{ type: "text", text: args[0] }]
|
|
8985
|
+
});
|
|
8986
|
+
ok(res, () => report(res, "Broadcast sent."));
|
|
8987
|
+
})
|
|
8988
|
+
);
|
|
8989
|
+
cmd.command("quota").description("How much of this month's message allowance is left").action(
|
|
8990
|
+
action(async ({ ctx }) => {
|
|
8991
|
+
const projectId = requireProject(ctx);
|
|
8992
|
+
const [quota, used] = await Promise.all([
|
|
8993
|
+
callLine(ctx, projectId, "quota", {}),
|
|
8994
|
+
callLine(ctx, projectId, "quota_consumption", {})
|
|
8995
|
+
]);
|
|
8996
|
+
ok({ quota: quota?.data, consumption: used?.data }, () => {
|
|
8997
|
+
const limit = quota?.data?.value;
|
|
8998
|
+
const spent = used?.data?.totalUsage;
|
|
8999
|
+
if (limit === void 0) return line(JSON.stringify(quota?.data ?? quota, null, 2));
|
|
9000
|
+
line(`${spent ?? "?"} of ${limit} messages used this month.`);
|
|
9001
|
+
});
|
|
9002
|
+
})
|
|
9003
|
+
);
|
|
9004
|
+
cmd.command("profile <userId>").description("Look up one follower").action(
|
|
9005
|
+
action(async ({ ctx, args }) => {
|
|
9006
|
+
const projectId = requireProject(ctx);
|
|
9007
|
+
const res = await callLine(ctx, projectId, "profile", { userId: args[0] });
|
|
9008
|
+
ok(res, () => line(JSON.stringify(res?.data ?? res, null, 2)));
|
|
9009
|
+
})
|
|
9010
|
+
);
|
|
9011
|
+
}
|
|
9012
|
+
function parseParams(raw) {
|
|
9013
|
+
try {
|
|
9014
|
+
const parsed = JSON.parse(raw || "{}");
|
|
9015
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
|
|
9016
|
+
} catch {
|
|
9017
|
+
}
|
|
9018
|
+
throw new Error(
|
|
9019
|
+
`--params must be a JSON object, e.g. --params '{"to":"U123","messages":[{"type":"text","text":"hi"}]}'`
|
|
9020
|
+
);
|
|
9021
|
+
}
|
|
9022
|
+
async function callLine(ctx, projectId, operation, params) {
|
|
9023
|
+
return api(ctx, `/v1/projects/${projectId}/line/call`, {
|
|
9024
|
+
body: { operation, params }
|
|
9025
|
+
});
|
|
9026
|
+
}
|
|
9027
|
+
function report(res, success2) {
|
|
9028
|
+
if (res?.ok === false) {
|
|
9029
|
+
line(import_picocolors23.default.red(res.message ?? "LINE refused that."));
|
|
9030
|
+
return;
|
|
9031
|
+
}
|
|
9032
|
+
line(success2);
|
|
9033
|
+
}
|
|
9034
|
+
|
|
9035
|
+
// src/commands/tool.ts
|
|
9036
|
+
var import_picocolors24 = __toESM(require_picocolors(), 1);
|
|
8743
9037
|
function registerTool(program3) {
|
|
8744
9038
|
const tool = program3.command("tool").description(
|
|
8745
9039
|
"Computer-use tools: filesystem, shell, screenshot, input control, clipboard, notifications, basic browser"
|
|
@@ -8748,7 +9042,7 @@ function registerTool(program3) {
|
|
|
8748
9042
|
action(async ({ ctx }) => {
|
|
8749
9043
|
const tools = await api(ctx, "/v1/tool/list");
|
|
8750
9044
|
ok(tools, () => {
|
|
8751
|
-
if (!tools?.length) return line(
|
|
9045
|
+
if (!tools?.length) return line(import_picocolors24.default.dim("No tools available."));
|
|
8752
9046
|
const byCategory = /* @__PURE__ */ new Map();
|
|
8753
9047
|
for (const t of tools) {
|
|
8754
9048
|
const list = byCategory.get(t.category) ?? [];
|
|
@@ -8756,9 +9050,9 @@ function registerTool(program3) {
|
|
|
8756
9050
|
byCategory.set(t.category, list);
|
|
8757
9051
|
}
|
|
8758
9052
|
for (const [category, items] of byCategory) {
|
|
8759
|
-
line(
|
|
9053
|
+
line(import_picocolors24.default.bold(category) + ":");
|
|
8760
9054
|
for (const t of items) {
|
|
8761
|
-
line(` ${t.name} ${
|
|
9055
|
+
line(` ${t.name} ${import_picocolors24.default.dim(t.description ?? "")}`);
|
|
8762
9056
|
}
|
|
8763
9057
|
}
|
|
8764
9058
|
});
|
|
@@ -8776,7 +9070,7 @@ function registerTool(program3) {
|
|
|
8776
9070
|
}
|
|
8777
9071
|
|
|
8778
9072
|
// src/commands/memory.ts
|
|
8779
|
-
var
|
|
9073
|
+
var import_picocolors25 = __toESM(require_picocolors(), 1);
|
|
8780
9074
|
function registerMemory(program3) {
|
|
8781
9075
|
const memory = program3.command("memory").description("Durable, cross-conversation project memory (shared with cloud agents on the same project)");
|
|
8782
9076
|
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(
|
|
@@ -8800,9 +9094,9 @@ function registerMemory(program3) {
|
|
|
8800
9094
|
});
|
|
8801
9095
|
ok(res, () => {
|
|
8802
9096
|
const results = res?.results ?? res ?? [];
|
|
8803
|
-
if (!results?.length) return line(
|
|
9097
|
+
if (!results?.length) return line(import_picocolors25.default.dim("No matching memories."));
|
|
8804
9098
|
for (const r of results) {
|
|
8805
|
-
line(`${
|
|
9099
|
+
line(`${import_picocolors25.default.dim(r.id ?? "?")} ${memoryText(r)}`);
|
|
8806
9100
|
}
|
|
8807
9101
|
});
|
|
8808
9102
|
})
|
|
@@ -8822,11 +9116,11 @@ function memoryText(r) {
|
|
|
8822
9116
|
if (typeof text === "string" && text.trim()) return text;
|
|
8823
9117
|
const title = r?.documents?.[0]?.title;
|
|
8824
9118
|
if (typeof title === "string" && title.trim()) return title;
|
|
8825
|
-
return
|
|
9119
|
+
return import_picocolors25.default.dim("(no readable text on this row)");
|
|
8826
9120
|
}
|
|
8827
9121
|
|
|
8828
9122
|
// src/commands/note.ts
|
|
8829
|
-
var
|
|
9123
|
+
var import_picocolors26 = __toESM(require_picocolors(), 1);
|
|
8830
9124
|
function registerNote(program3) {
|
|
8831
9125
|
program3.command("note <text>").description("Leave a fact the rest of the team will need").addHelpText(
|
|
8832
9126
|
"after",
|
|
@@ -8863,14 +9157,14 @@ function registerNote(program3) {
|
|
|
8863
9157
|
}
|
|
8864
9158
|
ok(res, () => {
|
|
8865
9159
|
success("Noted for the team.");
|
|
8866
|
-
line(
|
|
9160
|
+
line(import_picocolors26.default.dim(` ${text}`));
|
|
8867
9161
|
});
|
|
8868
9162
|
})
|
|
8869
9163
|
);
|
|
8870
9164
|
}
|
|
8871
9165
|
|
|
8872
9166
|
// src/commands/business.ts
|
|
8873
|
-
var
|
|
9167
|
+
var import_picocolors27 = __toESM(require_picocolors(), 1);
|
|
8874
9168
|
var RESOURCE_PATHS = {
|
|
8875
9169
|
"business-config": "business-config",
|
|
8876
9170
|
"business-settings": "business-settings",
|
|
@@ -8930,7 +9224,7 @@ function registerBusiness(program3) {
|
|
|
8930
9224
|
const projectId = requireProject(ctx);
|
|
8931
9225
|
const [resource] = args;
|
|
8932
9226
|
const res = await api(ctx, businessPath(projectId, resource), { body: JSON.parse(opts.body) });
|
|
8933
|
-
ok(res, () => line(`Created ${resource} ${
|
|
9227
|
+
ok(res, () => line(`Created ${resource} ${import_picocolors27.default.bold(res?.id ?? "")}.`));
|
|
8934
9228
|
})
|
|
8935
9229
|
);
|
|
8936
9230
|
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(
|
|
@@ -8972,7 +9266,7 @@ function businessPath(projectId, resource, subpath) {
|
|
|
8972
9266
|
}
|
|
8973
9267
|
|
|
8974
9268
|
// src/commands/artifact.ts
|
|
8975
|
-
var
|
|
9269
|
+
var import_picocolors28 = __toESM(require_picocolors(), 1);
|
|
8976
9270
|
import { existsSync as existsSync2, statSync } from "fs";
|
|
8977
9271
|
import { resolve as resolve3, basename as basename3 } from "path";
|
|
8978
9272
|
var KINDS = [
|
|
@@ -9069,7 +9363,7 @@ function registerArtifact(program3) {
|
|
|
9069
9363
|
ok(
|
|
9070
9364
|
res,
|
|
9071
9365
|
() => success(
|
|
9072
|
-
`Recorded ${
|
|
9366
|
+
`Recorded ${import_picocolors28.default.bold(res?.title ?? "artifact")}${res?.kind ? import_picocolors28.default.dim(` (${res.kind})`) : ""}`
|
|
9073
9367
|
)
|
|
9074
9368
|
);
|
|
9075
9369
|
})
|
|
@@ -9107,7 +9401,7 @@ function registerArtifact(program3) {
|
|
|
9107
9401
|
}
|
|
9108
9402
|
function printArtifacts(rows) {
|
|
9109
9403
|
if (!rows.length) {
|
|
9110
|
-
line(
|
|
9404
|
+
line(import_picocolors28.default.dim("Nothing produced yet."));
|
|
9111
9405
|
return;
|
|
9112
9406
|
}
|
|
9113
9407
|
const byStep = /* @__PURE__ */ new Map();
|
|
@@ -9117,26 +9411,26 @@ function printArtifacts(rows) {
|
|
|
9117
9411
|
byStep.set(r.subtask_id, list);
|
|
9118
9412
|
}
|
|
9119
9413
|
for (const [stepId, items] of byStep) {
|
|
9120
|
-
line(
|
|
9414
|
+
line(import_picocolors28.default.bold(`step ${stepId}`));
|
|
9121
9415
|
for (const a of items) {
|
|
9122
|
-
const flag = a.promoted_at ?
|
|
9416
|
+
const flag = a.promoted_at ? import_picocolors28.default.green(" *") : " ";
|
|
9123
9417
|
const where = a.local_path || a.cloud_url || "";
|
|
9124
9418
|
line(
|
|
9125
|
-
`${flag} ${
|
|
9419
|
+
`${flag} ${import_picocolors28.default.dim(`[${a.kind}]`)} ${a.title ?? "(untitled)"}` + (where ? import_picocolors28.default.dim(` ${where}`) : "")
|
|
9126
9420
|
);
|
|
9127
|
-
if (a.description) line(
|
|
9421
|
+
if (a.description) line(import_picocolors28.default.dim(` ${a.description}`));
|
|
9128
9422
|
}
|
|
9129
9423
|
line("");
|
|
9130
9424
|
}
|
|
9131
|
-
line(
|
|
9425
|
+
line(import_picocolors28.default.dim("* = handed over as a deliverable; the rest is working material."));
|
|
9132
9426
|
}
|
|
9133
9427
|
function printRun2(run) {
|
|
9134
9428
|
if (!run) return;
|
|
9135
|
-
line(` run ${
|
|
9429
|
+
line(` run ${import_picocolors28.default.bold(run.runId)}`);
|
|
9136
9430
|
if (run.taskId) line(` task ${run.taskId}`);
|
|
9137
9431
|
if (run.conversationId) line(` chat ${run.conversationId}`);
|
|
9138
9432
|
if (run.projectId) line(` project ${run.projectId}`);
|
|
9139
|
-
if (run.cwd) line(` folder ${
|
|
9433
|
+
if (run.cwd) line(` folder ${import_picocolors28.default.dim(run.cwd)}`);
|
|
9140
9434
|
}
|
|
9141
9435
|
|
|
9142
9436
|
// src/commands/image.ts
|
|
@@ -9343,7 +9637,7 @@ function registerAudio(program3) {
|
|
|
9343
9637
|
}
|
|
9344
9638
|
|
|
9345
9639
|
// src/commands/ask.ts
|
|
9346
|
-
var
|
|
9640
|
+
var import_picocolors29 = __toESM(require_picocolors(), 1);
|
|
9347
9641
|
var TYPES = [
|
|
9348
9642
|
"input",
|
|
9349
9643
|
"choice",
|
|
@@ -9440,7 +9734,7 @@ function registerAsk(program3) {
|
|
|
9440
9734
|
code: "bad_request"
|
|
9441
9735
|
});
|
|
9442
9736
|
}
|
|
9443
|
-
info(
|
|
9737
|
+
info(import_picocolors29.default.dim("Waiting for the user to answer\u2026"));
|
|
9444
9738
|
const res = await api(ctx, `/v1/runs/${runTarget(ctx)}/ask`, {
|
|
9445
9739
|
body: {
|
|
9446
9740
|
type,
|
|
@@ -9468,12 +9762,12 @@ function deriveTitle(message) {
|
|
|
9468
9762
|
function printAnswer(res) {
|
|
9469
9763
|
if (!res) return;
|
|
9470
9764
|
if (res.status === "answered") {
|
|
9471
|
-
line(` ${
|
|
9765
|
+
line(` ${import_picocolors29.default.green("answered")}`);
|
|
9472
9766
|
const value = extract(res.response);
|
|
9473
9767
|
if (value) line(` ${value}`);
|
|
9474
9768
|
return;
|
|
9475
9769
|
}
|
|
9476
|
-
line(` ${
|
|
9770
|
+
line(` ${import_picocolors29.default.yellow(res.status)} ${import_picocolors29.default.dim(res.reason ?? "")}`);
|
|
9477
9771
|
}
|
|
9478
9772
|
function extract(response) {
|
|
9479
9773
|
if (response == null) return "";
|
|
@@ -9492,7 +9786,7 @@ function extract(response) {
|
|
|
9492
9786
|
}
|
|
9493
9787
|
|
|
9494
9788
|
// src/commands/search.ts
|
|
9495
|
-
var
|
|
9789
|
+
var import_picocolors30 = __toESM(require_picocolors(), 1);
|
|
9496
9790
|
function registerSearch(program3) {
|
|
9497
9791
|
program3.command("search <query>").description("Search the web (Google-grounded, server-side)").option("-n, --max-results <n>", "max results", "5").action(
|
|
9498
9792
|
action(async ({ ctx, args, opts }) => {
|
|
@@ -9505,9 +9799,9 @@ function registerSearch(program3) {
|
|
|
9505
9799
|
line("");
|
|
9506
9800
|
}
|
|
9507
9801
|
const results = res?.results ?? [];
|
|
9508
|
-
if (!results.length) return line(
|
|
9802
|
+
if (!results.length) return line(import_picocolors30.default.dim("No results."));
|
|
9509
9803
|
for (const r of results) {
|
|
9510
|
-
line(`${r.title ||
|
|
9804
|
+
line(`${r.title || import_picocolors30.default.dim("(untitled)")} ${import_picocolors30.default.dim(r.url)}`);
|
|
9511
9805
|
}
|
|
9512
9806
|
});
|
|
9513
9807
|
})
|
|
@@ -9515,7 +9809,7 @@ function registerSearch(program3) {
|
|
|
9515
9809
|
}
|
|
9516
9810
|
|
|
9517
9811
|
// src/commands/board.ts
|
|
9518
|
-
var
|
|
9812
|
+
var import_picocolors31 = __toESM(require_picocolors(), 1);
|
|
9519
9813
|
|
|
9520
9814
|
// src/commands/record-step.ts
|
|
9521
9815
|
async function recordEntityStep(ctx, opts) {
|
|
@@ -9554,7 +9848,7 @@ function registerBoard(program3) {
|
|
|
9554
9848
|
}
|
|
9555
9849
|
ok(rows, () => {
|
|
9556
9850
|
if (!rows.length) {
|
|
9557
|
-
line(
|
|
9851
|
+
line(import_picocolors31.default.dim("No cards on the Board yet."));
|
|
9558
9852
|
return;
|
|
9559
9853
|
}
|
|
9560
9854
|
for (const r of rows) line(formatRow(r));
|
|
@@ -9569,7 +9863,7 @@ function registerBoard(program3) {
|
|
|
9569
9863
|
`/v1/projects/${projectId}/work-items/${args[0]}`
|
|
9570
9864
|
);
|
|
9571
9865
|
ok(row, () => {
|
|
9572
|
-
line(`${
|
|
9866
|
+
line(`${import_picocolors31.default.bold(row.title)} ${import_picocolors31.default.dim(row.id)}`);
|
|
9573
9867
|
line(`${statusTag(row.status)} priority ${row.priority}`);
|
|
9574
9868
|
if (row.ownerHuman) line(`owner: ${row.ownerHuman}`);
|
|
9575
9869
|
if (row.labels?.length) line(`labels: ${row.labels.join(", ")}`);
|
|
@@ -9610,7 +9904,7 @@ ${row.description}`);
|
|
|
9610
9904
|
refId: row?.id,
|
|
9611
9905
|
output: { workItem: row }
|
|
9612
9906
|
});
|
|
9613
|
-
ok(row, () => line(`Created work item ${
|
|
9907
|
+
ok(row, () => line(`Created work item ${import_picocolors31.default.bold(row?.id ?? "")} \u2014 ${title}`));
|
|
9614
9908
|
})
|
|
9615
9909
|
);
|
|
9616
9910
|
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(
|
|
@@ -9644,7 +9938,7 @@ ${row.description}`);
|
|
|
9644
9938
|
);
|
|
9645
9939
|
}
|
|
9646
9940
|
const row = await patchItem(ctx, projectId, String(args[0]), body);
|
|
9647
|
-
ok(row, () => line(`Updated ${
|
|
9941
|
+
ok(row, () => line(`Updated ${import_picocolors31.default.bold(row.id)} \u2014 ${row.title} ${statusTag(row.status)}`));
|
|
9648
9942
|
})
|
|
9649
9943
|
);
|
|
9650
9944
|
board.command("move <id> <status>").description(
|
|
@@ -9655,14 +9949,14 @@ ${row.description}`);
|
|
|
9655
9949
|
const status = String(args[1]);
|
|
9656
9950
|
assertStatus(status);
|
|
9657
9951
|
const row = await patchItem(ctx, projectId, String(args[0]), { status });
|
|
9658
|
-
ok(row, () => line(`Moved ${
|
|
9952
|
+
ok(row, () => line(`Moved ${import_picocolors31.default.bold(row.title)} \u2192 ${statusTag(row.status)}`));
|
|
9659
9953
|
})
|
|
9660
9954
|
);
|
|
9661
9955
|
board.command("close <id>").description("Shorthand for `board move <id> done`").action(
|
|
9662
9956
|
action(async ({ ctx, args }) => {
|
|
9663
9957
|
const projectId = requireProject(ctx);
|
|
9664
9958
|
const row = await patchItem(ctx, projectId, String(args[0]), { status: "done" });
|
|
9665
|
-
ok(row, () => line(`Closed ${
|
|
9959
|
+
ok(row, () => line(`Closed ${import_picocolors31.default.bold(row.title)} ${statusTag(row.status)}`));
|
|
9666
9960
|
})
|
|
9667
9961
|
);
|
|
9668
9962
|
}
|
|
@@ -9695,23 +9989,23 @@ function assertPriority(value) {
|
|
|
9695
9989
|
}
|
|
9696
9990
|
}
|
|
9697
9991
|
function formatRow(r) {
|
|
9698
|
-
const labels = r.labels?.length ?
|
|
9699
|
-
const owner = r.ownerHuman ?
|
|
9700
|
-
return `${
|
|
9992
|
+
const labels = r.labels?.length ? import_picocolors31.default.dim(` [${r.labels.join(", ")}]`) : "";
|
|
9993
|
+
const owner = r.ownerHuman ? import_picocolors31.default.dim(` @${r.ownerHuman}`) : "";
|
|
9994
|
+
return `${import_picocolors31.default.dim(r.id)} ${statusTag(r.status)} ${r.title}${labels}${owner}`;
|
|
9701
9995
|
}
|
|
9702
9996
|
function statusTag(status) {
|
|
9703
9997
|
const label = status.padEnd(11);
|
|
9704
|
-
if (status === "done") return
|
|
9705
|
-
if (status === "in-progress") return
|
|
9706
|
-
if (status === "in-review") return
|
|
9707
|
-
return
|
|
9998
|
+
if (status === "done") return import_picocolors31.default.green(label);
|
|
9999
|
+
if (status === "in-progress") return import_picocolors31.default.yellow(label);
|
|
10000
|
+
if (status === "in-review") return import_picocolors31.default.cyan(label);
|
|
10001
|
+
return import_picocolors31.default.dim(label);
|
|
9708
10002
|
}
|
|
9709
10003
|
function collect2(value, previous) {
|
|
9710
10004
|
return [...previous, value];
|
|
9711
10005
|
}
|
|
9712
10006
|
|
|
9713
10007
|
// src/commands/task.ts
|
|
9714
|
-
var
|
|
10008
|
+
var import_picocolors32 = __toESM(require_picocolors(), 1);
|
|
9715
10009
|
|
|
9716
10010
|
// src/subtask-attachments.ts
|
|
9717
10011
|
var MAX_REF_NOTE = 500;
|
|
@@ -9826,7 +10120,7 @@ function registerTask(program3) {
|
|
|
9826
10120
|
}) ?? [];
|
|
9827
10121
|
ok(rows, () => {
|
|
9828
10122
|
if (!rows.length) {
|
|
9829
|
-
line(
|
|
10123
|
+
line(import_picocolors32.default.dim("No tasks on the board yet."));
|
|
9830
10124
|
return;
|
|
9831
10125
|
}
|
|
9832
10126
|
for (const r of rows) line(formatRow2(r));
|
|
@@ -9941,10 +10235,10 @@ function registerTask(program3) {
|
|
|
9941
10235
|
};
|
|
9942
10236
|
ok(result, () => {
|
|
9943
10237
|
line(
|
|
9944
|
-
`${
|
|
10238
|
+
`${import_picocolors32.default.green("opened")} ${import_picocolors32.default.bold(row.title)} ${import_picocolors32.default.dim(row.key ?? row.id)}`
|
|
9945
10239
|
);
|
|
9946
10240
|
if (channelMessage)
|
|
9947
|
-
line(
|
|
10241
|
+
line(import_picocolors32.default.dim("posted to the channel as Project Manager"));
|
|
9948
10242
|
if (channelMessageError) {
|
|
9949
10243
|
warn(
|
|
9950
10244
|
`Task opened, but its Project Manager card could not be posted: ${channelMessageError.message}`
|
|
@@ -10023,12 +10317,12 @@ function registerTask(program3) {
|
|
|
10023
10317
|
) : null;
|
|
10024
10318
|
ok(runner ?? row, () => {
|
|
10025
10319
|
line(
|
|
10026
|
-
`${
|
|
10320
|
+
`${import_picocolors32.default.green("added")} ${import_picocolors32.default.bold(row.title)} ${import_picocolors32.default.dim(row.key ?? row.id)}`
|
|
10027
10321
|
);
|
|
10028
|
-
if (row.role) line(
|
|
10322
|
+
if (row.role) line(import_picocolors32.default.dim(`role: ${row.role}`));
|
|
10029
10323
|
if (runner) {
|
|
10030
10324
|
line(
|
|
10031
|
-
|
|
10325
|
+
import_picocolors32.default.dim(
|
|
10032
10326
|
`runs on: ${[opts.agent, opts.model, opts.effort].filter(Boolean).join(" \xB7 ")}`
|
|
10033
10327
|
)
|
|
10034
10328
|
);
|
|
@@ -10046,7 +10340,7 @@ function registerTask(program3) {
|
|
|
10046
10340
|
const rows = row.subtasks ?? [];
|
|
10047
10341
|
ok(rows, () => {
|
|
10048
10342
|
if (!rows.length) {
|
|
10049
|
-
line(
|
|
10343
|
+
line(import_picocolors32.default.dim("No subtasks yet."));
|
|
10050
10344
|
return;
|
|
10051
10345
|
}
|
|
10052
10346
|
rows.forEach((r, i) => line(formatSubtask(r, i + 1)));
|
|
@@ -10094,7 +10388,7 @@ function registerTask(program3) {
|
|
|
10094
10388
|
}
|
|
10095
10389
|
}
|
|
10096
10390
|
);
|
|
10097
|
-
ok(row, () => line(`${
|
|
10391
|
+
ok(row, () => line(`${import_picocolors32.default.green("updated")} ${import_picocolors32.default.bold(row.title)}`));
|
|
10098
10392
|
})
|
|
10099
10393
|
);
|
|
10100
10394
|
subtask.command("remove <id>").description("Remove a subtask (only before the work starts)").action(
|
|
@@ -10102,7 +10396,7 @@ function registerTask(program3) {
|
|
|
10102
10396
|
await api(ctx, `/v1/project-tasks/${encodeURIComponent(args[0])}`, {
|
|
10103
10397
|
method: "DELETE"
|
|
10104
10398
|
});
|
|
10105
|
-
ok({ removed: args[0] }, () => line(
|
|
10399
|
+
ok({ removed: args[0] }, () => line(import_picocolors32.default.green("removed")));
|
|
10106
10400
|
})
|
|
10107
10401
|
);
|
|
10108
10402
|
task.command("move <id> <status>").description(
|
|
@@ -10117,7 +10411,7 @@ function registerTask(program3) {
|
|
|
10117
10411
|
);
|
|
10118
10412
|
ok(
|
|
10119
10413
|
row,
|
|
10120
|
-
() => line(`${
|
|
10414
|
+
() => line(`${import_picocolors32.default.green("moved")} ${import_picocolors32.default.bold(row.title)} \u2192 ${args[1]}`)
|
|
10121
10415
|
);
|
|
10122
10416
|
})
|
|
10123
10417
|
);
|
|
@@ -10133,18 +10427,18 @@ function registerTask(program3) {
|
|
|
10133
10427
|
);
|
|
10134
10428
|
ok(row, () => {
|
|
10135
10429
|
if (!row?.queued) {
|
|
10136
|
-
line(
|
|
10430
|
+
line(import_picocolors32.default.yellow("could not resume it \u2014 check the step id"));
|
|
10137
10431
|
return;
|
|
10138
10432
|
}
|
|
10139
10433
|
const started = row.started ?? 0;
|
|
10140
10434
|
if (started > 0) {
|
|
10141
10435
|
line(
|
|
10142
|
-
`${
|
|
10436
|
+
`${import_picocolors32.default.green("resumed")} \u2014 ${started} step${started === 1 ? "" : "s"} started`
|
|
10143
10437
|
);
|
|
10144
10438
|
return;
|
|
10145
10439
|
}
|
|
10146
10440
|
line(
|
|
10147
|
-
`${
|
|
10441
|
+
`${import_picocolors32.default.green("resumed")} \u2014 it is queued, but nothing started yet. Check the plan is approved and that no step is blocking the rest.`
|
|
10148
10442
|
);
|
|
10149
10443
|
});
|
|
10150
10444
|
})
|
|
@@ -10158,11 +10452,11 @@ function registerTask(program3) {
|
|
|
10158
10452
|
);
|
|
10159
10453
|
ok(row, () => {
|
|
10160
10454
|
if (row?.reopened) {
|
|
10161
|
-
line(`${
|
|
10455
|
+
line(`${import_picocolors32.default.green("sent back")} \u2014 it will be picked up again`);
|
|
10162
10456
|
return;
|
|
10163
10457
|
}
|
|
10164
10458
|
line(
|
|
10165
|
-
|
|
10459
|
+
import_picocolors32.default.yellow(
|
|
10166
10460
|
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"
|
|
10167
10461
|
)
|
|
10168
10462
|
);
|
|
@@ -10179,7 +10473,7 @@ function registerTask(program3) {
|
|
|
10179
10473
|
`/v1/project-tasks/${encodeURIComponent(id)}/dispatch-check`,
|
|
10180
10474
|
{ method: "POST" }
|
|
10181
10475
|
);
|
|
10182
|
-
ok(row, () => line(
|
|
10476
|
+
ok(row, () => line(import_picocolors32.default.green("approved \u2014 you may start")));
|
|
10183
10477
|
})
|
|
10184
10478
|
);
|
|
10185
10479
|
task.command("start [id]").description(
|
|
@@ -10194,13 +10488,13 @@ function registerTask(program3) {
|
|
|
10194
10488
|
const started = row?.started ?? null;
|
|
10195
10489
|
if (started && started > 0) {
|
|
10196
10490
|
line(
|
|
10197
|
-
|
|
10491
|
+
import_picocolors32.default.green(
|
|
10198
10492
|
`started ${started} step${started === 1 ? "" : "s"} \u2014 they are running now`
|
|
10199
10493
|
)
|
|
10200
10494
|
);
|
|
10201
10495
|
return;
|
|
10202
10496
|
}
|
|
10203
|
-
line(
|
|
10497
|
+
line(import_picocolors32.default.yellow(row?.note ?? "Nothing started."));
|
|
10204
10498
|
});
|
|
10205
10499
|
})
|
|
10206
10500
|
);
|
|
@@ -10215,7 +10509,7 @@ function registerTask(program3) {
|
|
|
10215
10509
|
);
|
|
10216
10510
|
ok({ awaiting: row2.approval_state === "awaiting", task: row2 }, () => {
|
|
10217
10511
|
line(
|
|
10218
|
-
row2.approval_state === "awaiting" ?
|
|
10512
|
+
row2.approval_state === "awaiting" ? import_picocolors32.default.yellow(
|
|
10219
10513
|
"The plan is waiting on the owner. They see it in the task."
|
|
10220
10514
|
) : `Already ${row2.approval_state}.`
|
|
10221
10515
|
);
|
|
@@ -10240,7 +10534,7 @@ function registerTask(program3) {
|
|
|
10240
10534
|
);
|
|
10241
10535
|
ok(
|
|
10242
10536
|
row,
|
|
10243
|
-
() => line(`${
|
|
10537
|
+
() => line(`${import_picocolors32.default.green(row.approval_state)} ${import_picocolors32.default.bold(row.title)}`)
|
|
10244
10538
|
);
|
|
10245
10539
|
})
|
|
10246
10540
|
);
|
|
@@ -10256,7 +10550,7 @@ function registerTask(program3) {
|
|
|
10256
10550
|
`/v1/project-tasks/${encodeURIComponent(id)}/move`,
|
|
10257
10551
|
{ body: { status: "ready" } }
|
|
10258
10552
|
);
|
|
10259
|
-
ok(row, () => line(`${
|
|
10553
|
+
ok(row, () => line(`${import_picocolors32.default.green("ready")} ${import_picocolors32.default.bold(row.title)}`));
|
|
10260
10554
|
})
|
|
10261
10555
|
);
|
|
10262
10556
|
}
|
|
@@ -10301,24 +10595,24 @@ function assertOneOf(flag, value, allowed) {
|
|
|
10301
10595
|
}
|
|
10302
10596
|
}
|
|
10303
10597
|
function formatRow2(r) {
|
|
10304
|
-
const key =
|
|
10305
|
-
const steps = r.subtaskTotal ?
|
|
10306
|
-
const gate = r.approval_state === "awaiting" ?
|
|
10598
|
+
const key = import_picocolors32.default.dim((r.key ?? r.id.slice(0, 8)).padEnd(10));
|
|
10599
|
+
const steps = r.subtaskTotal ? import_picocolors32.default.dim(` ${r.subtaskDone}/${r.subtaskTotal}`) : "";
|
|
10600
|
+
const gate = r.approval_state === "awaiting" ? import_picocolors32.default.yellow(" awaiting approval") : "";
|
|
10307
10601
|
return `${key} ${statusTag2(r.status)} ${r.title}${steps}${gate}`;
|
|
10308
10602
|
}
|
|
10309
10603
|
function formatSubtask(r, index) {
|
|
10310
|
-
const n =
|
|
10311
|
-
const role = r.role ?
|
|
10312
|
-
const scope = r.scope_paths?.length ?
|
|
10604
|
+
const n = import_picocolors32.default.dim(String(index).padStart(2, "0"));
|
|
10605
|
+
const role = r.role ? import_picocolors32.default.dim(` [${r.role}]`) : "";
|
|
10606
|
+
const scope = r.scope_paths?.length ? import_picocolors32.default.dim(` owns: ${r.scope_paths.join(", ")}`) : "";
|
|
10313
10607
|
const head = `${n} ${statusTag2(r.status)} ${r.title}${role}${scope}`;
|
|
10314
10608
|
const summary = (r.result_summary ?? "").trim();
|
|
10315
10609
|
if (!summary) return head;
|
|
10316
10610
|
const wrapped = summary.split("\n").map((l) => ` ${l}`).join("\n");
|
|
10317
10611
|
return `${head}
|
|
10318
|
-
${
|
|
10612
|
+
${import_picocolors32.default.dim(wrapped)}`;
|
|
10319
10613
|
}
|
|
10320
10614
|
function printTask(row, goal) {
|
|
10321
|
-
line(`${
|
|
10615
|
+
line(`${import_picocolors32.default.bold(row.title)} ${import_picocolors32.default.dim(row.key ?? row.id)}`);
|
|
10322
10616
|
line(`${statusTag2(row.status)} approval: ${row.approval_state}`);
|
|
10323
10617
|
if (row.summary) line(`
|
|
10324
10618
|
${row.summary}`);
|
|
@@ -10331,53 +10625,53 @@ touches: ${row.targets.map((t) => t.appName ?? t.ref ?? t.kind).join(", ")}`
|
|
|
10331
10625
|
}
|
|
10332
10626
|
if (row.subtasks?.length) {
|
|
10333
10627
|
line(`
|
|
10334
|
-
${
|
|
10628
|
+
${import_picocolors32.default.bold("subtasks")}`);
|
|
10335
10629
|
row.subtasks.forEach((s, i) => line(formatSubtask(s, i + 1)));
|
|
10336
10630
|
line(
|
|
10337
|
-
|
|
10631
|
+
import_picocolors32.default.dim(
|
|
10338
10632
|
`
|
|
10339
10633
|
Run \`workser artifact list\` to see what these subtasks produced,`
|
|
10340
10634
|
)
|
|
10341
10635
|
);
|
|
10342
10636
|
line(
|
|
10343
|
-
|
|
10637
|
+
import_picocolors32.default.dim(
|
|
10344
10638
|
`or \`workser artifact list --step <id>\` for one subtask's output alone.`
|
|
10345
10639
|
)
|
|
10346
10640
|
);
|
|
10347
10641
|
} else {
|
|
10348
|
-
line(
|
|
10642
|
+
line(import_picocolors32.default.dim("\nNo subtasks yet."));
|
|
10349
10643
|
}
|
|
10350
10644
|
}
|
|
10351
10645
|
function printGoalContext(row, goal) {
|
|
10352
10646
|
const mine = row.phase ?? null;
|
|
10353
10647
|
line(`
|
|
10354
|
-
${
|
|
10355
|
-
if (goal.outcome) line(
|
|
10648
|
+
${import_picocolors32.default.bold("part of")}: ${goal.title}`);
|
|
10649
|
+
if (goal.outcome) line(import_picocolors32.default.dim(`done means: ${goal.outcome}`));
|
|
10356
10650
|
const progress = goal.progress ?? [];
|
|
10357
10651
|
for (const p of progress) {
|
|
10358
10652
|
const where = p.total === 0 ? "not started" : `${p.done} of ${p.total} done`;
|
|
10359
|
-
const here = mine && p.name === mine ?
|
|
10360
|
-
const mark = p.state === "done" ?
|
|
10653
|
+
const here = mine && p.name === mine ? import_picocolors32.default.cyan(" <- this task") : "";
|
|
10654
|
+
const mark = p.state === "done" ? import_picocolors32.default.green("*") : import_picocolors32.default.dim("-");
|
|
10361
10655
|
line(` ${mark} ${p.name} \u2014 ${where}${here}`);
|
|
10362
10656
|
}
|
|
10363
10657
|
const next = progress.find((p) => p.state !== "done");
|
|
10364
10658
|
const running = progress.some((p) => p.state === "working");
|
|
10365
10659
|
if (next && !running) {
|
|
10366
10660
|
line(
|
|
10367
|
-
|
|
10661
|
+
import_picocolors32.default.dim(
|
|
10368
10662
|
`
|
|
10369
10663
|
Nothing is running. The next part waiting is "${next.name}" \u2014 offer it to them in a sentence rather than starting it unasked.`
|
|
10370
10664
|
)
|
|
10371
10665
|
);
|
|
10372
10666
|
} else if (!next) {
|
|
10373
10667
|
line(
|
|
10374
|
-
|
|
10668
|
+
import_picocolors32.default.dim(
|
|
10375
10669
|
"\nEvery part of this plan is done. Say so, and offer to wrap it up."
|
|
10376
10670
|
)
|
|
10377
10671
|
);
|
|
10378
10672
|
}
|
|
10379
10673
|
line(
|
|
10380
|
-
|
|
10674
|
+
import_picocolors32.default.dim(
|
|
10381
10675
|
"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."
|
|
10382
10676
|
)
|
|
10383
10677
|
);
|
|
@@ -10385,22 +10679,22 @@ Nothing is running. The next part waiting is "${next.name}" \u2014 offer it to t
|
|
|
10385
10679
|
function statusTag2(status) {
|
|
10386
10680
|
switch (status) {
|
|
10387
10681
|
case "ready":
|
|
10388
|
-
return
|
|
10682
|
+
return import_picocolors32.default.green("[ready]");
|
|
10389
10683
|
case "working":
|
|
10390
|
-
return
|
|
10684
|
+
return import_picocolors32.default.blue("[working]");
|
|
10391
10685
|
case "checking":
|
|
10392
|
-
return
|
|
10686
|
+
return import_picocolors32.default.cyan("[checking]");
|
|
10393
10687
|
case "accepted":
|
|
10394
|
-
return
|
|
10688
|
+
return import_picocolors32.default.green("[accepted]");
|
|
10395
10689
|
case "archived":
|
|
10396
|
-
return
|
|
10690
|
+
return import_picocolors32.default.dim("[archived]");
|
|
10397
10691
|
default:
|
|
10398
|
-
return
|
|
10692
|
+
return import_picocolors32.default.dim("[todo]");
|
|
10399
10693
|
}
|
|
10400
10694
|
}
|
|
10401
10695
|
|
|
10402
10696
|
// src/commands/goal.ts
|
|
10403
|
-
var
|
|
10697
|
+
var import_picocolors33 = __toESM(require_picocolors(), 1);
|
|
10404
10698
|
var STATUSES3 = ["proposed", "agreed", "working", "delivered", "abandoned"];
|
|
10405
10699
|
var PACES = ["slice", "phase", "all"];
|
|
10406
10700
|
function registerGoal(program3) {
|
|
@@ -10413,7 +10707,7 @@ function registerGoal(program3) {
|
|
|
10413
10707
|
}) ?? [];
|
|
10414
10708
|
ok(rows, () => {
|
|
10415
10709
|
if (!rows.length) {
|
|
10416
|
-
line(
|
|
10710
|
+
line(import_picocolors33.default.dim("No goals yet \u2014 every task here stands on its own."));
|
|
10417
10711
|
return;
|
|
10418
10712
|
}
|
|
10419
10713
|
for (const g of rows) line(formatGoal(g));
|
|
@@ -10499,10 +10793,10 @@ function registerGoal(program3) {
|
|
|
10499
10793
|
}
|
|
10500
10794
|
});
|
|
10501
10795
|
ok(row, () => {
|
|
10502
|
-
success(`Proposed ${
|
|
10796
|
+
success(`Proposed ${import_picocolors33.default.bold(row?.title ?? "goal")}`);
|
|
10503
10797
|
printGoal(row);
|
|
10504
10798
|
line(
|
|
10505
|
-
|
|
10799
|
+
import_picocolors33.default.dim(
|
|
10506
10800
|
"\nNothing has been created yet. The owner agrees the shape first."
|
|
10507
10801
|
)
|
|
10508
10802
|
);
|
|
@@ -10531,7 +10825,7 @@ function registerGoal(program3) {
|
|
|
10531
10825
|
ok(
|
|
10532
10826
|
row,
|
|
10533
10827
|
() => line(
|
|
10534
|
-
row?.recorded ? met === true ?
|
|
10828
|
+
row?.recorded ? met === true ? import_picocolors33.default.green("recorded \u2014 met") : met === false ? import_picocolors33.default.yellow("recorded \u2014 not met") : import_picocolors33.default.dim("recorded \u2014 back to unchecked") : import_picocolors33.default.yellow(
|
|
10535
10829
|
"couldn't record it \u2014 check the goal id, the phase name and the criterion id"
|
|
10536
10830
|
)
|
|
10537
10831
|
)
|
|
@@ -10574,7 +10868,7 @@ function registerGoal(program3) {
|
|
|
10574
10868
|
}
|
|
10575
10869
|
ok({ goalId, phase, filed }, () => {
|
|
10576
10870
|
success(
|
|
10577
|
-
`Filed ${filed.length} ${filed.length === 1 ? "task" : "tasks"} under ${
|
|
10871
|
+
`Filed ${filed.length} ${filed.length === 1 ? "task" : "tasks"} under ${import_picocolors33.default.bold(phase)}`
|
|
10578
10872
|
);
|
|
10579
10873
|
});
|
|
10580
10874
|
})
|
|
@@ -10612,43 +10906,43 @@ function registerGoal(program3) {
|
|
|
10612
10906
|
function appScope(g) {
|
|
10613
10907
|
const n = g.appIds?.length ?? 0;
|
|
10614
10908
|
if (!n) return "";
|
|
10615
|
-
return
|
|
10909
|
+
return import_picocolors33.default.dim(` ${n} part${n === 1 ? "" : "s"} of the system`);
|
|
10616
10910
|
}
|
|
10617
10911
|
function formatGoal(g) {
|
|
10618
|
-
const where = g.currentPhase && g.status !== "delivered" ?
|
|
10619
|
-
const count = g.taskTotal != null ?
|
|
10620
|
-
return `${statusTag3(g.status)} ${g.title}${appScope(g)}${where}${count} ${
|
|
10912
|
+
const where = g.currentPhase && g.status !== "delivered" ? import_picocolors33.default.dim(` now: ${g.currentPhase}`) : "";
|
|
10913
|
+
const count = g.taskTotal != null ? import_picocolors33.default.dim(` ${g.taskDone}/${g.taskTotal} done`) : "";
|
|
10914
|
+
return `${statusTag3(g.status)} ${g.title}${appScope(g)}${where}${count} ${import_picocolors33.default.dim(g.id)}`;
|
|
10621
10915
|
}
|
|
10622
10916
|
function printGoal(g) {
|
|
10623
10917
|
if (!g) return;
|
|
10624
|
-
line(`${
|
|
10918
|
+
line(`${import_picocolors33.default.bold(g.title)} ${import_picocolors33.default.dim(g.id)}`);
|
|
10625
10919
|
line(statusTag3(g.status));
|
|
10626
10920
|
if (g.outcome) line(`
|
|
10627
10921
|
done means: ${g.outcome}`);
|
|
10628
|
-
if (g.pace) line(
|
|
10922
|
+
if (g.pace) line(import_picocolors33.default.dim(`pace: ${paceLine(g.pace)}`));
|
|
10629
10923
|
const progress = g.progress ?? [];
|
|
10630
10924
|
if (!progress.length) {
|
|
10631
|
-
line(
|
|
10925
|
+
line(import_picocolors33.default.dim("\nNo phases agreed yet."));
|
|
10632
10926
|
return;
|
|
10633
10927
|
}
|
|
10634
10928
|
line(`
|
|
10635
|
-
${
|
|
10929
|
+
${import_picocolors33.default.bold("phases")}`);
|
|
10636
10930
|
for (const p of progress) {
|
|
10637
|
-
const bar2 = p.total > 0 ? `${p.done}/${p.total} done` :
|
|
10638
|
-
const mark = p.state === "done" ?
|
|
10931
|
+
const bar2 = p.total > 0 ? `${p.done}/${p.total} done` : import_picocolors33.default.dim("nothing filed yet");
|
|
10932
|
+
const mark = p.state === "done" ? import_picocolors33.default.green("done") : p.state === "working" ? import_picocolors33.default.blue("working") : import_picocolors33.default.dim("waiting");
|
|
10639
10933
|
line(
|
|
10640
|
-
` ${
|
|
10934
|
+
` ${import_picocolors33.default.dim(String(p.index).padStart(2, "0"))} ${p.name} ${mark} ${import_picocolors33.default.dim(bar2)}`
|
|
10641
10935
|
);
|
|
10642
10936
|
for (const c of p.criteria ?? []) {
|
|
10643
|
-
const tick = c.met === true ?
|
|
10644
|
-
line(` ${tick} ${c.text} ${
|
|
10645
|
-
if (c.note) line(
|
|
10937
|
+
const tick = c.met === true ? import_picocolors33.default.green("\u2713") : c.met === false ? import_picocolors33.default.red("\u2717") : import_picocolors33.default.dim("\xB7");
|
|
10938
|
+
line(` ${tick} ${c.text} ${import_picocolors33.default.dim(c.id)}`);
|
|
10939
|
+
if (c.note) line(import_picocolors33.default.dim(` ${c.note}`));
|
|
10646
10940
|
}
|
|
10647
10941
|
}
|
|
10648
10942
|
const current = progress.find((p) => p.name === g.currentPhase);
|
|
10649
10943
|
if (current) {
|
|
10650
10944
|
line(
|
|
10651
|
-
|
|
10945
|
+
import_picocolors33.default.dim(
|
|
10652
10946
|
`
|
|
10653
10947
|
${current.name} \u2014 ${current.done} of ${current.total} done (phase ${current.index} of ${progress.length}).`
|
|
10654
10948
|
)
|
|
@@ -10658,15 +10952,15 @@ ${current.name} \u2014 ${current.done} of ${current.total} done (phase ${current
|
|
|
10658
10952
|
function statusTag3(status) {
|
|
10659
10953
|
switch (status) {
|
|
10660
10954
|
case "agreed":
|
|
10661
|
-
return
|
|
10955
|
+
return import_picocolors33.default.cyan("[agreed]");
|
|
10662
10956
|
case "working":
|
|
10663
|
-
return
|
|
10957
|
+
return import_picocolors33.default.blue("[working]");
|
|
10664
10958
|
case "delivered":
|
|
10665
|
-
return
|
|
10959
|
+
return import_picocolors33.default.green("[delivered]");
|
|
10666
10960
|
case "abandoned":
|
|
10667
|
-
return
|
|
10961
|
+
return import_picocolors33.default.dim("[abandoned]");
|
|
10668
10962
|
default:
|
|
10669
|
-
return
|
|
10963
|
+
return import_picocolors33.default.yellow("[proposed]");
|
|
10670
10964
|
}
|
|
10671
10965
|
}
|
|
10672
10966
|
function paceLine(pace) {
|
|
@@ -10720,7 +11014,7 @@ function stripLeadingGlobalOptions(argv) {
|
|
|
10720
11014
|
}
|
|
10721
11015
|
|
|
10722
11016
|
// src/commands/decision.ts
|
|
10723
|
-
var
|
|
11017
|
+
var import_picocolors34 = __toESM(require_picocolors(), 1);
|
|
10724
11018
|
function registerDecision(program3) {
|
|
10725
11019
|
const decision = program3.command("decision").description("Read and record the project's architecture decisions");
|
|
10726
11020
|
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)").option("--search <text>", "match the title, case-insensitively").option("--label <name>", "only decisions carrying this label").option("--app <id>", "only decisions about this app").option("--infra <name>", "only decisions touching this part of the infrastructure").option("--status <name>", "proposed | accepted | superseded").action(
|
|
@@ -10743,13 +11037,13 @@ function registerDecision(program3) {
|
|
|
10743
11037
|
rows = applyLimit(rows, opts.limit);
|
|
10744
11038
|
ok(rows, () => {
|
|
10745
11039
|
if (!rows.length) {
|
|
10746
|
-
line(
|
|
11040
|
+
line(import_picocolors34.default.dim("No decisions recorded yet."));
|
|
10747
11041
|
return;
|
|
10748
11042
|
}
|
|
10749
11043
|
for (const r of rows) {
|
|
10750
11044
|
const tags = [...r.labels ?? [], ...r.infraRefs ?? []];
|
|
10751
|
-
const meta = tags.length ?
|
|
10752
|
-
line(`${
|
|
11045
|
+
const meta = tags.length ? import_picocolors34.default.dim(` [${tags.join(", ")}]`) : "";
|
|
11046
|
+
line(`${import_picocolors34.default.dim(r.id)} ${import_picocolors34.default.dim(shortDate(r.createdAt))} ${r.title}${meta}`);
|
|
10753
11047
|
line(` ${truncate(r.decision, 100)}`);
|
|
10754
11048
|
}
|
|
10755
11049
|
});
|
|
@@ -10763,16 +11057,16 @@ function registerDecision(program3) {
|
|
|
10763
11057
|
`/v1/projects/${projectId}/architecture-decisions/${args[0]}`
|
|
10764
11058
|
);
|
|
10765
11059
|
ok(row, () => {
|
|
10766
|
-
line(`${
|
|
10767
|
-
line(
|
|
11060
|
+
line(`${import_picocolors34.default.bold(row.title)} ${import_picocolors34.default.dim(row.id)}`);
|
|
11061
|
+
line(import_picocolors34.default.dim(`${row.status} \xB7 ${shortDate(row.createdAt)}`));
|
|
10768
11062
|
line(`
|
|
10769
|
-
${
|
|
11063
|
+
${import_picocolors34.default.bold("Context")}
|
|
10770
11064
|
${row.context}`);
|
|
10771
11065
|
line(`
|
|
10772
|
-
${
|
|
11066
|
+
${import_picocolors34.default.bold("Decision")}
|
|
10773
11067
|
${row.decision}`);
|
|
10774
11068
|
if (row.consequences) line(`
|
|
10775
|
-
${
|
|
11069
|
+
${import_picocolors34.default.bold("Consequences")}
|
|
10776
11070
|
${row.consequences}`);
|
|
10777
11071
|
});
|
|
10778
11072
|
})
|
|
@@ -10789,7 +11083,7 @@ ${row.consequences}`);
|
|
|
10789
11083
|
const path = `/v1/projects/${projectId}/architecture-decisions/${id}`;
|
|
10790
11084
|
if (opts.delete) {
|
|
10791
11085
|
await api(ctx, path, { method: "DELETE" });
|
|
10792
|
-
ok({ deleted: true, id }, () => line(`Deleted decision ${
|
|
11086
|
+
ok({ deleted: true, id }, () => line(`Deleted decision ${import_picocolors34.default.bold(id)}.`));
|
|
10793
11087
|
return;
|
|
10794
11088
|
}
|
|
10795
11089
|
const row = await api(ctx, path, {
|
|
@@ -10799,7 +11093,7 @@ ${row.consequences}`);
|
|
|
10799
11093
|
ok(
|
|
10800
11094
|
row,
|
|
10801
11095
|
() => line(
|
|
10802
|
-
`Marked ${
|
|
11096
|
+
`Marked ${import_picocolors34.default.bold(row?.title ?? id)} superseded.` + (opts.reason ? ` Record the replacement with \`decision create\`.` : "")
|
|
10803
11097
|
)
|
|
10804
11098
|
);
|
|
10805
11099
|
})
|
|
@@ -10820,7 +11114,7 @@ ${row.consequences}`);
|
|
|
10820
11114
|
`/v1/projects/${projectId}/architecture-decisions/${id}`,
|
|
10821
11115
|
{ method: "PATCH", body }
|
|
10822
11116
|
);
|
|
10823
|
-
ok(row, () => line(`Filed decision ${
|
|
11117
|
+
ok(row, () => line(`Filed decision ${import_picocolors34.default.bold(row?.title ?? id)}.`));
|
|
10824
11118
|
})
|
|
10825
11119
|
);
|
|
10826
11120
|
decision.command("create <title>").description(
|
|
@@ -10851,7 +11145,7 @@ ${row.consequences}`);
|
|
|
10851
11145
|
refId: row?.id,
|
|
10852
11146
|
output: { decision: row }
|
|
10853
11147
|
});
|
|
10854
|
-
ok(row, () => line(`Recorded decision ${
|
|
11148
|
+
ok(row, () => line(`Recorded decision ${import_picocolors34.default.bold(row?.id ?? "")} \u2014 ${title}`));
|
|
10855
11149
|
})
|
|
10856
11150
|
);
|
|
10857
11151
|
const requirement = program3.command("requirement").description("Read and record the project's requirements");
|
|
@@ -10863,11 +11157,11 @@ ${row.consequences}`);
|
|
|
10863
11157
|
rows = applyLimit(rows, opts.limit);
|
|
10864
11158
|
ok(rows, () => {
|
|
10865
11159
|
if (!rows.length) {
|
|
10866
|
-
line(
|
|
11160
|
+
line(import_picocolors34.default.dim("No requirements recorded yet."));
|
|
10867
11161
|
return;
|
|
10868
11162
|
}
|
|
10869
11163
|
for (const r of rows) {
|
|
10870
|
-
line(`${
|
|
11164
|
+
line(`${import_picocolors34.default.dim(r.id)} ${r.status.padEnd(9)} ${r.title}`);
|
|
10871
11165
|
}
|
|
10872
11166
|
});
|
|
10873
11167
|
})
|
|
@@ -10880,8 +11174,8 @@ ${row.consequences}`);
|
|
|
10880
11174
|
`/v1/projects/${projectId}/requirements/${args[0]}`
|
|
10881
11175
|
);
|
|
10882
11176
|
ok(row, () => {
|
|
10883
|
-
line(`${
|
|
10884
|
-
line(
|
|
11177
|
+
line(`${import_picocolors34.default.bold(row.title)} ${import_picocolors34.default.dim(row.id)}`);
|
|
11178
|
+
line(import_picocolors34.default.dim(`${row.status} \xB7 ${shortDate(row.createdAt)}`));
|
|
10885
11179
|
line(`
|
|
10886
11180
|
${row.body}`);
|
|
10887
11181
|
});
|
|
@@ -10907,7 +11201,7 @@ ${row.body}`);
|
|
|
10907
11201
|
refId: row?.id,
|
|
10908
11202
|
output: { requirement: row }
|
|
10909
11203
|
});
|
|
10910
|
-
ok(row, () => line(`Recorded requirement ${
|
|
11204
|
+
ok(row, () => line(`Recorded requirement ${import_picocolors34.default.bold(row?.id ?? "")} \u2014 ${title}`));
|
|
10911
11205
|
})
|
|
10912
11206
|
);
|
|
10913
11207
|
requirement.command("update <id>").description(
|
|
@@ -10936,7 +11230,7 @@ ${row.body}`);
|
|
|
10936
11230
|
code: "bad_request"
|
|
10937
11231
|
});
|
|
10938
11232
|
}
|
|
10939
|
-
ok(row, () => line(`Updated requirement ${
|
|
11233
|
+
ok(row, () => line(`Updated requirement ${import_picocolors34.default.bold(row.id)} \u2014 ${row.title} (${row.status})`));
|
|
10940
11234
|
})
|
|
10941
11235
|
);
|
|
10942
11236
|
}
|
|
@@ -10975,7 +11269,7 @@ function toList(value) {
|
|
|
10975
11269
|
}
|
|
10976
11270
|
|
|
10977
11271
|
// src/commands/doc.ts
|
|
10978
|
-
var
|
|
11272
|
+
var import_picocolors35 = __toESM(require_picocolors(), 1);
|
|
10979
11273
|
|
|
10980
11274
|
// src/mermaid-fences.ts
|
|
10981
11275
|
function hasDiagram(code) {
|
|
@@ -11062,16 +11356,16 @@ function registerDoc(program3) {
|
|
|
11062
11356
|
}) ?? [];
|
|
11063
11357
|
ok(rows, () => {
|
|
11064
11358
|
if (!rows.length) {
|
|
11065
|
-
line(
|
|
11359
|
+
line(import_picocolors35.default.dim("No documents yet."));
|
|
11066
11360
|
return;
|
|
11067
11361
|
}
|
|
11068
11362
|
for (const r of rows) {
|
|
11069
|
-
const link = r.workItemId ?
|
|
11070
|
-
const file = r.filePath ?
|
|
11363
|
+
const link = r.workItemId ? import_picocolors35.default.dim(` \u21B3 ${r.workItemId}`) : "";
|
|
11364
|
+
const file = r.filePath ? import_picocolors35.default.dim(` ${r.filePath}`) : "";
|
|
11071
11365
|
const tags = [...r.labels ?? [], ...r.infraRefs ?? []];
|
|
11072
|
-
const meta = tags.length ?
|
|
11073
|
-
const kind = r.docKind ?
|
|
11074
|
-
line(`${
|
|
11366
|
+
const meta = tags.length ? import_picocolors35.default.dim(` [${tags.join(", ")}]`) : "";
|
|
11367
|
+
const kind = r.docKind ? import_picocolors35.default.dim(`${r.docKind} `) : "";
|
|
11368
|
+
line(`${import_picocolors35.default.dim(r.id)} ${kind}${r.title}${meta}${link}${file}`);
|
|
11075
11369
|
}
|
|
11076
11370
|
});
|
|
11077
11371
|
})
|
|
@@ -11085,17 +11379,17 @@ function registerDoc(program3) {
|
|
|
11085
11379
|
);
|
|
11086
11380
|
if (opts.markdown) {
|
|
11087
11381
|
ok({ id: row.id, title: row.title, filePath: row.filePath }, () => {
|
|
11088
|
-
line(`${
|
|
11382
|
+
line(`${import_picocolors35.default.bold(row.title)} ${import_picocolors35.default.dim(row.id)}`);
|
|
11089
11383
|
line(
|
|
11090
|
-
row.filePath ? `Read it at ${
|
|
11384
|
+
row.filePath ? `Read it at ${import_picocolors35.default.bold(row.filePath)} (relative to the project folder).` : import_picocolors35.default.dim("This document has no markdown mirror on disk yet.")
|
|
11091
11385
|
);
|
|
11092
11386
|
});
|
|
11093
11387
|
return;
|
|
11094
11388
|
}
|
|
11095
11389
|
ok(row, () => {
|
|
11096
|
-
line(`${
|
|
11097
|
-
if (row.workItemId) line(
|
|
11098
|
-
if (row.filePath) line(
|
|
11390
|
+
line(`${import_picocolors35.default.bold(row.title)} ${import_picocolors35.default.dim(row.id)}`);
|
|
11391
|
+
if (row.workItemId) line(import_picocolors35.default.dim(`linked to work item ${row.workItemId}`));
|
|
11392
|
+
if (row.filePath) line(import_picocolors35.default.dim(`markdown mirror: ${row.filePath}`));
|
|
11099
11393
|
line("");
|
|
11100
11394
|
line(row.contentJson);
|
|
11101
11395
|
});
|
|
@@ -11128,7 +11422,7 @@ function registerDoc(program3) {
|
|
|
11128
11422
|
refId: row?.id,
|
|
11129
11423
|
output: { document: row }
|
|
11130
11424
|
});
|
|
11131
|
-
ok(row, () => line(`Created document ${
|
|
11425
|
+
ok(row, () => line(`Created document ${import_picocolors35.default.bold(row?.id ?? "")} \u2014 ${title}`));
|
|
11132
11426
|
})
|
|
11133
11427
|
);
|
|
11134
11428
|
doc.command("file <id>").description("File an existing document \u2014 its kind, labels, app, infrastructure").option("--kind <kind>", `what this document IS \u2014 ${KIND_HELP2}`).option("--label <name...>", "tag it \u2014 shares the project's label vocabulary").option("--app <id>", "which app this document is about").option("--infra <name...>", "what it touches: database, storage, auth, \u2026").action(
|
|
@@ -11147,7 +11441,7 @@ function registerDoc(program3) {
|
|
|
11147
11441
|
`/v1/projects/${projectId}/documents/${id}`,
|
|
11148
11442
|
{ method: "PATCH", body }
|
|
11149
11443
|
);
|
|
11150
|
-
ok(row, () => line(`Filed ${
|
|
11444
|
+
ok(row, () => line(`Filed ${import_picocolors35.default.bold(row?.title ?? id)}.`));
|
|
11151
11445
|
})
|
|
11152
11446
|
);
|
|
11153
11447
|
doc.command("diagram <id>").description(
|
|
@@ -11173,19 +11467,19 @@ function registerDoc(program3) {
|
|
|
11173
11467
|
diagrams: diagrams.map((code) => ({ kind: diagramKind(code), code }))
|
|
11174
11468
|
};
|
|
11175
11469
|
ok(payload, () => {
|
|
11176
|
-
line(`${
|
|
11470
|
+
line(`${import_picocolors35.default.bold(row.title)} ${import_picocolors35.default.dim(row.id)}`);
|
|
11177
11471
|
if (markdown === null) {
|
|
11178
11472
|
line(
|
|
11179
|
-
|
|
11473
|
+
import_picocolors35.default.dim(
|
|
11180
11474
|
row.filePath ? `Could not read ${row.filePath} from this folder.` : "This document has no markdown mirror on disk yet."
|
|
11181
11475
|
)
|
|
11182
11476
|
);
|
|
11183
11477
|
} else if (!diagrams.length) {
|
|
11184
|
-
line(
|
|
11478
|
+
line(import_picocolors35.default.dim("No diagrams in this document."));
|
|
11185
11479
|
} else {
|
|
11186
11480
|
for (const [i, code] of diagrams.entries()) {
|
|
11187
11481
|
const kind = diagramKind(code) ?? "diagram";
|
|
11188
|
-
line(`${
|
|
11482
|
+
line(`${import_picocolors35.default.dim(String(i + 1))} ${kind} ${import_picocolors35.default.dim(`${code.split("\n").length} lines`)}`);
|
|
11189
11483
|
}
|
|
11190
11484
|
}
|
|
11191
11485
|
});
|
|
@@ -11221,7 +11515,7 @@ function registerDoc(program3) {
|
|
|
11221
11515
|
code: "bad_request"
|
|
11222
11516
|
});
|
|
11223
11517
|
}
|
|
11224
|
-
ok(row, () => line(`Updated document ${
|
|
11518
|
+
ok(row, () => line(`Updated document ${import_picocolors35.default.bold(row.id)} \u2014 ${row.title}`));
|
|
11225
11519
|
})
|
|
11226
11520
|
);
|
|
11227
11521
|
}
|
|
@@ -11235,7 +11529,7 @@ function readMirror(cwd, filePath) {
|
|
|
11235
11529
|
}
|
|
11236
11530
|
|
|
11237
11531
|
// src/commands/design.ts
|
|
11238
|
-
var
|
|
11532
|
+
var import_picocolors36 = __toESM(require_picocolors(), 1);
|
|
11239
11533
|
function registerDesign(program3) {
|
|
11240
11534
|
const design = program3.command("design").description("The project's brand, and pictures of the screens you draw");
|
|
11241
11535
|
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(
|
|
@@ -11249,11 +11543,11 @@ function registerDesign(program3) {
|
|
|
11249
11543
|
if (opts.raw) {
|
|
11250
11544
|
ok(files, () => {
|
|
11251
11545
|
if (!files.length) {
|
|
11252
|
-
line(
|
|
11546
|
+
line(import_picocolors36.default.dim("No brand set for this project."));
|
|
11253
11547
|
return;
|
|
11254
11548
|
}
|
|
11255
11549
|
for (const f of files) {
|
|
11256
|
-
line(
|
|
11550
|
+
line(import_picocolors36.default.bold(f.path));
|
|
11257
11551
|
line(f.contents);
|
|
11258
11552
|
line("");
|
|
11259
11553
|
}
|
|
@@ -11270,21 +11564,21 @@ function registerDesign(program3) {
|
|
|
11270
11564
|
} : { hasBrand: false, colors: {}, fonts: {}, brand: {}, files: [] };
|
|
11271
11565
|
ok(summary, () => {
|
|
11272
11566
|
if (!tokens) {
|
|
11273
|
-
line(
|
|
11567
|
+
line(import_picocolors36.default.dim("No brand set for this project \u2014 choose sensible styling yourself."));
|
|
11274
11568
|
return;
|
|
11275
11569
|
}
|
|
11276
11570
|
for (const [name, value] of Object.entries(tokens.brand)) {
|
|
11277
|
-
line(`${
|
|
11571
|
+
line(`${import_picocolors36.default.dim(name.padEnd(12))} ${value}`);
|
|
11278
11572
|
}
|
|
11279
11573
|
for (const [name, value] of Object.entries(tokens.color)) {
|
|
11280
|
-
line(`${
|
|
11574
|
+
line(`${import_picocolors36.default.dim(`color.${name}`.padEnd(12))} ${value}`);
|
|
11281
11575
|
}
|
|
11282
11576
|
for (const [name, value] of Object.entries(tokens.font)) {
|
|
11283
|
-
line(`${
|
|
11577
|
+
line(`${import_picocolors36.default.dim(`font.${name}`.padEnd(12))} ${value}`);
|
|
11284
11578
|
}
|
|
11285
11579
|
line("");
|
|
11286
11580
|
line(
|
|
11287
|
-
|
|
11581
|
+
import_picocolors36.default.dim(
|
|
11288
11582
|
`Generated into the working tree as ${files.map((f) => f.path).join(", ")} \u2014 wire those in, never edit them.`
|
|
11289
11583
|
)
|
|
11290
11584
|
);
|
|
@@ -11306,19 +11600,19 @@ function registerDesign(program3) {
|
|
|
11306
11600
|
ok(res, () => {
|
|
11307
11601
|
for (const shot of res.shots ?? []) {
|
|
11308
11602
|
if (shot.out) {
|
|
11309
|
-
line(`${
|
|
11603
|
+
line(`${import_picocolors36.default.green("\u2713")} ${shot.file} ${import_picocolors36.default.dim("\u2192")} ${shot.out}`);
|
|
11310
11604
|
} else {
|
|
11311
|
-
line(`${
|
|
11605
|
+
line(`${import_picocolors36.default.red("\u2717")} ${shot.file} ${import_picocolors36.default.dim(shot.error ?? "no image")}`);
|
|
11312
11606
|
}
|
|
11313
11607
|
}
|
|
11314
11608
|
for (const path of res.refused ?? []) {
|
|
11315
|
-
line(
|
|
11609
|
+
line(import_picocolors36.default.dim(`skipped ${path} \u2014 not a page inside this project`));
|
|
11316
11610
|
}
|
|
11317
11611
|
const made = (res.shots ?? []).filter((s) => s.out).length;
|
|
11318
11612
|
if (made) {
|
|
11319
11613
|
line("");
|
|
11320
11614
|
line(
|
|
11321
|
-
|
|
11615
|
+
import_picocolors36.default.dim(
|
|
11322
11616
|
`Record each one so it shows up: workser artifact add <file>.png --kind design -d "<what this screen is>"`
|
|
11323
11617
|
)
|
|
11324
11618
|
);
|
|
@@ -11350,7 +11644,7 @@ function unwrap(group) {
|
|
|
11350
11644
|
}
|
|
11351
11645
|
|
|
11352
11646
|
// src/commands/api.ts
|
|
11353
|
-
var
|
|
11647
|
+
var import_picocolors37 = __toESM(require_picocolors(), 1);
|
|
11354
11648
|
import { readdirSync, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
|
|
11355
11649
|
import { join as join3, relative, sep } from "path";
|
|
11356
11650
|
|
|
@@ -11444,16 +11738,16 @@ function specReport(routes, documented) {
|
|
|
11444
11738
|
ok: missing.length === 0
|
|
11445
11739
|
};
|
|
11446
11740
|
}
|
|
11447
|
-
function specSummary(
|
|
11741
|
+
function specSummary(report2, specFile) {
|
|
11448
11742
|
if (!specFile) {
|
|
11449
11743
|
return `This service has no API description. Write one at ${SPEC_FILES[0]} listing the routes it serves.`;
|
|
11450
11744
|
}
|
|
11451
|
-
if (
|
|
11452
|
-
const n =
|
|
11745
|
+
if (report2.ok) {
|
|
11746
|
+
const n = report2.routes.length;
|
|
11453
11747
|
return n === 1 ? `The one route this service has is described in ${specFile}.` : `All ${n} routes are described in ${specFile}.`;
|
|
11454
11748
|
}
|
|
11455
|
-
const names =
|
|
11456
|
-
return `${
|
|
11749
|
+
const names = report2.missing.map((m) => m.path).join(", ");
|
|
11750
|
+
return `${report2.missing.length} route${report2.missing.length === 1 ? " is" : "s are"} not described in ${specFile}: ${names}`;
|
|
11457
11751
|
}
|
|
11458
11752
|
|
|
11459
11753
|
// src/commands/api.ts
|
|
@@ -11464,10 +11758,10 @@ function registerApi(program3) {
|
|
|
11464
11758
|
const appId = requireApp2(opts.app);
|
|
11465
11759
|
const res = await api(ctx, `/v1/apps/${encodeURIComponent(appId)}/api/requests`);
|
|
11466
11760
|
ok(res, () => {
|
|
11467
|
-
for (const note of res?.notes ?? []) line(
|
|
11761
|
+
for (const note of res?.notes ?? []) line(import_picocolors37.default.dim(note));
|
|
11468
11762
|
for (const r of res?.requests ?? []) {
|
|
11469
11763
|
line(
|
|
11470
|
-
`${
|
|
11764
|
+
`${import_picocolors37.default.dim(r.method.padEnd(6))}${r.path}${r.note ? import_picocolors37.default.dim(` ${r.note}`) : ""}`
|
|
11471
11765
|
);
|
|
11472
11766
|
}
|
|
11473
11767
|
});
|
|
@@ -11501,14 +11795,14 @@ function registerApi(program3) {
|
|
|
11501
11795
|
);
|
|
11502
11796
|
ok(res, () => {
|
|
11503
11797
|
if (!res?.ok) {
|
|
11504
|
-
line(
|
|
11798
|
+
line(import_picocolors37.default.red(res?.error ?? "The service did not answer."));
|
|
11505
11799
|
return;
|
|
11506
11800
|
}
|
|
11507
11801
|
const code = `${res.status}${res.statusText ? ` ${res.statusText}` : ""}`;
|
|
11508
|
-
const colour2 = res.status && res.status < 300 ?
|
|
11509
|
-
line(`${colour2(code)} ${
|
|
11802
|
+
const colour2 = res.status && res.status < 300 ? import_picocolors37.default.green : res.status && res.status < 500 ? import_picocolors37.default.yellow : import_picocolors37.default.red;
|
|
11803
|
+
line(`${colour2(code)} ${import_picocolors37.default.dim(`${res.durationMs}ms ${res.url}`)}`);
|
|
11510
11804
|
if (res.body) line(res.body);
|
|
11511
|
-
if (res.truncated) line(
|
|
11805
|
+
if (res.truncated) line(import_picocolors37.default.dim("(answer truncated)"));
|
|
11512
11806
|
});
|
|
11513
11807
|
if (!res?.ok) process.exitCode = 1;
|
|
11514
11808
|
})
|
|
@@ -11522,23 +11816,23 @@ function registerApi(program3) {
|
|
|
11522
11816
|
const routes = discoverRoutes(files);
|
|
11523
11817
|
const specFile = SPEC_FILES.find((f) => files.includes(f)) ?? null;
|
|
11524
11818
|
const documented = specFile ? specPaths(readIfPresent(join3(ctx.cwd, specFile))) : [];
|
|
11525
|
-
const
|
|
11526
|
-
const summary = specSummary(
|
|
11527
|
-
ok({ ...
|
|
11528
|
-
for (const r of
|
|
11529
|
-
const known =
|
|
11819
|
+
const report2 = specReport(routes, documented);
|
|
11820
|
+
const summary = specSummary(report2, specFile);
|
|
11821
|
+
ok({ ...report2, specFile, summary }, () => {
|
|
11822
|
+
for (const r of report2.routes) {
|
|
11823
|
+
const known = report2.missing.some((m) => m.path === r.path);
|
|
11530
11824
|
line(
|
|
11531
|
-
`${known ?
|
|
11825
|
+
`${known ? import_picocolors37.default.yellow("undocumented") : import_picocolors37.default.green("documented ")} ${r.path}${import_picocolors37.default.dim(` ${r.file}`)}`
|
|
11532
11826
|
);
|
|
11533
11827
|
}
|
|
11534
|
-
for (const p of
|
|
11535
|
-
line(`${
|
|
11828
|
+
for (const p of report2.stale) {
|
|
11829
|
+
line(`${import_picocolors37.default.dim("in spec only ")} ${p}`);
|
|
11536
11830
|
}
|
|
11537
11831
|
line("");
|
|
11538
|
-
if (
|
|
11539
|
-
else line(
|
|
11832
|
+
if (report2.ok && specFile) success(summary);
|
|
11833
|
+
else line(import_picocolors37.default.yellow(summary));
|
|
11540
11834
|
});
|
|
11541
|
-
if (opts.check && !
|
|
11835
|
+
if (opts.check && !report2.ok) {
|
|
11542
11836
|
throw new WorkserError(summary, { code: "bad_request" });
|
|
11543
11837
|
}
|
|
11544
11838
|
if (opts.check && !specFile) {
|
|
@@ -11607,7 +11901,7 @@ function listRepoFiles(root, maxDepth = 8) {
|
|
|
11607
11901
|
}
|
|
11608
11902
|
|
|
11609
11903
|
// src/commands/analysis.ts
|
|
11610
|
-
var
|
|
11904
|
+
var import_picocolors38 = __toESM(require_picocolors(), 1);
|
|
11611
11905
|
import { readFileSync as readFileSync4 } from "fs";
|
|
11612
11906
|
function registerAnalysis(program3) {
|
|
11613
11907
|
const cmd = program3.command("analysis").description("Run Python analysis locally, recorded in the task");
|
|
@@ -11617,14 +11911,14 @@ function registerAnalysis(program3) {
|
|
|
11617
11911
|
const res = await api(ctx, path);
|
|
11618
11912
|
ok(res, () => {
|
|
11619
11913
|
line(
|
|
11620
|
-
`${res?.available ?
|
|
11914
|
+
`${res?.available ? import_picocolors38.default.green("python") : import_picocolors38.default.red("python")} ${res?.version ?? "not found"} ${import_picocolors38.default.dim(res?.python ?? "")}`
|
|
11621
11915
|
);
|
|
11622
11916
|
for (const lib of res?.libraries ?? []) {
|
|
11623
11917
|
line(
|
|
11624
|
-
`${lib.present ?
|
|
11918
|
+
`${lib.present ? import_picocolors38.default.green(lib.name) : import_picocolors38.default.yellow(lib.name)}${import_picocolors38.default.dim(lib.present ? "" : " missing")}`
|
|
11625
11919
|
);
|
|
11626
11920
|
}
|
|
11627
|
-
for (const note of res?.notes ?? []) line(
|
|
11921
|
+
for (const note of res?.notes ?? []) line(import_picocolors38.default.dim(note));
|
|
11628
11922
|
});
|
|
11629
11923
|
if (!res?.available) process.exitCode = 1;
|
|
11630
11924
|
})
|
|
@@ -11646,15 +11940,15 @@ function registerAnalysis(program3) {
|
|
|
11646
11940
|
);
|
|
11647
11941
|
ok(res, () => {
|
|
11648
11942
|
if (res?.stdout) line(res.stdout.replace(/\n$/, ""));
|
|
11649
|
-
if (res?.stderr) line(
|
|
11650
|
-
if (res?.truncated) line(
|
|
11943
|
+
if (res?.stderr) line(import_picocolors38.default.dim(res.stderr.replace(/\n$/, "")));
|
|
11944
|
+
if (res?.truncated) line(import_picocolors38.default.dim("(output truncated)"));
|
|
11651
11945
|
const took = `${Math.round((res?.durationMs ?? 0) / 100) / 10}s`;
|
|
11652
11946
|
line(
|
|
11653
|
-
res?.ok ?
|
|
11947
|
+
res?.ok ? import_picocolors38.default.green(`\u2713 ${res.summary ?? "It finished."}`) + import_picocolors38.default.dim(` ${took}`) : import_picocolors38.default.yellow(res?.summary ?? "It did not finish.") + import_picocolors38.default.dim(` ${took}`)
|
|
11654
11948
|
);
|
|
11655
11949
|
if (res && !res.sandboxed) {
|
|
11656
11950
|
line(
|
|
11657
|
-
|
|
11951
|
+
import_picocolors38.default.dim(
|
|
11658
11952
|
"This platform has no OS sandbox, so the script ran with your own file access."
|
|
11659
11953
|
)
|
|
11660
11954
|
);
|
|
@@ -11682,7 +11976,7 @@ function readCode(file, inline) {
|
|
|
11682
11976
|
}
|
|
11683
11977
|
|
|
11684
11978
|
// src/commands/scan.ts
|
|
11685
|
-
var
|
|
11979
|
+
var import_picocolors39 = __toESM(require_picocolors(), 1);
|
|
11686
11980
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
11687
11981
|
import { existsSync as existsSync3, readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync3 } from "fs";
|
|
11688
11982
|
import { join as join4, relative as relative2, sep as sep2 } from "path";
|
|
@@ -11840,15 +12134,15 @@ function buildReport(input) {
|
|
|
11840
12134
|
function rank(s) {
|
|
11841
12135
|
return s === "high" ? 3 : s === "medium" ? 2 : 1;
|
|
11842
12136
|
}
|
|
11843
|
-
function scanSummary(
|
|
11844
|
-
const ran =
|
|
12137
|
+
function scanSummary(report2) {
|
|
12138
|
+
const ran = report2.checked.length;
|
|
11845
12139
|
if (!ran) return "Nothing could be checked \u2014 see the reasons above.";
|
|
11846
|
-
const what =
|
|
11847
|
-
const total =
|
|
12140
|
+
const what = report2.checked.join(", ");
|
|
12141
|
+
const total = report2.findings.length;
|
|
11848
12142
|
if (!total) {
|
|
11849
12143
|
return `Checked ${what} \u2014 nothing found.`;
|
|
11850
12144
|
}
|
|
11851
|
-
const high =
|
|
12145
|
+
const high = report2.counts.high;
|
|
11852
12146
|
return `Checked ${what} \u2014 ${total} ${total === 1 ? "thing" : "things"} to look at` + (high ? `, ${high} of them serious.` : ".");
|
|
11853
12147
|
}
|
|
11854
12148
|
|
|
@@ -11870,10 +12164,10 @@ function registerScan(program3) {
|
|
|
11870
12164
|
if (only.has("secrets")) runSecrets(ctx.cwd, !!opts.staged, findings, checked, skipped);
|
|
11871
12165
|
if (only.has("deps")) runDeps(ctx.cwd, findings, checked, skipped);
|
|
11872
12166
|
if (only.has("permissions")) runPermissions(ctx.cwd, findings, checked, skipped);
|
|
11873
|
-
const
|
|
11874
|
-
const summary = scanSummary(
|
|
11875
|
-
ok({ ...
|
|
11876
|
-
if (opts.check && !
|
|
12167
|
+
const report2 = buildReport({ findings, checked, skipped });
|
|
12168
|
+
const summary = scanSummary(report2);
|
|
12169
|
+
ok({ ...report2, summary }, () => print2(report2, summary));
|
|
12170
|
+
if (opts.check && !report2.ok) {
|
|
11877
12171
|
throw new WorkserError(summary, { code: "bad_request" });
|
|
11878
12172
|
}
|
|
11879
12173
|
})
|
|
@@ -11964,24 +12258,24 @@ function runPermissions(cwd, findings, checked, skipped) {
|
|
|
11964
12258
|
});
|
|
11965
12259
|
}
|
|
11966
12260
|
}
|
|
11967
|
-
function print2(
|
|
11968
|
-
for (const s of
|
|
11969
|
-
line(`${
|
|
12261
|
+
function print2(report2, summary) {
|
|
12262
|
+
for (const s of report2.skipped) {
|
|
12263
|
+
line(`${import_picocolors39.default.yellow("not checked")} ${s.check}${import_picocolors39.default.dim(` \u2014 ${s.reason}`)}`);
|
|
11970
12264
|
}
|
|
11971
|
-
for (const f of
|
|
11972
|
-
const where = f.file ?
|
|
12265
|
+
for (const f of report2.findings) {
|
|
12266
|
+
const where = f.file ? import_picocolors39.default.dim(` ${f.file}${f.line ? `:${f.line}` : ""}`) : "";
|
|
11973
12267
|
line(`${severityTag(f.severity)} ${f.title}${where}`);
|
|
11974
|
-
line(` ${
|
|
12268
|
+
line(` ${import_picocolors39.default.dim(f.fix)}`);
|
|
11975
12269
|
}
|
|
11976
|
-
if (
|
|
11977
|
-
if (
|
|
11978
|
-
else if (
|
|
11979
|
-
else line(
|
|
12270
|
+
if (report2.findings.length || report2.skipped.length) line("");
|
|
12271
|
+
if (report2.ok && !report2.skipped.length) success(summary);
|
|
12272
|
+
else if (report2.ok) line(import_picocolors39.default.yellow(summary));
|
|
12273
|
+
else line(import_picocolors39.default.red(summary));
|
|
11980
12274
|
}
|
|
11981
12275
|
function severityTag(severity) {
|
|
11982
|
-
if (severity === "high") return
|
|
11983
|
-
if (severity === "medium") return
|
|
11984
|
-
return
|
|
12276
|
+
if (severity === "high") return import_picocolors39.default.red("serious ");
|
|
12277
|
+
if (severity === "medium") return import_picocolors39.default.yellow("worth fixing");
|
|
12278
|
+
return import_picocolors39.default.dim("minor ");
|
|
11985
12279
|
}
|
|
11986
12280
|
function git(cwd, args) {
|
|
11987
12281
|
try {
|
|
@@ -12042,7 +12336,7 @@ function listRepoFiles2(root, maxDepth = 8) {
|
|
|
12042
12336
|
}
|
|
12043
12337
|
|
|
12044
12338
|
// src/commands/health.ts
|
|
12045
|
-
var
|
|
12339
|
+
var import_picocolors40 = __toESM(require_picocolors(), 1);
|
|
12046
12340
|
function registerHealth(program3) {
|
|
12047
12341
|
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(
|
|
12048
12342
|
action(async ({ ctx, opts }) => {
|
|
@@ -12056,16 +12350,16 @@ function registerHealth(program3) {
|
|
|
12056
12350
|
}
|
|
12057
12351
|
function print3(res) {
|
|
12058
12352
|
if (!res?.checks?.length) {
|
|
12059
|
-
line(
|
|
12353
|
+
line(import_picocolors40.default.dim(res?.note ?? "Nothing to check."));
|
|
12060
12354
|
return;
|
|
12061
12355
|
}
|
|
12062
12356
|
for (const c of res.checks) {
|
|
12063
|
-
const mark = c.ok ?
|
|
12064
|
-
const timing =
|
|
12065
|
-
const detail = c.ok ? timing :
|
|
12066
|
-
line(` ${mark} ${c.appName} ${
|
|
12357
|
+
const mark = c.ok ? import_picocolors40.default.green("up ") : import_picocolors40.default.red("down");
|
|
12358
|
+
const timing = import_picocolors40.default.dim(`${c.ms}ms`);
|
|
12359
|
+
const detail = c.ok ? timing : import_picocolors40.default.dim(`${c.error ?? "no answer"}${c.failures > 1 ? ` \xB7 ${c.failures} in a row` : ""}`);
|
|
12360
|
+
line(` ${mark} ${c.appName} ${import_picocolors40.default.dim(`(${c.environment})`)} ${c.url} ${detail}`);
|
|
12067
12361
|
if (c.incidentOpened) {
|
|
12068
|
-
line(
|
|
12362
|
+
line(import_picocolors40.default.yellow(` An incident has been opened on the board for this.`));
|
|
12069
12363
|
}
|
|
12070
12364
|
}
|
|
12071
12365
|
const down = res.checks.filter((c) => !c.ok);
|
|
@@ -12078,14 +12372,14 @@ function print3(res) {
|
|
|
12078
12372
|
}
|
|
12079
12373
|
const production = down.filter((c) => c.environment === "production").length;
|
|
12080
12374
|
line(
|
|
12081
|
-
|
|
12375
|
+
import_picocolors40.default.red(
|
|
12082
12376
|
`${down.length} of ${res.checks.length} not answering` + (production ? ` \u2014 ${production} customer-facing.` : " (preview only).")
|
|
12083
12377
|
)
|
|
12084
12378
|
);
|
|
12085
12379
|
}
|
|
12086
12380
|
|
|
12087
12381
|
// src/commands/urls.ts
|
|
12088
|
-
var
|
|
12382
|
+
var import_picocolors41 = __toESM(require_picocolors(), 1);
|
|
12089
12383
|
function registerUrls(program3) {
|
|
12090
12384
|
program3.command("urls").description("The stable preview and production addresses of every app in this project").option("--app <webAppId>", "just one app").action(
|
|
12091
12385
|
action(async ({ ctx, opts }) => {
|
|
@@ -12099,20 +12393,20 @@ function registerUrls(program3) {
|
|
|
12099
12393
|
const summary = urlsSummary(rows);
|
|
12100
12394
|
ok({ rows, summary }, () => {
|
|
12101
12395
|
for (const row of rows) {
|
|
12102
|
-
const label =
|
|
12103
|
-
const value = row.url ?
|
|
12396
|
+
const label = import_picocolors41.default.dim(row.environment.padEnd(10));
|
|
12397
|
+
const value = row.url ? import_picocolors41.default.cyan(row.url) : import_picocolors41.default.dim(row.note ?? "not published");
|
|
12104
12398
|
line(` ${row.appName.padEnd(22)} ${label} ${value}`);
|
|
12105
12399
|
}
|
|
12106
12400
|
line("");
|
|
12107
12401
|
if (rows.some((r) => r.url)) success(summary);
|
|
12108
|
-
else line(
|
|
12402
|
+
else line(import_picocolors41.default.yellow(summary));
|
|
12109
12403
|
});
|
|
12110
12404
|
})
|
|
12111
12405
|
);
|
|
12112
12406
|
}
|
|
12113
12407
|
|
|
12114
12408
|
// src/commands/deployments.ts
|
|
12115
|
-
var
|
|
12409
|
+
var import_picocolors42 = __toESM(require_picocolors(), 1);
|
|
12116
12410
|
function registerDeployments(program3) {
|
|
12117
12411
|
const cmd = program3.command("deployments").description("Deployment history, and putting a build in front of customers");
|
|
12118
12412
|
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(
|
|
@@ -12130,7 +12424,7 @@ function registerDeployments(program3) {
|
|
|
12130
12424
|
ok(res, () => {
|
|
12131
12425
|
if (!items.length) {
|
|
12132
12426
|
return line(
|
|
12133
|
-
|
|
12427
|
+
import_picocolors42.default.dim(
|
|
12134
12428
|
environment ? `Nothing has been deployed to ${environment} yet.` : "Nothing has been deployed yet. `workser deploy` builds the first one."
|
|
12135
12429
|
)
|
|
12136
12430
|
);
|
|
@@ -12150,13 +12444,13 @@ function registerDeployments(program3) {
|
|
|
12150
12444
|
).catch(() => null) : null;
|
|
12151
12445
|
ok({ ...dep, logs }, () => {
|
|
12152
12446
|
line(formatDeployment(dep));
|
|
12153
|
-
if (dep?.error_message) line(
|
|
12447
|
+
if (dep?.error_message) line(import_picocolors42.default.red(` ${dep.error_message}`));
|
|
12154
12448
|
const events = logs?.events ?? [];
|
|
12155
12449
|
for (const e of events) {
|
|
12156
|
-
line(` ${
|
|
12450
|
+
line(` ${import_picocolors42.default.dim(String(e.type ?? "log"))} ${e.text ?? ""}`);
|
|
12157
12451
|
}
|
|
12158
12452
|
if (opts.logs && !events.length) {
|
|
12159
|
-
line(
|
|
12453
|
+
line(import_picocolors42.default.dim(" That build produced no output."));
|
|
12160
12454
|
}
|
|
12161
12455
|
});
|
|
12162
12456
|
})
|
|
@@ -12200,16 +12494,16 @@ function printPromoted(res, version) {
|
|
|
12200
12494
|
const what = version === null ? "the latest build" : `version ${version}`;
|
|
12201
12495
|
const url = res.url ?? res.vercel_url;
|
|
12202
12496
|
success(`Production is being rebuilt from ${what}.`);
|
|
12203
|
-
if (url) line(
|
|
12204
|
-
line(
|
|
12497
|
+
if (url) line(import_picocolors42.default.dim(`It will be at ${url}`));
|
|
12498
|
+
line(import_picocolors42.default.dim("`workser deploy status` follows it."));
|
|
12205
12499
|
}
|
|
12206
12500
|
function formatDeployment(d) {
|
|
12207
12501
|
if (!d) return "";
|
|
12208
|
-
const version = d.version !== void 0 ?
|
|
12209
|
-
const env =
|
|
12502
|
+
const version = d.version !== void 0 ? import_picocolors42.default.yellow(`v${d.version}`) : import_picocolors42.default.dim("v?");
|
|
12503
|
+
const env = import_picocolors42.default.dim((d.environment ?? "?").padEnd(10));
|
|
12210
12504
|
const app = d.webAppName ? `${d.webAppName} ` : "";
|
|
12211
|
-
const when =
|
|
12212
|
-
const url = d.url ? " " +
|
|
12505
|
+
const when = import_picocolors42.default.dim(formatTime2(d.created_at));
|
|
12506
|
+
const url = d.url ? " " + import_picocolors42.default.cyan(d.url) : "";
|
|
12213
12507
|
return `${version} ${env} ${colorStatus(d.status ?? "")} ${app}${when}${url}`;
|
|
12214
12508
|
}
|
|
12215
12509
|
function formatTime2(t) {
|
|
@@ -12219,7 +12513,7 @@ function formatTime2(t) {
|
|
|
12219
12513
|
}
|
|
12220
12514
|
|
|
12221
12515
|
// src/commands/usage.ts
|
|
12222
|
-
var
|
|
12516
|
+
var import_picocolors43 = __toESM(require_picocolors(), 1);
|
|
12223
12517
|
|
|
12224
12518
|
// src/usage.ts
|
|
12225
12519
|
var NEAR_LIMIT_FRACTION = 0.8;
|
|
@@ -12266,22 +12560,22 @@ function dimensionLine(d) {
|
|
|
12266
12560
|
}
|
|
12267
12561
|
return `${d.label}: ${used} of ${limit}`;
|
|
12268
12562
|
}
|
|
12269
|
-
function usageSummary(
|
|
12270
|
-
const dims =
|
|
12563
|
+
function usageSummary(report2) {
|
|
12564
|
+
const dims = report2.dimensions ?? [];
|
|
12271
12565
|
const unknown = dims.filter((d) => d.used === null);
|
|
12272
12566
|
const over = dims.filter((d) => usageState(d) === "over");
|
|
12273
12567
|
const near = dims.filter((d) => usageState(d) === "near");
|
|
12274
12568
|
const parts = [];
|
|
12275
12569
|
if (over.length) {
|
|
12276
12570
|
parts.push(
|
|
12277
|
-
`${over.length === 1 ? "One thing is" : `${over.length} things are`} over the ${
|
|
12571
|
+
`${over.length === 1 ? "One thing is" : `${over.length} things are`} over the ${report2.tier} plan's limit`
|
|
12278
12572
|
);
|
|
12279
12573
|
} else if (near.length) {
|
|
12280
12574
|
parts.push(
|
|
12281
|
-
`${near.length === 1 ? "One thing is" : `${near.length} things are`} close to the ${
|
|
12575
|
+
`${near.length === 1 ? "One thing is" : `${near.length} things are`} close to the ${report2.tier} plan's limit`
|
|
12282
12576
|
);
|
|
12283
12577
|
} else if (dims.some((d) => d.used !== null)) {
|
|
12284
|
-
parts.push(`Everything is comfortably inside the ${
|
|
12578
|
+
parts.push(`Everything is comfortably inside the ${report2.tier} plan`);
|
|
12285
12579
|
}
|
|
12286
12580
|
if (unknown.length) {
|
|
12287
12581
|
parts.push(
|
|
@@ -12291,8 +12585,8 @@ function usageSummary(report) {
|
|
|
12291
12585
|
if (!parts.length) return "Nothing could be measured.";
|
|
12292
12586
|
return `${parts.join("; ")}.`;
|
|
12293
12587
|
}
|
|
12294
|
-
function shouldFail(
|
|
12295
|
-
return (
|
|
12588
|
+
function shouldFail(report2) {
|
|
12589
|
+
return (report2.dimensions ?? []).some(
|
|
12296
12590
|
(d) => d.kind === "hard" && usageState(d) === "over"
|
|
12297
12591
|
);
|
|
12298
12592
|
}
|
|
@@ -12302,12 +12596,12 @@ function registerUsage(program3) {
|
|
|
12302
12596
|
const usage = program3.command("usage").description("What this project and your plan are using \u2014 storage, projects, apps").action(
|
|
12303
12597
|
action(async ({ ctx }) => {
|
|
12304
12598
|
const projectId = requireProject(ctx);
|
|
12305
|
-
const
|
|
12599
|
+
const report2 = await api(
|
|
12306
12600
|
ctx,
|
|
12307
12601
|
`/v1/projects/${projectId}/usage`
|
|
12308
12602
|
);
|
|
12309
|
-
ok(
|
|
12310
|
-
if (shouldFail(
|
|
12603
|
+
ok(report2, () => print4(report2));
|
|
12604
|
+
if (shouldFail(report2)) process.exitCode = 1;
|
|
12311
12605
|
})
|
|
12312
12606
|
);
|
|
12313
12607
|
usage.command("infra").description(
|
|
@@ -12332,15 +12626,15 @@ function printInfra(usage) {
|
|
|
12332
12626
|
];
|
|
12333
12627
|
const width = Math.max(...rows.map(([label]) => label.length));
|
|
12334
12628
|
for (const [label, dim, unit] of rows) {
|
|
12335
|
-
const value = dim.value === null ?
|
|
12336
|
-
const when = dim.live ?
|
|
12629
|
+
const value = dim.value === null ? import_picocolors43.default.dim("not measured") : `${dim.value}${unit ? ` ${unit}` : ""}`;
|
|
12630
|
+
const when = dim.live ? import_picocolors43.default.dim("now") : import_picocolors43.default.dim(`through ${shortDay(dim.asOf)}`);
|
|
12337
12631
|
line(` ${label.padEnd(width)} ${value} ${when}`);
|
|
12338
12632
|
}
|
|
12339
12633
|
const stale = rows.find(([, dim]) => !dim.live && dim.nextUpdate);
|
|
12340
12634
|
if (stale) {
|
|
12341
12635
|
line("");
|
|
12342
12636
|
line(
|
|
12343
|
-
|
|
12637
|
+
import_picocolors43.default.dim(
|
|
12344
12638
|
`Bandwidth is reported by the host in closed days, so it updates once a day \u2014 next around ${shortTime(
|
|
12345
12639
|
stale[1].nextUpdate
|
|
12346
12640
|
)}.`
|
|
@@ -12356,35 +12650,35 @@ function shortTime(iso) {
|
|
|
12356
12650
|
const d = new Date(iso);
|
|
12357
12651
|
return Number.isFinite(d.getTime()) ? `${d.toISOString().slice(11, 16)} UTC` : "\u2014";
|
|
12358
12652
|
}
|
|
12359
|
-
function print4(
|
|
12360
|
-
const dims =
|
|
12653
|
+
function print4(report2) {
|
|
12654
|
+
const dims = report2.dimensions ?? [];
|
|
12361
12655
|
if (!dims.length) {
|
|
12362
|
-
return line(
|
|
12656
|
+
return line(import_picocolors43.default.dim("Nothing to measure for this project yet."));
|
|
12363
12657
|
}
|
|
12364
12658
|
const width = Math.max(...dims.map((d) => d.label.length));
|
|
12365
12659
|
for (const d of dims) {
|
|
12366
12660
|
line(` ${colour(d)(dimensionLine(d).padEnd(0))}${gauge(d, width)}`);
|
|
12367
12661
|
}
|
|
12368
12662
|
line("");
|
|
12369
|
-
const summary = usageSummary(
|
|
12663
|
+
const summary = usageSummary(report2);
|
|
12370
12664
|
const worst = dims.map(usageState);
|
|
12371
|
-
if (worst.includes("over")) line(
|
|
12665
|
+
if (worst.includes("over")) line(import_picocolors43.default.red(summary));
|
|
12372
12666
|
else if (worst.includes("near") || worst.includes("unknown"))
|
|
12373
|
-
line(
|
|
12667
|
+
line(import_picocolors43.default.yellow(summary));
|
|
12374
12668
|
else success(summary);
|
|
12375
12669
|
}
|
|
12376
12670
|
function gauge(d, _labelWidth) {
|
|
12377
12671
|
const drawn = bar(d);
|
|
12378
|
-
return drawn ? ` ${
|
|
12672
|
+
return drawn ? ` ${import_picocolors43.default.dim(drawn)}` : "";
|
|
12379
12673
|
}
|
|
12380
12674
|
function colour(d) {
|
|
12381
12675
|
switch (usageState(d)) {
|
|
12382
12676
|
case "over":
|
|
12383
|
-
return d.kind === "hard" ?
|
|
12677
|
+
return d.kind === "hard" ? import_picocolors43.default.red : import_picocolors43.default.yellow;
|
|
12384
12678
|
case "near":
|
|
12385
|
-
return
|
|
12679
|
+
return import_picocolors43.default.yellow;
|
|
12386
12680
|
case "unknown":
|
|
12387
|
-
return
|
|
12681
|
+
return import_picocolors43.default.dim;
|
|
12388
12682
|
default:
|
|
12389
12683
|
return (s) => s;
|
|
12390
12684
|
}
|
|
@@ -12392,7 +12686,7 @@ function colour(d) {
|
|
|
12392
12686
|
|
|
12393
12687
|
// src/index.ts
|
|
12394
12688
|
var pkg = {
|
|
12395
|
-
version: true ? "0.6.
|
|
12689
|
+
version: true ? "0.6.28" : "0.0.0-dev"
|
|
12396
12690
|
};
|
|
12397
12691
|
var program2 = new Command();
|
|
12398
12692
|
program2.name("workser").description(
|
|
@@ -12438,6 +12732,7 @@ registerCheckpoint(program2);
|
|
|
12438
12732
|
registerSync(program2);
|
|
12439
12733
|
registerWorkflow(program2);
|
|
12440
12734
|
registerConnection(program2);
|
|
12735
|
+
registerLine(program2);
|
|
12441
12736
|
registerTool(program2);
|
|
12442
12737
|
registerMemory(program2);
|
|
12443
12738
|
registerNote(program2);
|