@workser/cli 0.6.7 → 0.6.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +17 -6
- package/dist/index.js +590 -314
- package/package.json +1 -1
- package/skills/workser/SKILL.md +5 -6
- package/skills/workser/reference/key.md +40 -0
- package/skills/workser/reference/sdlc-entities.md +11 -0
package/dist/index.js
CHANGED
|
@@ -4636,6 +4636,47 @@ workser audio understand "transcribe this" --file ./voicemail.m4a -t transcribe
|
|
|
4636
4636
|
- **This is billed to the project's organization**, same as image generation \u2014 it's
|
|
4637
4637
|
a real provider call, not free introspection. Don't loop it over every file in a
|
|
4638
4638
|
folder "just in case"; use it when you actually need to know what's in one.
|
|
4639
|
+
`
|
|
4640
|
+
},
|
|
4641
|
+
{
|
|
4642
|
+
topic: "key",
|
|
4643
|
+
title: "Managed keys \u2014 list and rotate this app's Workser-issued credentials",
|
|
4644
|
+
summary: "See this app's AI Gateway and auth keys (redacted), and rotate one without opening Orbit.",
|
|
4645
|
+
commands: ["key"],
|
|
4646
|
+
source: "skills/workser/reference/key.md",
|
|
4647
|
+
body: `# Managed keys \u2014 list and rotate this app's Workser-issued credentials
|
|
4648
|
+
|
|
4649
|
+
\`\`\`
|
|
4650
|
+
workser key list [--app <webAppId>]
|
|
4651
|
+
workser key rotate <key> [--app <webAppId>] [--env production|preview]
|
|
4652
|
+
\`\`\`
|
|
4653
|
+
|
|
4654
|
+
App-scoped, not project-scoped: run from the app's own folder and \`--app\` is
|
|
4655
|
+
picked up automatically; from anywhere else, pass \`--app <webAppId>\` \u2014 a
|
|
4656
|
+
mistake here is the wrong app's key, so there is no "primary app" default the
|
|
4657
|
+
way \`env\` has one.
|
|
4658
|
+
|
|
4659
|
+
## What's rotatable
|
|
4660
|
+
|
|
4661
|
+
Only credentials with a real rotation handler:
|
|
4662
|
+
|
|
4663
|
+
- \`AI_GATEWAY_API_KEY\` \u2014 the deployed agent's key into the Workser AI
|
|
4664
|
+
Gateway. Split by environment (\`--env production\` or \`--env preview\`
|
|
4665
|
+
required), so rotating one never touches the other.
|
|
4666
|
+
- \`BETTER_AUTH_SECRET\` \u2014 a single value, no \`--env\` needed.
|
|
4667
|
+
|
|
4668
|
+
Every other Workser-managed value (\`DATABASE_URL\`, the internal service
|
|
4669
|
+
keys) has no rotation handler yet \u2014 each belongs to a different subsystem
|
|
4670
|
+
with its own cutover semantics, and \`key rotate\` refuses rather than fake
|
|
4671
|
+
one.
|
|
4672
|
+
|
|
4673
|
+
## After rotating
|
|
4674
|
+
|
|
4675
|
+
The old value stops authorizing immediately, server-side. An already-running
|
|
4676
|
+
deployment keeps using whatever it was built with until it's redeployed \u2014
|
|
4677
|
+
run \`workser deploy\` (\`--prod\` for the production key) to pick up the new
|
|
4678
|
+
value. \`key rotate\` prints the new secret exactly once; it is never shown
|
|
4679
|
+
again or stored anywhere in the clear.
|
|
4639
4680
|
`
|
|
4640
4681
|
},
|
|
4641
4682
|
{
|
|
@@ -4865,6 +4906,17 @@ workser doc create "Checkout \u2014 implementation plan" --markdown "$(cat plan.
|
|
|
4865
4906
|
workser decision create "Carts live server-side" --context "\u2026" --decision "\u2026" --json
|
|
4866
4907
|
\`\`\`
|
|
4867
4908
|
|
|
4909
|
+
**A wrong row is edited, not replaced.** If a subtask's title, teammate, note or
|
|
4910
|
+
scope is wrong after you created it, fix that same row:
|
|
4911
|
+
|
|
4912
|
+
\`\`\`bash
|
|
4913
|
+
workser task subtask update <id> --title "\u2026" --role api --note "\u2026" --scope "src/api"
|
|
4914
|
+
\`\`\`
|
|
4915
|
+
|
|
4916
|
+
Never tell the user a subtask is locked, and never file a second one alongside
|
|
4917
|
+
the wrong one \u2014 a plan with a duplicate phase in it is a plan nobody can read
|
|
4918
|
+
the progress of.
|
|
4919
|
+
|
|
4868
4920
|
**Don't pass \`--work-item\` for a multi-phase plan.** A linked document renders on
|
|
4869
4921
|
its card and is *hidden* from the Docs panel; a plan spanning three phases
|
|
4870
4922
|
belongs to the project, not to phase 1.
|
|
@@ -5511,6 +5563,10 @@ function requireProject(ctx) {
|
|
|
5511
5563
|
}
|
|
5512
5564
|
return ctx.projectId;
|
|
5513
5565
|
}
|
|
5566
|
+
function appTarget(ctx, explicit) {
|
|
5567
|
+
const said = typeof explicit === "string" ? explicit.trim() : "";
|
|
5568
|
+
return said || ctx.appId || void 0;
|
|
5569
|
+
}
|
|
5514
5570
|
|
|
5515
5571
|
// src/run.ts
|
|
5516
5572
|
function action(fn) {
|
|
@@ -6791,8 +6847,71 @@ function formatEnvValue(value) {
|
|
|
6791
6847
|
return /[\s"'#]/.test(value) ? JSON.stringify(value) : value;
|
|
6792
6848
|
}
|
|
6793
6849
|
|
|
6794
|
-
// src/commands/
|
|
6850
|
+
// src/commands/key.ts
|
|
6795
6851
|
var import_picocolors10 = __toESM(require_picocolors(), 1);
|
|
6852
|
+
function requireApp(ctx, explicit) {
|
|
6853
|
+
const appId = appTarget(ctx, explicit);
|
|
6854
|
+
if (!appId) {
|
|
6855
|
+
throw new WorkserError(
|
|
6856
|
+
"No app to target.\n\n \u2022 Run this from the app's own folder (its ID is picked up automatically), or\n \u2022 pass --app <webAppId> \u2014 `workser project show` lists an app's ID.",
|
|
6857
|
+
{ code: "no_app" }
|
|
6858
|
+
);
|
|
6859
|
+
}
|
|
6860
|
+
return appId;
|
|
6861
|
+
}
|
|
6862
|
+
function registerKey(program3) {
|
|
6863
|
+
const key = program3.command("key").description("Manage this app's Workser-issued credentials (AI Gateway, auth secret)");
|
|
6864
|
+
key.command("list").description("List this app's managed keys (redacted \u2014 never the secret)").option("--app <webAppId>", "Which app (default: the one this folder is linked to)").action(
|
|
6865
|
+
action(async ({ ctx, opts }) => {
|
|
6866
|
+
const appId = requireApp(ctx, opts.app);
|
|
6867
|
+
const items = await api(ctx, `/v1/apps/${appId}/keys`);
|
|
6868
|
+
ok(items, () => {
|
|
6869
|
+
if (!items?.length) {
|
|
6870
|
+
return line(import_picocolors10.default.dim("No managed keys yet \u2014 they're created the first time this app deploys."));
|
|
6871
|
+
}
|
|
6872
|
+
for (const item of items) {
|
|
6873
|
+
const lastUsed = item.last_used_at ? `last used ${item.last_used_at}` : "never used yet";
|
|
6874
|
+
line(`${import_picocolors10.default.bold(item.environment)} ${item.prefix}\u2026 ${import_picocolors10.default.dim(`(${lastUsed})`)}`);
|
|
6875
|
+
}
|
|
6876
|
+
});
|
|
6877
|
+
})
|
|
6878
|
+
);
|
|
6879
|
+
key.command("rotate <key>").description("Rotate a managed key (AI_GATEWAY_API_KEY, BETTER_AUTH_SECRET)").option("--app <webAppId>", "Which app (default: the one this folder is linked to)").option("--env <environment>", "production or preview \u2014 required for AI_GATEWAY_API_KEY").action(
|
|
6880
|
+
action(async ({ ctx, args, opts }) => {
|
|
6881
|
+
const appId = requireApp(ctx, opts.app);
|
|
6882
|
+
const keyName = args[0];
|
|
6883
|
+
const environment = typeof opts.env === "string" ? opts.env : void 0;
|
|
6884
|
+
if (environment && environment !== "production" && environment !== "preview") {
|
|
6885
|
+
throw new WorkserError(
|
|
6886
|
+
`--env must be "production" or "preview", got "${environment}".`,
|
|
6887
|
+
{ code: "bad_input" }
|
|
6888
|
+
);
|
|
6889
|
+
}
|
|
6890
|
+
const res = await api(
|
|
6891
|
+
ctx,
|
|
6892
|
+
`/v1/apps/${appId}/keys/${encodeURIComponent(keyName)}/rotate`,
|
|
6893
|
+
{ body: { environment } }
|
|
6894
|
+
);
|
|
6895
|
+
ok(res, () => {
|
|
6896
|
+
success(`Rotated ${import_picocolors10.default.bold(keyName)}${res?.environment ? ` (${res.environment})` : ""}.`);
|
|
6897
|
+
if (res?.key) {
|
|
6898
|
+
line("");
|
|
6899
|
+
line(import_picocolors10.default.bold("New value \u2014 shown once, not stored anywhere in the clear:"));
|
|
6900
|
+
line(import_picocolors10.default.yellow(res.key));
|
|
6901
|
+
}
|
|
6902
|
+
line("");
|
|
6903
|
+
line(
|
|
6904
|
+
import_picocolors10.default.dim(
|
|
6905
|
+
"The old value stopped working immediately. If this app is already deployed, redeploy so it picks up the new one: workser deploy" + (res?.environment === "production" ? " --prod" : "")
|
|
6906
|
+
)
|
|
6907
|
+
);
|
|
6908
|
+
});
|
|
6909
|
+
})
|
|
6910
|
+
);
|
|
6911
|
+
}
|
|
6912
|
+
|
|
6913
|
+
// src/commands/deploy.ts
|
|
6914
|
+
var import_picocolors11 = __toESM(require_picocolors(), 1);
|
|
6796
6915
|
var TERMINAL = /* @__PURE__ */ new Set(["ready", "live", "success", "error", "failed", "canceled"]);
|
|
6797
6916
|
function registerDeploy(program3) {
|
|
6798
6917
|
const deploy = program3.command("deploy").description("Deploy the current project to Workser (git \u2192 Vercel) and return a live URL").option("--prod", "deploy to production (same as --env production)", false).option(
|
|
@@ -6843,7 +6962,7 @@ async function watchDeploy(ctx, id) {
|
|
|
6843
6962
|
for (; ; ) {
|
|
6844
6963
|
const dep = await api(ctx, `/v1/deployments/${encodeURIComponent(id)}`);
|
|
6845
6964
|
if (!isJson() && dep.status !== last) {
|
|
6846
|
-
line(` ${colorStatus(dep.status)}${dep.url ? " " +
|
|
6965
|
+
line(` ${colorStatus(dep.status)}${dep.url ? " " + import_picocolors11.default.cyan(dep.url) : ""}`);
|
|
6847
6966
|
last = dep.status;
|
|
6848
6967
|
}
|
|
6849
6968
|
if (TERMINAL.has(String(dep.status).toLowerCase())) return dep;
|
|
@@ -6853,12 +6972,12 @@ async function watchDeploy(ctx, id) {
|
|
|
6853
6972
|
function printDeploy(dep) {
|
|
6854
6973
|
if (!dep) return;
|
|
6855
6974
|
const ready = ["ready", "live", "success"].includes(String(dep.status).toLowerCase());
|
|
6856
|
-
if (ready && dep.url) success(`Live at ${
|
|
6857
|
-
else line(`deploy ${colorStatus(dep.status)} ${
|
|
6975
|
+
if (ready && dep.url) success(`Live at ${import_picocolors11.default.cyan(dep.url)}`);
|
|
6976
|
+
else line(`deploy ${colorStatus(dep.status)} ${import_picocolors11.default.dim(`(${dep.id ?? "?"})`)}${dep.url ? " " + dep.url : ""}`);
|
|
6858
6977
|
}
|
|
6859
6978
|
|
|
6860
6979
|
// src/commands/versions.ts
|
|
6861
|
-
var
|
|
6980
|
+
var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
6862
6981
|
function registerVersions(program3) {
|
|
6863
6982
|
program3.command("versions").description("List the Workser-managed versions of the project (deploy history)").option("--app <webAppId>", "which app (defaults to the primary app)").option(
|
|
6864
6983
|
"--env <environment>",
|
|
@@ -6877,7 +6996,7 @@ function registerVersions(program3) {
|
|
|
6877
6996
|
}
|
|
6878
6997
|
});
|
|
6879
6998
|
ok(items, () => {
|
|
6880
|
-
if (!items?.length) return line(
|
|
6999
|
+
if (!items?.length) return line(import_picocolors12.default.dim("No versions yet. `workser deploy` to create one."));
|
|
6881
7000
|
for (const v of items) {
|
|
6882
7001
|
line(formatVersion(v));
|
|
6883
7002
|
}
|
|
@@ -6886,11 +7005,11 @@ function registerVersions(program3) {
|
|
|
6886
7005
|
);
|
|
6887
7006
|
}
|
|
6888
7007
|
function formatVersion(v) {
|
|
6889
|
-
const ref =
|
|
6890
|
-
const when =
|
|
6891
|
-
const msg = (v.message ?? "").trim() ||
|
|
6892
|
-
const badge = v.deployed ? " " +
|
|
6893
|
-
const url = v.url ? " " +
|
|
7008
|
+
const ref = import_picocolors12.default.yellow(shortRef(v.ref));
|
|
7009
|
+
const when = import_picocolors12.default.dim(formatTime(v.createdAt));
|
|
7010
|
+
const msg = (v.message ?? "").trim() || import_picocolors12.default.dim("(no message)");
|
|
7011
|
+
const badge = v.deployed ? " " + import_picocolors12.default.green(v.deployedEnvironment ? `live in ${v.deployedEnvironment}` : "deployed") : "";
|
|
7012
|
+
const url = v.url ? " " + import_picocolors12.default.cyan(v.url) : "";
|
|
6894
7013
|
return `${ref} ${when} ${msg}${badge}${url}`;
|
|
6895
7014
|
}
|
|
6896
7015
|
function shortRef(ref) {
|
|
@@ -6904,7 +7023,7 @@ function formatTime(t) {
|
|
|
6904
7023
|
}
|
|
6905
7024
|
|
|
6906
7025
|
// src/commands/logs.ts
|
|
6907
|
-
var
|
|
7026
|
+
var import_picocolors13 = __toESM(require_picocolors(), 1);
|
|
6908
7027
|
function registerLogs(program3) {
|
|
6909
7028
|
program3.command("logs").description("Show the build logs of the latest deployment").option("-n, --lines <n>", "number of lines", "100").option("-f, --follow", "keep streaming new logs", false).option("--app <webAppId>", "which app (defaults to the primary app)").option("--env <environment>", "preview or production (default: whichever deployed last)").action(
|
|
6910
7029
|
action(async ({ ctx, opts }) => {
|
|
@@ -6938,10 +7057,10 @@ function registerLogs(program3) {
|
|
|
6938
7057
|
function print(res) {
|
|
6939
7058
|
const entries = res?.entries ?? [];
|
|
6940
7059
|
for (const e of entries) line(formatLog(e));
|
|
6941
|
-
if (!entries.length && res?.note) line(
|
|
7060
|
+
if (!entries.length && res?.note) line(import_picocolors13.default.dim(res.note));
|
|
6942
7061
|
if (entries.length && res?.deploymentId) {
|
|
6943
7062
|
const where = res.environment ? ` (${res.environment})` : "";
|
|
6944
|
-
line(
|
|
7063
|
+
line(import_picocolors13.default.dim(`\u2014 build ${res.deploymentId}${where}`));
|
|
6945
7064
|
}
|
|
6946
7065
|
}
|
|
6947
7066
|
function formatLog(e) {
|
|
@@ -6950,7 +7069,7 @@ function formatLog(e) {
|
|
|
6950
7069
|
}
|
|
6951
7070
|
|
|
6952
7071
|
// src/commands/domain.ts
|
|
6953
|
-
var
|
|
7072
|
+
var import_picocolors14 = __toESM(require_picocolors(), 1);
|
|
6954
7073
|
|
|
6955
7074
|
// src/reserved-domains.ts
|
|
6956
7075
|
var RESERVED_APEX = [
|
|
@@ -7013,9 +7132,9 @@ function registerDomain(program3) {
|
|
|
7013
7132
|
{ method: "POST", body: { domain: host } }
|
|
7014
7133
|
);
|
|
7015
7134
|
ok(result, () => {
|
|
7016
|
-
line(`${
|
|
7135
|
+
line(`${import_picocolors14.default.green("Attached")} ${host}`);
|
|
7017
7136
|
line(
|
|
7018
|
-
|
|
7137
|
+
import_picocolors14.default.dim(
|
|
7019
7138
|
"It goes live once DNS points at us. Run `workser domain list` to see its status."
|
|
7020
7139
|
)
|
|
7021
7140
|
);
|
|
@@ -7031,7 +7150,7 @@ function registerDomain(program3) {
|
|
|
7031
7150
|
opts.app ? `/v1/projects/${projectId}/web-apps/${opts.app}/domains/${encodeURIComponent(host)}` : `/v1/projects/${projectId}/domains/${encodeURIComponent(host)}`,
|
|
7032
7151
|
{ method: "DELETE" }
|
|
7033
7152
|
);
|
|
7034
|
-
ok(result, () => line(`${
|
|
7153
|
+
ok(result, () => line(`${import_picocolors14.default.yellow("Detached")} ${host}`));
|
|
7035
7154
|
})
|
|
7036
7155
|
);
|
|
7037
7156
|
domain.command("list").description("List domains attached to the project").action(
|
|
@@ -7039,8 +7158,8 @@ function registerDomain(program3) {
|
|
|
7039
7158
|
const projectId = requireProject(ctx);
|
|
7040
7159
|
const items = await api(ctx, `/v1/projects/${projectId}/domains`);
|
|
7041
7160
|
ok(items, () => {
|
|
7042
|
-
if (!items?.length) return line(
|
|
7043
|
-
for (const d of items) line(`${d.domain}${
|
|
7161
|
+
if (!items?.length) return line(import_picocolors14.default.dim("No custom domains."));
|
|
7162
|
+
for (const d of items) line(`${d.domain}${import_picocolors14.default.dim(" " + (d.status ?? ""))}`);
|
|
7044
7163
|
});
|
|
7045
7164
|
})
|
|
7046
7165
|
);
|
|
@@ -7072,7 +7191,7 @@ function openUrl(url) {
|
|
|
7072
7191
|
}
|
|
7073
7192
|
|
|
7074
7193
|
// src/commands/doctor.ts
|
|
7075
|
-
var
|
|
7194
|
+
var import_picocolors15 = __toESM(require_picocolors(), 1);
|
|
7076
7195
|
import { spawnSync } from "child_process";
|
|
7077
7196
|
function registerDoctor(program3) {
|
|
7078
7197
|
program3.command("doctor").description("Print the resolved endpoint, mode, token presence (masked), and current project").action(
|
|
@@ -7106,29 +7225,29 @@ function registerDoctor(program3) {
|
|
|
7106
7225
|
workspace: session.workspaceName ?? null
|
|
7107
7226
|
};
|
|
7108
7227
|
ok(report, () => {
|
|
7109
|
-
line(
|
|
7110
|
-
line(` endpoint: ${ctx.endpoint} ${
|
|
7228
|
+
line(import_picocolors15.default.bold("workser doctor"));
|
|
7229
|
+
line(` endpoint: ${ctx.endpoint} ${import_picocolors15.default.dim(`(${endpointSource})`)}`);
|
|
7111
7230
|
line(
|
|
7112
|
-
` env: ${env === "prod" ?
|
|
7231
|
+
` env: ${env === "prod" ? import_picocolors15.default.yellow(env) : env}` + import_picocolors15.default.dim(process.env.WORKSER_ENV ? " ($WORKSER_ENV)" : " (default)")
|
|
7113
7232
|
);
|
|
7114
7233
|
line(` mode: ${ctx.mode}`);
|
|
7115
7234
|
line(
|
|
7116
|
-
` token: ${ctx.token ? `${maskToken(ctx.token)} ${
|
|
7235
|
+
` token: ${ctx.token ? `${maskToken(ctx.token)} ${import_picocolors15.default.dim(`(${tokenSource})`)}` : import_picocolors15.default.yellow("none \u2014 run `workser login`")}`
|
|
7117
7236
|
);
|
|
7118
7237
|
line(
|
|
7119
|
-
` project: ${ctx.projectId ??
|
|
7238
|
+
` project: ${ctx.projectId ?? import_picocolors15.default.dim("none")}` + (link?.name ? ` ${import_picocolors15.default.dim(`(${link.name})`)}` : "") + (projectSource ? import_picocolors15.default.dim(` [${projectSource}]`) : "")
|
|
7120
7239
|
);
|
|
7121
7240
|
line(` cwd: ${ctx.cwd}`);
|
|
7122
|
-
line(` git: ${git2 ??
|
|
7241
|
+
line(` git: ${git2 ?? import_picocolors15.default.dim("not on this shell's PATH")}`);
|
|
7123
7242
|
if (!git2) {
|
|
7124
7243
|
line("");
|
|
7125
7244
|
line(
|
|
7126
|
-
|
|
7245
|
+
import_picocolors15.default.dim(
|
|
7127
7246
|
" Workser brings its own git, so syncing and publishing still work."
|
|
7128
7247
|
)
|
|
7129
7248
|
);
|
|
7130
7249
|
line(
|
|
7131
|
-
|
|
7250
|
+
import_picocolors15.default.dim(
|
|
7132
7251
|
` Only needed if you want to run git yourself here. ${GIT_INSTALL_HINT}`
|
|
7133
7252
|
)
|
|
7134
7253
|
);
|
|
@@ -7136,16 +7255,16 @@ function registerDoctor(program3) {
|
|
|
7136
7255
|
if (envIgnored) {
|
|
7137
7256
|
line("");
|
|
7138
7257
|
line(
|
|
7139
|
-
|
|
7258
|
+
import_picocolors15.default.yellow(
|
|
7140
7259
|
` WORKSER_ENV=${env} is not in effect \u2014 ${endpointSource} wins.`
|
|
7141
7260
|
)
|
|
7142
7261
|
);
|
|
7143
7262
|
line(
|
|
7144
|
-
|
|
7263
|
+
import_picocolors15.default.dim(
|
|
7145
7264
|
` Re-run \`workser login\` to switch (the saved token is tied to ${ctx.endpoint}),`
|
|
7146
7265
|
)
|
|
7147
7266
|
);
|
|
7148
|
-
line(
|
|
7267
|
+
line(import_picocolors15.default.dim(` or pass --endpoint ${ENV_BASE_URLS[env]}.`));
|
|
7149
7268
|
}
|
|
7150
7269
|
});
|
|
7151
7270
|
})
|
|
@@ -7175,7 +7294,32 @@ function maskToken(token) {
|
|
|
7175
7294
|
}
|
|
7176
7295
|
|
|
7177
7296
|
// src/commands/agent.ts
|
|
7178
|
-
var
|
|
7297
|
+
var import_picocolors16 = __toESM(require_picocolors(), 1);
|
|
7298
|
+
|
|
7299
|
+
// src/model-policy.ts
|
|
7300
|
+
var DELEGATION_BLOCKED_MODELS = [
|
|
7301
|
+
{
|
|
7302
|
+
match: "fable",
|
|
7303
|
+
label: "Claude Fable 5",
|
|
7304
|
+
reason: "it is the most expensive model available and no delegated run is worth it \u2014 ask the owner if you think this one is"
|
|
7305
|
+
}
|
|
7306
|
+
];
|
|
7307
|
+
function blockedDelegationModel(model) {
|
|
7308
|
+
const value = (model ?? "").trim().toLowerCase();
|
|
7309
|
+
if (!value) return null;
|
|
7310
|
+
return DELEGATION_BLOCKED_MODELS.find((entry) => value.includes(entry.match)) ?? null;
|
|
7311
|
+
}
|
|
7312
|
+
function assertDelegatableModel(flag, model) {
|
|
7313
|
+
const blocked = blockedDelegationModel(model);
|
|
7314
|
+
if (!blocked || !model) return;
|
|
7315
|
+
throw new WorkserError(
|
|
7316
|
+
`${flag} "${model}" can't be chosen for a delegated run: ${blocked.reason}.
|
|
7317
|
+
Pick another model, or leave ${flag} off to use the agent's own default.`,
|
|
7318
|
+
{ code: "bad_request" }
|
|
7319
|
+
);
|
|
7320
|
+
}
|
|
7321
|
+
|
|
7322
|
+
// src/commands/agent.ts
|
|
7179
7323
|
var SPAWNABLE_AGENTS = ["claude_code", "codex", "kimi", "opencode", "grok"];
|
|
7180
7324
|
function registerAgent(program3) {
|
|
7181
7325
|
const agent = program3.command("agent").description("Delegate focused subtasks to your configured agent roles (each runs isolated)");
|
|
@@ -7183,20 +7327,20 @@ function registerAgent(program3) {
|
|
|
7183
7327
|
action(async ({ ctx }) => {
|
|
7184
7328
|
const cfg = await api(ctx, "/v1/agents");
|
|
7185
7329
|
ok(cfg, () => {
|
|
7186
|
-
line(
|
|
7187
|
-
line(
|
|
7330
|
+
line(import_picocolors16.default.bold("main agent:") + " " + (cfg?.mainAgent ?? import_picocolors16.default.dim("none")));
|
|
7331
|
+
line(import_picocolors16.default.bold("backup agent:") + " " + (cfg?.backupAgent ?? import_picocolors16.default.dim("none")));
|
|
7188
7332
|
if (cfg?.effectiveMainAgent && cfg.effectiveMainAgent !== cfg.mainAgent) {
|
|
7189
7333
|
line(
|
|
7190
|
-
|
|
7334
|
+
import_picocolors16.default.yellow(
|
|
7191
7335
|
` \u2937 failover active: runs use ${cfg.effectiveMainAgent} (main not available)`
|
|
7192
7336
|
)
|
|
7193
7337
|
);
|
|
7194
7338
|
}
|
|
7195
7339
|
const roles = cfg?.roles ?? [];
|
|
7196
7340
|
if (!roles.length) {
|
|
7197
|
-
line(
|
|
7341
|
+
line(import_picocolors16.default.dim("No subagents configured. Add them in the Workser Orbit Agents screen."));
|
|
7198
7342
|
} else {
|
|
7199
|
-
line(
|
|
7343
|
+
line(import_picocolors16.default.bold("subagents:"));
|
|
7200
7344
|
for (const r of roles) line(" " + formatRole(r));
|
|
7201
7345
|
}
|
|
7202
7346
|
const detected = cfg?.detected ?? [];
|
|
@@ -7204,7 +7348,7 @@ function registerAgent(program3) {
|
|
|
7204
7348
|
(d) => d?.installed && d?.authed !== false
|
|
7205
7349
|
);
|
|
7206
7350
|
line(
|
|
7207
|
-
|
|
7351
|
+
import_picocolors16.default.bold("spawnable (workser agent spawn <agent>):") + " " + (spawnable.length ? spawnable.map((d) => toContractId(d.id)).join(", ") : import_picocolors16.default.dim("none connected"))
|
|
7208
7352
|
);
|
|
7209
7353
|
});
|
|
7210
7354
|
})
|
|
@@ -7218,8 +7362,8 @@ function registerAgent(program3) {
|
|
|
7218
7362
|
backupAgent: cfg?.backupAgent ?? null
|
|
7219
7363
|
},
|
|
7220
7364
|
() => {
|
|
7221
|
-
line(
|
|
7222
|
-
line(
|
|
7365
|
+
line(import_picocolors16.default.bold("main agent:") + " " + (cfg?.mainAgent ?? import_picocolors16.default.dim("none")));
|
|
7366
|
+
line(import_picocolors16.default.bold("backup agent:") + " " + (cfg?.backupAgent ?? import_picocolors16.default.dim("none")));
|
|
7223
7367
|
}
|
|
7224
7368
|
);
|
|
7225
7369
|
})
|
|
@@ -7251,6 +7395,7 @@ function registerAgent(program3) {
|
|
|
7251
7395
|
action(async ({ ctx, args, opts }) => {
|
|
7252
7396
|
const spawnAgent = args[0];
|
|
7253
7397
|
const task = args[1].join(" ");
|
|
7398
|
+
assertDelegatableModel("--model", opts.model);
|
|
7254
7399
|
const res = await api(ctx, "/v1/agents/run", {
|
|
7255
7400
|
body: {
|
|
7256
7401
|
agent: spawnAgent,
|
|
@@ -7279,21 +7424,21 @@ function toContractId(id) {
|
|
|
7279
7424
|
return id === "claude" ? "claude_code" : id;
|
|
7280
7425
|
}
|
|
7281
7426
|
function formatRole(r) {
|
|
7282
|
-
const label =
|
|
7283
|
-
const agent =
|
|
7284
|
-
const enabled = r.enabled === false ?
|
|
7427
|
+
const label = import_picocolors16.default.yellow(r.role);
|
|
7428
|
+
const agent = import_picocolors16.default.dim("\xB7 " + (r.agent ?? "?"));
|
|
7429
|
+
const enabled = r.enabled === false ? import_picocolors16.default.red("disabled") : import_picocolors16.default.green("enabled");
|
|
7285
7430
|
const runnable = r.installed && r.authed !== false;
|
|
7286
|
-
const ready = runnable ?
|
|
7431
|
+
const ready = runnable ? import_picocolors16.default.green("runnable") : import_picocolors16.default.dim("not runnable");
|
|
7287
7432
|
const extras = [];
|
|
7288
7433
|
if (r.model) extras.push(`model ${r.model}`);
|
|
7289
7434
|
if (Array.isArray(r.apps) && r.apps.length) extras.push(`apps: ${r.apps.join(",")}`);
|
|
7290
7435
|
if (Array.isArray(r.mcp) && r.mcp.length) extras.push(`mcp: ${r.mcp.length}`);
|
|
7291
|
-
const tail = extras.length ? " " +
|
|
7436
|
+
const tail = extras.length ? " " + import_picocolors16.default.dim(extras.join(" \xB7 ")) : "";
|
|
7292
7437
|
return `${label} ${agent} ${enabled} ${ready}${tail}`;
|
|
7293
7438
|
}
|
|
7294
7439
|
|
|
7295
7440
|
// src/commands/verify.ts
|
|
7296
|
-
var
|
|
7441
|
+
var import_picocolors17 = __toESM(require_picocolors(), 1);
|
|
7297
7442
|
function registerVerify(program3) {
|
|
7298
7443
|
program3.command("verify").description(
|
|
7299
7444
|
"Run the project's checks (typecheck/lint/build) \u2014 use before declaring a task done"
|
|
@@ -7315,23 +7460,23 @@ function registerVerify(program3) {
|
|
|
7315
7460
|
function printVerify(res) {
|
|
7316
7461
|
if (!res) return;
|
|
7317
7462
|
if (!res.checks?.length) {
|
|
7318
|
-
line(
|
|
7463
|
+
line(import_picocolors17.default.dim(res.note ?? "No checks detected."));
|
|
7319
7464
|
return;
|
|
7320
7465
|
}
|
|
7321
7466
|
for (const c of res.checks) {
|
|
7322
7467
|
line(
|
|
7323
|
-
` ${c.ok ?
|
|
7468
|
+
` ${c.ok ? import_picocolors17.default.green("\u2713") : import_picocolors17.default.red("\u2717")} ${c.name}${c.ok ? "" : import_picocolors17.default.dim(` (exit ${c.exitCode})`)}`
|
|
7324
7469
|
);
|
|
7325
7470
|
}
|
|
7326
7471
|
if (res.ok) success("All checks passed");
|
|
7327
7472
|
else
|
|
7328
7473
|
line(
|
|
7329
|
-
|
|
7474
|
+
import_picocolors17.default.red("Some checks failed \u2014 fix the errors above and re-run ") + import_picocolors17.default.bold("workser verify") + import_picocolors17.default.red(".")
|
|
7330
7475
|
);
|
|
7331
7476
|
}
|
|
7332
7477
|
|
|
7333
7478
|
// src/commands/checkpoint.ts
|
|
7334
|
-
var
|
|
7479
|
+
var import_picocolors18 = __toESM(require_picocolors(), 1);
|
|
7335
7480
|
function registerCheckpoint(program3) {
|
|
7336
7481
|
program3.command("checkpoint [label]").description(
|
|
7337
7482
|
"Save the current state of this folder so you can come back to it"
|
|
@@ -7348,8 +7493,8 @@ function registerCheckpoint(program3) {
|
|
|
7348
7493
|
ok(res, () => {
|
|
7349
7494
|
const p = res?.point;
|
|
7350
7495
|
success(`Saved a checkpoint${p?.label ? `: ${p.label}` : ""}`);
|
|
7351
|
-
if (p?.ref) line(
|
|
7352
|
-
line(
|
|
7496
|
+
if (p?.ref) line(import_picocolors18.default.dim(` ${p.ref.slice(0, 7)}`));
|
|
7497
|
+
line(import_picocolors18.default.dim(" Come back to it with `workser restore`."));
|
|
7353
7498
|
});
|
|
7354
7499
|
})
|
|
7355
7500
|
);
|
|
@@ -7375,12 +7520,12 @@ function registerCheckpoint(program3) {
|
|
|
7375
7520
|
);
|
|
7376
7521
|
if (res?.filesChanged) {
|
|
7377
7522
|
line(
|
|
7378
|
-
|
|
7523
|
+
import_picocolors18.default.dim(
|
|
7379
7524
|
` ${res.filesChanged} file${res.filesChanged === 1 ? "" : "s"} changed`
|
|
7380
7525
|
)
|
|
7381
7526
|
);
|
|
7382
7527
|
}
|
|
7383
|
-
line(
|
|
7528
|
+
line(import_picocolors18.default.dim(" This is reversible: `workser restore` again."));
|
|
7384
7529
|
});
|
|
7385
7530
|
})
|
|
7386
7531
|
);
|
|
@@ -7397,25 +7542,25 @@ function registerCheckpoint(program3) {
|
|
|
7397
7542
|
function printPoints(points) {
|
|
7398
7543
|
if (!points.length) {
|
|
7399
7544
|
info("No checkpoints yet for this folder.");
|
|
7400
|
-
line(
|
|
7545
|
+
line(import_picocolors18.default.dim(" Take one with `workser checkpoint`."));
|
|
7401
7546
|
return;
|
|
7402
7547
|
}
|
|
7403
|
-
line(
|
|
7548
|
+
line(import_picocolors18.default.bold("Checkpoints"));
|
|
7404
7549
|
for (const p of points) {
|
|
7405
7550
|
const when = p.at ? new Date(p.at).toLocaleString() : "";
|
|
7406
7551
|
line(
|
|
7407
|
-
` ${
|
|
7552
|
+
` ${import_picocolors18.default.dim(p.ref.slice(0, 7))} ${p.label}${when ? import_picocolors18.default.dim(` ${when}`) : ""}`
|
|
7408
7553
|
);
|
|
7409
7554
|
}
|
|
7410
7555
|
line(
|
|
7411
|
-
|
|
7556
|
+
import_picocolors18.default.dim(
|
|
7412
7557
|
"\nGo back with `workser restore <ref>`, or just `workser restore` for the newest."
|
|
7413
7558
|
)
|
|
7414
7559
|
);
|
|
7415
7560
|
}
|
|
7416
7561
|
|
|
7417
7562
|
// src/commands/sync.ts
|
|
7418
|
-
var
|
|
7563
|
+
var import_picocolors19 = __toESM(require_picocolors(), 1);
|
|
7419
7564
|
function registerSync(program3) {
|
|
7420
7565
|
program3.command("sync").description(
|
|
7421
7566
|
"Reconcile this folder with the copy Workser holds (pull, then push)"
|
|
@@ -7442,7 +7587,7 @@ function registerSync(program3) {
|
|
|
7442
7587
|
warn(res?.message ?? "Couldn't sync this folder.");
|
|
7443
7588
|
if (res?.state === "diverged") {
|
|
7444
7589
|
line(
|
|
7445
|
-
|
|
7590
|
+
import_picocolors19.default.dim(
|
|
7446
7591
|
" This folder and Workser's copy have both changed. Open Workser to resolve it."
|
|
7447
7592
|
)
|
|
7448
7593
|
);
|
|
@@ -7454,7 +7599,7 @@ function registerSync(program3) {
|
|
|
7454
7599
|
return;
|
|
7455
7600
|
}
|
|
7456
7601
|
success("Synced");
|
|
7457
|
-
if (res?.ref) line(
|
|
7602
|
+
if (res?.ref) line(import_picocolors19.default.dim(` ${String(res.ref).slice(0, 7)}`));
|
|
7458
7603
|
});
|
|
7459
7604
|
if (refused) process.exitCode = 1;
|
|
7460
7605
|
})
|
|
@@ -7462,7 +7607,7 @@ function registerSync(program3) {
|
|
|
7462
7607
|
}
|
|
7463
7608
|
|
|
7464
7609
|
// src/commands/workflow.ts
|
|
7465
|
-
var
|
|
7610
|
+
var import_picocolors20 = __toESM(require_picocolors(), 1);
|
|
7466
7611
|
function registerWorkflow(program3) {
|
|
7467
7612
|
const wf = program3.command("workflow").description("Create, run, and inspect workflow automations for the project");
|
|
7468
7613
|
wf.command("list").description("List the project's workflows").action(
|
|
@@ -7470,10 +7615,10 @@ function registerWorkflow(program3) {
|
|
|
7470
7615
|
const projectId = requireProject(ctx);
|
|
7471
7616
|
const items = await api(ctx, `/v1/projects/${projectId}/workflows`);
|
|
7472
7617
|
ok(items, () => {
|
|
7473
|
-
if (!items?.length) return line(
|
|
7618
|
+
if (!items?.length) return line(import_picocolors20.default.dim("No workflows yet. `workser workflow create`."));
|
|
7474
7619
|
for (const w of items) {
|
|
7475
|
-
const status = w.is_active ?
|
|
7476
|
-
line(`${w.id} ${
|
|
7620
|
+
const status = w.is_active ? import_picocolors20.default.green("active") : import_picocolors20.default.dim("inactive");
|
|
7621
|
+
line(`${w.id} ${import_picocolors20.default.bold(w.name ?? "Untitled")} ${status}`);
|
|
7477
7622
|
}
|
|
7478
7623
|
});
|
|
7479
7624
|
})
|
|
@@ -7485,7 +7630,7 @@ function registerWorkflow(program3) {
|
|
|
7485
7630
|
const res = await api(ctx, `/v1/projects/${projectId}/workflows`, {
|
|
7486
7631
|
body: { name: args[0], ...extra }
|
|
7487
7632
|
});
|
|
7488
|
-
ok(res, () => line(`Created workflow ${
|
|
7633
|
+
ok(res, () => line(`Created workflow ${import_picocolors20.default.bold(res.id)}.`));
|
|
7489
7634
|
})
|
|
7490
7635
|
);
|
|
7491
7636
|
wf.command("get <id>").description("Show a workflow's full definition").action(
|
|
@@ -7520,8 +7665,8 @@ function registerWorkflow(program3) {
|
|
|
7520
7665
|
action(async ({ ctx, args }) => {
|
|
7521
7666
|
const items = await api(ctx, `/v1/workflows/${args[0]}/executions`);
|
|
7522
7667
|
ok(items, () => {
|
|
7523
|
-
if (!items?.length) return line(
|
|
7524
|
-
for (const e of items) line(`${e.id} ${e.status ?? ""} ${
|
|
7668
|
+
if (!items?.length) return line(import_picocolors20.default.dim("No runs yet."));
|
|
7669
|
+
for (const e of items) line(`${e.id} ${e.status ?? ""} ${import_picocolors20.default.dim(e.started_at ?? "")}`);
|
|
7525
7670
|
});
|
|
7526
7671
|
})
|
|
7527
7672
|
);
|
|
@@ -7529,15 +7674,15 @@ function registerWorkflow(program3) {
|
|
|
7529
7674
|
action(async ({ ctx, args }) => {
|
|
7530
7675
|
const items = await api(ctx, `/v1/node-types`, { query: { q: args[0] } });
|
|
7531
7676
|
ok(items, () => {
|
|
7532
|
-
if (!items?.length) return line(
|
|
7533
|
-
for (const n of items) line(`${n.name ?? n.type} ${
|
|
7677
|
+
if (!items?.length) return line(import_picocolors20.default.dim("No matching node types."));
|
|
7678
|
+
for (const n of items) line(`${n.name ?? n.type} ${import_picocolors20.default.dim(n.category ?? "")}`);
|
|
7534
7679
|
});
|
|
7535
7680
|
})
|
|
7536
7681
|
);
|
|
7537
7682
|
}
|
|
7538
7683
|
|
|
7539
7684
|
// src/commands/connection.ts
|
|
7540
|
-
var
|
|
7685
|
+
var import_picocolors21 = __toESM(require_picocolors(), 1);
|
|
7541
7686
|
function registerConnection(program3) {
|
|
7542
7687
|
const connection = program3.command("connection").description("Connect and use third-party app connections (Gmail, Slack, Stripe, ...)");
|
|
7543
7688
|
connection.command("list").description("List connectable toolkits and this project's existing connections").option("--toolkit <slug>", "filter connections to one toolkit").action(
|
|
@@ -7550,8 +7695,8 @@ function registerConnection(program3) {
|
|
|
7550
7695
|
ok({ catalog, connections }, () => {
|
|
7551
7696
|
const connected = new Set((connections ?? []).map((c) => c.toolkit ?? c.composio_app));
|
|
7552
7697
|
for (const t of catalog ?? []) {
|
|
7553
|
-
const status = connected.has(t.slug) ?
|
|
7554
|
-
line(`${t.slug} ${
|
|
7698
|
+
const status = connected.has(t.slug) ? import_picocolors21.default.green("connected") : import_picocolors21.default.dim("not connected");
|
|
7699
|
+
line(`${t.slug} ${import_picocolors21.default.bold(t.name ?? t.slug)} ${status}`);
|
|
7555
7700
|
}
|
|
7556
7701
|
});
|
|
7557
7702
|
})
|
|
@@ -7563,9 +7708,9 @@ function registerConnection(program3) {
|
|
|
7563
7708
|
query: { q: args[0], toolkit: opts.toolkit, limit: opts.limit }
|
|
7564
7709
|
});
|
|
7565
7710
|
ok(items, () => {
|
|
7566
|
-
if (!items?.length) return line(
|
|
7711
|
+
if (!items?.length) return line(import_picocolors21.default.dim("No matching actions."));
|
|
7567
7712
|
for (const t of items) {
|
|
7568
|
-
line(`${t.slug} ${
|
|
7713
|
+
line(`${t.slug} ${import_picocolors21.default.dim(`[${t.toolkit}]`)} ${t.description ?? ""}`);
|
|
7569
7714
|
}
|
|
7570
7715
|
});
|
|
7571
7716
|
})
|
|
@@ -7582,7 +7727,7 @@ function registerConnection(program3) {
|
|
|
7582
7727
|
});
|
|
7583
7728
|
ok(
|
|
7584
7729
|
res,
|
|
7585
|
-
() => res.oauth_url ? line(`Open this URL to finish connecting: ${
|
|
7730
|
+
() => res.oauth_url ? line(`Open this URL to finish connecting: ${import_picocolors21.default.underline(res.oauth_url)}`) : line(`Connection ${res.connection_id} is ${res.status}.`)
|
|
7586
7731
|
);
|
|
7587
7732
|
})
|
|
7588
7733
|
);
|
|
@@ -7600,8 +7745,8 @@ function registerConnection(program3) {
|
|
|
7600
7745
|
const projectId = requireProject(ctx);
|
|
7601
7746
|
const items = await api(ctx, `/v1/projects/${projectId}/integrations/${args[0]}/tools`);
|
|
7602
7747
|
ok(items, () => {
|
|
7603
|
-
if (!items?.length) return line(
|
|
7604
|
-
for (const t of items) line(`${t.slug} ${
|
|
7748
|
+
if (!items?.length) return line(import_picocolors21.default.dim("No tools found."));
|
|
7749
|
+
for (const t of items) line(`${t.slug} ${import_picocolors21.default.dim(t.description ?? "")}`);
|
|
7605
7750
|
});
|
|
7606
7751
|
})
|
|
7607
7752
|
);
|
|
@@ -7617,7 +7762,7 @@ function registerConnection(program3) {
|
|
|
7617
7762
|
}
|
|
7618
7763
|
|
|
7619
7764
|
// src/commands/tool.ts
|
|
7620
|
-
var
|
|
7765
|
+
var import_picocolors22 = __toESM(require_picocolors(), 1);
|
|
7621
7766
|
function registerTool(program3) {
|
|
7622
7767
|
const tool = program3.command("tool").description(
|
|
7623
7768
|
"Computer-use tools: filesystem, shell, screenshot, input control, clipboard, notifications, basic browser"
|
|
@@ -7626,7 +7771,7 @@ function registerTool(program3) {
|
|
|
7626
7771
|
action(async ({ ctx }) => {
|
|
7627
7772
|
const tools = await api(ctx, "/v1/tool/list");
|
|
7628
7773
|
ok(tools, () => {
|
|
7629
|
-
if (!tools?.length) return line(
|
|
7774
|
+
if (!tools?.length) return line(import_picocolors22.default.dim("No tools available."));
|
|
7630
7775
|
const byCategory = /* @__PURE__ */ new Map();
|
|
7631
7776
|
for (const t of tools) {
|
|
7632
7777
|
const list = byCategory.get(t.category) ?? [];
|
|
@@ -7634,9 +7779,9 @@ function registerTool(program3) {
|
|
|
7634
7779
|
byCategory.set(t.category, list);
|
|
7635
7780
|
}
|
|
7636
7781
|
for (const [category, items] of byCategory) {
|
|
7637
|
-
line(
|
|
7782
|
+
line(import_picocolors22.default.bold(category) + ":");
|
|
7638
7783
|
for (const t of items) {
|
|
7639
|
-
line(` ${t.name} ${
|
|
7784
|
+
line(` ${t.name} ${import_picocolors22.default.dim(t.description ?? "")}`);
|
|
7640
7785
|
}
|
|
7641
7786
|
}
|
|
7642
7787
|
});
|
|
@@ -7654,7 +7799,7 @@ function registerTool(program3) {
|
|
|
7654
7799
|
}
|
|
7655
7800
|
|
|
7656
7801
|
// src/commands/memory.ts
|
|
7657
|
-
var
|
|
7802
|
+
var import_picocolors23 = __toESM(require_picocolors(), 1);
|
|
7658
7803
|
function registerMemory(program3) {
|
|
7659
7804
|
const memory = program3.command("memory").description("Durable, cross-conversation project memory (shared with cloud agents on the same project)");
|
|
7660
7805
|
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(
|
|
@@ -7678,9 +7823,9 @@ function registerMemory(program3) {
|
|
|
7678
7823
|
});
|
|
7679
7824
|
ok(res, () => {
|
|
7680
7825
|
const results = res?.results ?? res ?? [];
|
|
7681
|
-
if (!results?.length) return line(
|
|
7826
|
+
if (!results?.length) return line(import_picocolors23.default.dim("No matching memories."));
|
|
7682
7827
|
for (const r of results) {
|
|
7683
|
-
line(`${
|
|
7828
|
+
line(`${import_picocolors23.default.dim(r.id ?? "?")} ${r.memory ?? r.content ?? ""}`);
|
|
7684
7829
|
}
|
|
7685
7830
|
});
|
|
7686
7831
|
})
|
|
@@ -7697,7 +7842,7 @@ function registerMemory(program3) {
|
|
|
7697
7842
|
}
|
|
7698
7843
|
|
|
7699
7844
|
// src/commands/business.ts
|
|
7700
|
-
var
|
|
7845
|
+
var import_picocolors24 = __toESM(require_picocolors(), 1);
|
|
7701
7846
|
var RESOURCE_PATHS = {
|
|
7702
7847
|
"business-config": "business-config",
|
|
7703
7848
|
"business-settings": "business-settings",
|
|
@@ -7757,7 +7902,7 @@ function registerBusiness(program3) {
|
|
|
7757
7902
|
const projectId = requireProject(ctx);
|
|
7758
7903
|
const [resource] = args;
|
|
7759
7904
|
const res = await api(ctx, businessPath(projectId, resource), { body: JSON.parse(opts.body) });
|
|
7760
|
-
ok(res, () => line(`Created ${resource} ${
|
|
7905
|
+
ok(res, () => line(`Created ${resource} ${import_picocolors24.default.bold(res?.id ?? "")}.`));
|
|
7761
7906
|
})
|
|
7762
7907
|
);
|
|
7763
7908
|
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(
|
|
@@ -7799,7 +7944,7 @@ function businessPath(projectId, resource, subpath) {
|
|
|
7799
7944
|
}
|
|
7800
7945
|
|
|
7801
7946
|
// src/commands/artifact.ts
|
|
7802
|
-
var
|
|
7947
|
+
var import_picocolors25 = __toESM(require_picocolors(), 1);
|
|
7803
7948
|
import { existsSync as existsSync2, statSync } from "fs";
|
|
7804
7949
|
import { resolve as resolve3, basename as basename3 } from "path";
|
|
7805
7950
|
var KINDS = [
|
|
@@ -7896,7 +8041,7 @@ function registerArtifact(program3) {
|
|
|
7896
8041
|
ok(
|
|
7897
8042
|
res,
|
|
7898
8043
|
() => success(
|
|
7899
|
-
`Recorded ${
|
|
8044
|
+
`Recorded ${import_picocolors25.default.bold(res?.title ?? "artifact")}${res?.kind ? import_picocolors25.default.dim(` (${res.kind})`) : ""}`
|
|
7900
8045
|
)
|
|
7901
8046
|
);
|
|
7902
8047
|
})
|
|
@@ -7934,7 +8079,7 @@ function registerArtifact(program3) {
|
|
|
7934
8079
|
}
|
|
7935
8080
|
function printArtifacts(rows) {
|
|
7936
8081
|
if (!rows.length) {
|
|
7937
|
-
line(
|
|
8082
|
+
line(import_picocolors25.default.dim("Nothing produced yet."));
|
|
7938
8083
|
return;
|
|
7939
8084
|
}
|
|
7940
8085
|
const byStep = /* @__PURE__ */ new Map();
|
|
@@ -7944,26 +8089,26 @@ function printArtifacts(rows) {
|
|
|
7944
8089
|
byStep.set(r.subtask_id, list);
|
|
7945
8090
|
}
|
|
7946
8091
|
for (const [stepId, items] of byStep) {
|
|
7947
|
-
line(
|
|
8092
|
+
line(import_picocolors25.default.bold(`step ${stepId}`));
|
|
7948
8093
|
for (const a of items) {
|
|
7949
|
-
const flag = a.promoted_at ?
|
|
8094
|
+
const flag = a.promoted_at ? import_picocolors25.default.green(" *") : " ";
|
|
7950
8095
|
const where = a.local_path || a.cloud_url || "";
|
|
7951
8096
|
line(
|
|
7952
|
-
`${flag} ${
|
|
8097
|
+
`${flag} ${import_picocolors25.default.dim(`[${a.kind}]`)} ${a.title ?? "(untitled)"}` + (where ? import_picocolors25.default.dim(` ${where}`) : "")
|
|
7953
8098
|
);
|
|
7954
|
-
if (a.description) line(
|
|
8099
|
+
if (a.description) line(import_picocolors25.default.dim(` ${a.description}`));
|
|
7955
8100
|
}
|
|
7956
8101
|
line("");
|
|
7957
8102
|
}
|
|
7958
|
-
line(
|
|
8103
|
+
line(import_picocolors25.default.dim("* = handed over as a deliverable; the rest is working material."));
|
|
7959
8104
|
}
|
|
7960
8105
|
function printRun(run) {
|
|
7961
8106
|
if (!run) return;
|
|
7962
|
-
line(` run ${
|
|
8107
|
+
line(` run ${import_picocolors25.default.bold(run.runId)}`);
|
|
7963
8108
|
if (run.taskId) line(` task ${run.taskId}`);
|
|
7964
8109
|
if (run.conversationId) line(` chat ${run.conversationId}`);
|
|
7965
8110
|
if (run.projectId) line(` project ${run.projectId}`);
|
|
7966
|
-
if (run.cwd) line(` folder ${
|
|
8111
|
+
if (run.cwd) line(` folder ${import_picocolors25.default.dim(run.cwd)}`);
|
|
7967
8112
|
}
|
|
7968
8113
|
|
|
7969
8114
|
// src/commands/image.ts
|
|
@@ -8144,7 +8289,7 @@ function registerAudio(program3) {
|
|
|
8144
8289
|
}
|
|
8145
8290
|
|
|
8146
8291
|
// src/commands/ask.ts
|
|
8147
|
-
var
|
|
8292
|
+
var import_picocolors26 = __toESM(require_picocolors(), 1);
|
|
8148
8293
|
var TYPES = [
|
|
8149
8294
|
"input",
|
|
8150
8295
|
"choice",
|
|
@@ -8222,7 +8367,7 @@ function registerAsk(program3) {
|
|
|
8222
8367
|
code: "bad_request"
|
|
8223
8368
|
});
|
|
8224
8369
|
}
|
|
8225
|
-
info(
|
|
8370
|
+
info(import_picocolors26.default.dim("Waiting for the user to answer\u2026"));
|
|
8226
8371
|
const res = await api(ctx, `/v1/runs/${runTarget(ctx)}/ask`, {
|
|
8227
8372
|
body: {
|
|
8228
8373
|
type,
|
|
@@ -8250,12 +8395,12 @@ function deriveTitle(message) {
|
|
|
8250
8395
|
function printAnswer(res) {
|
|
8251
8396
|
if (!res) return;
|
|
8252
8397
|
if (res.status === "answered") {
|
|
8253
|
-
line(` ${
|
|
8398
|
+
line(` ${import_picocolors26.default.green("answered")}`);
|
|
8254
8399
|
const value = extract(res.response);
|
|
8255
8400
|
if (value) line(` ${value}`);
|
|
8256
8401
|
return;
|
|
8257
8402
|
}
|
|
8258
|
-
line(` ${
|
|
8403
|
+
line(` ${import_picocolors26.default.yellow(res.status)} ${import_picocolors26.default.dim(res.reason ?? "")}`);
|
|
8259
8404
|
}
|
|
8260
8405
|
function extract(response) {
|
|
8261
8406
|
if (response == null) return "";
|
|
@@ -8274,7 +8419,7 @@ function extract(response) {
|
|
|
8274
8419
|
}
|
|
8275
8420
|
|
|
8276
8421
|
// src/commands/search.ts
|
|
8277
|
-
var
|
|
8422
|
+
var import_picocolors27 = __toESM(require_picocolors(), 1);
|
|
8278
8423
|
function registerSearch(program3) {
|
|
8279
8424
|
program3.command("search <query>").description("Search the web (Google-grounded, server-side)").option("-n, --max-results <n>", "max results", "5").action(
|
|
8280
8425
|
action(async ({ ctx, args, opts }) => {
|
|
@@ -8287,9 +8432,9 @@ function registerSearch(program3) {
|
|
|
8287
8432
|
line("");
|
|
8288
8433
|
}
|
|
8289
8434
|
const results = res?.results ?? [];
|
|
8290
|
-
if (!results.length) return line(
|
|
8435
|
+
if (!results.length) return line(import_picocolors27.default.dim("No results."));
|
|
8291
8436
|
for (const r of results) {
|
|
8292
|
-
line(`${r.title ||
|
|
8437
|
+
line(`${r.title || import_picocolors27.default.dim("(untitled)")} ${import_picocolors27.default.dim(r.url)}`);
|
|
8293
8438
|
}
|
|
8294
8439
|
});
|
|
8295
8440
|
})
|
|
@@ -8297,7 +8442,7 @@ function registerSearch(program3) {
|
|
|
8297
8442
|
}
|
|
8298
8443
|
|
|
8299
8444
|
// src/commands/board.ts
|
|
8300
|
-
var
|
|
8445
|
+
var import_picocolors28 = __toESM(require_picocolors(), 1);
|
|
8301
8446
|
|
|
8302
8447
|
// src/commands/record-step.ts
|
|
8303
8448
|
async function recordEntityStep(ctx, opts) {
|
|
@@ -8336,7 +8481,7 @@ function registerBoard(program3) {
|
|
|
8336
8481
|
}
|
|
8337
8482
|
ok(rows, () => {
|
|
8338
8483
|
if (!rows.length) {
|
|
8339
|
-
line(
|
|
8484
|
+
line(import_picocolors28.default.dim("No cards on the Board yet."));
|
|
8340
8485
|
return;
|
|
8341
8486
|
}
|
|
8342
8487
|
for (const r of rows) line(formatRow(r));
|
|
@@ -8351,7 +8496,7 @@ function registerBoard(program3) {
|
|
|
8351
8496
|
`/v1/projects/${projectId}/work-items/${args[0]}`
|
|
8352
8497
|
);
|
|
8353
8498
|
ok(row, () => {
|
|
8354
|
-
line(`${
|
|
8499
|
+
line(`${import_picocolors28.default.bold(row.title)} ${import_picocolors28.default.dim(row.id)}`);
|
|
8355
8500
|
line(`${statusTag(row.status)} priority ${row.priority}`);
|
|
8356
8501
|
if (row.ownerHuman) line(`owner: ${row.ownerHuman}`);
|
|
8357
8502
|
if (row.labels?.length) line(`labels: ${row.labels.join(", ")}`);
|
|
@@ -8392,7 +8537,7 @@ ${row.description}`);
|
|
|
8392
8537
|
refId: row?.id,
|
|
8393
8538
|
output: { workItem: row }
|
|
8394
8539
|
});
|
|
8395
|
-
ok(row, () => line(`Created work item ${
|
|
8540
|
+
ok(row, () => line(`Created work item ${import_picocolors28.default.bold(row?.id ?? "")} \u2014 ${title}`));
|
|
8396
8541
|
})
|
|
8397
8542
|
);
|
|
8398
8543
|
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(
|
|
@@ -8426,7 +8571,7 @@ ${row.description}`);
|
|
|
8426
8571
|
);
|
|
8427
8572
|
}
|
|
8428
8573
|
const row = await patchItem(ctx, projectId, String(args[0]), body);
|
|
8429
|
-
ok(row, () => line(`Updated ${
|
|
8574
|
+
ok(row, () => line(`Updated ${import_picocolors28.default.bold(row.id)} \u2014 ${row.title} ${statusTag(row.status)}`));
|
|
8430
8575
|
})
|
|
8431
8576
|
);
|
|
8432
8577
|
board.command("move <id> <status>").description(
|
|
@@ -8437,14 +8582,14 @@ ${row.description}`);
|
|
|
8437
8582
|
const status = String(args[1]);
|
|
8438
8583
|
assertStatus(status);
|
|
8439
8584
|
const row = await patchItem(ctx, projectId, String(args[0]), { status });
|
|
8440
|
-
ok(row, () => line(`Moved ${
|
|
8585
|
+
ok(row, () => line(`Moved ${import_picocolors28.default.bold(row.title)} \u2192 ${statusTag(row.status)}`));
|
|
8441
8586
|
})
|
|
8442
8587
|
);
|
|
8443
8588
|
board.command("close <id>").description("Shorthand for `board move <id> done`").action(
|
|
8444
8589
|
action(async ({ ctx, args }) => {
|
|
8445
8590
|
const projectId = requireProject(ctx);
|
|
8446
8591
|
const row = await patchItem(ctx, projectId, String(args[0]), { status: "done" });
|
|
8447
|
-
ok(row, () => line(`Closed ${
|
|
8592
|
+
ok(row, () => line(`Closed ${import_picocolors28.default.bold(row.title)} ${statusTag(row.status)}`));
|
|
8448
8593
|
})
|
|
8449
8594
|
);
|
|
8450
8595
|
}
|
|
@@ -8477,32 +8622,74 @@ function assertPriority(value) {
|
|
|
8477
8622
|
}
|
|
8478
8623
|
}
|
|
8479
8624
|
function formatRow(r) {
|
|
8480
|
-
const labels = r.labels?.length ?
|
|
8481
|
-
const owner = r.ownerHuman ?
|
|
8482
|
-
return `${
|
|
8625
|
+
const labels = r.labels?.length ? import_picocolors28.default.dim(` [${r.labels.join(", ")}]`) : "";
|
|
8626
|
+
const owner = r.ownerHuman ? import_picocolors28.default.dim(` @${r.ownerHuman}`) : "";
|
|
8627
|
+
return `${import_picocolors28.default.dim(r.id)} ${statusTag(r.status)} ${r.title}${labels}${owner}`;
|
|
8483
8628
|
}
|
|
8484
8629
|
function statusTag(status) {
|
|
8485
8630
|
const label = status.padEnd(11);
|
|
8486
|
-
if (status === "done") return
|
|
8487
|
-
if (status === "in-progress") return
|
|
8488
|
-
if (status === "in-review") return
|
|
8489
|
-
return
|
|
8631
|
+
if (status === "done") return import_picocolors28.default.green(label);
|
|
8632
|
+
if (status === "in-progress") return import_picocolors28.default.yellow(label);
|
|
8633
|
+
if (status === "in-review") return import_picocolors28.default.cyan(label);
|
|
8634
|
+
return import_picocolors28.default.dim(label);
|
|
8490
8635
|
}
|
|
8491
8636
|
function collect2(value, previous) {
|
|
8492
8637
|
return [...previous, value];
|
|
8493
8638
|
}
|
|
8494
8639
|
|
|
8495
8640
|
// src/commands/task.ts
|
|
8496
|
-
var
|
|
8497
|
-
var STATUSES2 = [
|
|
8498
|
-
|
|
8499
|
-
|
|
8641
|
+
var import_picocolors29 = __toESM(require_picocolors(), 1);
|
|
8642
|
+
var STATUSES2 = [
|
|
8643
|
+
"todo",
|
|
8644
|
+
"working",
|
|
8645
|
+
"checking",
|
|
8646
|
+
"ready",
|
|
8647
|
+
"accepted",
|
|
8648
|
+
"archived"
|
|
8649
|
+
];
|
|
8650
|
+
var ROLES = [
|
|
8651
|
+
"pm",
|
|
8652
|
+
"architect",
|
|
8653
|
+
"designer",
|
|
8654
|
+
"web",
|
|
8655
|
+
"api",
|
|
8656
|
+
"mobile",
|
|
8657
|
+
"python",
|
|
8658
|
+
"automation",
|
|
8659
|
+
"qa",
|
|
8660
|
+
"devops",
|
|
8661
|
+
"sre",
|
|
8662
|
+
"security",
|
|
8663
|
+
"analyst"
|
|
8664
|
+
];
|
|
8665
|
+
var AGENTS = [
|
|
8666
|
+
"claude_code",
|
|
8667
|
+
"codex",
|
|
8668
|
+
"workser_code",
|
|
8669
|
+
"opencode",
|
|
8670
|
+
"cursor",
|
|
8671
|
+
"gemini"
|
|
8672
|
+
];
|
|
8673
|
+
var EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
8674
|
+
var KINDS2 = [
|
|
8675
|
+
"data_reports",
|
|
8676
|
+
"web",
|
|
8677
|
+
"mobile",
|
|
8678
|
+
"service",
|
|
8679
|
+
"automation",
|
|
8680
|
+
"docs"
|
|
8681
|
+
];
|
|
8682
|
+
var KIND_HELP = "what it produces (web app \u2192 web \xB7 phone app \u2192 mobile \xB7 api or ai-agent \u2192 service \xB7 worker or scheduled job \u2192 automation \xB7 report or analysis \u2192 data_reports \xB7 written page \u2192 docs)";
|
|
8500
8683
|
function registerTask(program3) {
|
|
8501
8684
|
const task = program3.command("task").description("The project's tasks and their subtasks (AI Tech Team)");
|
|
8502
|
-
task.command("list").description("List the board's tasks \u2014 run this before starting anything").option(
|
|
8685
|
+
task.command("list").description("List the board's tasks \u2014 run this before starting anything").option(
|
|
8686
|
+
"--status <value>",
|
|
8687
|
+
`only tasks in this status (${STATUSES2.join(" | ")})`
|
|
8688
|
+
).option("--label <value>", "only tasks carrying this label").option("--limit <n>", "cap the number of tasks returned").action(
|
|
8503
8689
|
action(async ({ ctx, opts }) => {
|
|
8504
8690
|
requireProject(ctx);
|
|
8505
|
-
if (opts.status !== void 0)
|
|
8691
|
+
if (opts.status !== void 0)
|
|
8692
|
+
assertOneOf("--status", opts.status, STATUSES2);
|
|
8506
8693
|
const rows = await api(ctx, "/v1/project-tasks", {
|
|
8507
8694
|
query: {
|
|
8508
8695
|
status: opts.status,
|
|
@@ -8512,7 +8699,7 @@ function registerTask(program3) {
|
|
|
8512
8699
|
}) ?? [];
|
|
8513
8700
|
ok(rows, () => {
|
|
8514
8701
|
if (!rows.length) {
|
|
8515
|
-
line(
|
|
8702
|
+
line(import_picocolors29.default.dim("No tasks on the board yet."));
|
|
8516
8703
|
return;
|
|
8517
8704
|
}
|
|
8518
8705
|
for (const r of rows) line(formatRow2(r));
|
|
@@ -8524,7 +8711,10 @@ function registerTask(program3) {
|
|
|
8524
8711
|
).action(
|
|
8525
8712
|
action(async ({ ctx, args }) => {
|
|
8526
8713
|
const id = args[0] || ctx.parentTaskId || resolveTaskId(ctx);
|
|
8527
|
-
const row = await api(
|
|
8714
|
+
const row = await api(
|
|
8715
|
+
ctx,
|
|
8716
|
+
`/v1/project-tasks/${encodeURIComponent(id)}`
|
|
8717
|
+
);
|
|
8528
8718
|
const goalId = row.goal_id;
|
|
8529
8719
|
const goal = goalId ? await api(
|
|
8530
8720
|
ctx,
|
|
@@ -8533,7 +8723,7 @@ function registerTask(program3) {
|
|
|
8533
8723
|
ok({ ...row, goal }, () => printTask(row, goal));
|
|
8534
8724
|
})
|
|
8535
8725
|
);
|
|
8536
|
-
task.command("create <title>").description("Open a new root task for the project team").option("--note <text>", "context, constraints and expected outcome").option("--kind <value>",
|
|
8726
|
+
task.command("create <title>").description("Open a new root task for the project team").option("--note <text>", "context, constraints and expected outcome").option("--kind <value>", KIND_HELP).option("--label <value...>", "labels to put on the task").option("--app <id...>", "apps the task touches").option("--infra <ref...>", "shared setup it touches").option("--goal <id>", "the business goal this delivers part of").option(
|
|
8537
8727
|
"--phase <name>",
|
|
8538
8728
|
"which slice of that goal \u2014 must match one of its phase names"
|
|
8539
8729
|
).action(
|
|
@@ -8554,8 +8744,14 @@ function registerTask(program3) {
|
|
|
8554
8744
|
goalId: opts.goal,
|
|
8555
8745
|
phase: opts.phase,
|
|
8556
8746
|
targets: [
|
|
8557
|
-
...(opts.app ?? []).map((appId) => ({
|
|
8558
|
-
|
|
8747
|
+
...(opts.app ?? []).map((appId) => ({
|
|
8748
|
+
kind: "app",
|
|
8749
|
+
appId
|
|
8750
|
+
})),
|
|
8751
|
+
...(opts.infra ?? []).map((ref) => ({
|
|
8752
|
+
kind: "infra",
|
|
8753
|
+
ref
|
|
8754
|
+
}))
|
|
8559
8755
|
],
|
|
8560
8756
|
...hasChannelOrigin ? {
|
|
8561
8757
|
channelId: ctx.projectChannelId,
|
|
@@ -8595,8 +8791,11 @@ function registerTask(program3) {
|
|
|
8595
8791
|
...channelMessageError ? { channelMessageError } : {}
|
|
8596
8792
|
};
|
|
8597
8793
|
ok(result, () => {
|
|
8598
|
-
line(
|
|
8599
|
-
|
|
8794
|
+
line(
|
|
8795
|
+
`${import_picocolors29.default.green("opened")} ${import_picocolors29.default.bold(row.title)} ${import_picocolors29.default.dim(row.key ?? row.id)}`
|
|
8796
|
+
);
|
|
8797
|
+
if (channelMessage)
|
|
8798
|
+
line(import_picocolors29.default.dim("posted to the channel as Project Manager"));
|
|
8600
8799
|
if (channelMessageError) {
|
|
8601
8800
|
warn(
|
|
8602
8801
|
`Task opened, but its Project Manager card could not be posted: ${channelMessageError.message}`
|
|
@@ -8608,14 +8807,30 @@ function registerTask(program3) {
|
|
|
8608
8807
|
const subtask = task.command("subtask").description("The subtasks a task is broken into");
|
|
8609
8808
|
subtask.command("add <title>").description(
|
|
8610
8809
|
'Add one subtask, e.g. `workser task subtask add "Build the upload screen" --role web`'
|
|
8611
|
-
).option(
|
|
8810
|
+
).option(
|
|
8811
|
+
"--task <id>",
|
|
8812
|
+
"the parent task (defaults to the task this run is inside)"
|
|
8813
|
+
).option("--role <value>", `who does it (${ROLES.join(" | ")})`).option("--kind <value>", KIND_HELP).option("--note <text>", "one sentence on what this subtask does").option(
|
|
8612
8814
|
"--app <id...>",
|
|
8613
8815
|
"the app this subtask is for \u2014 one id runs it inside that app's folder; leave it off and it runs at the project, seeing every app"
|
|
8614
|
-
).option(
|
|
8816
|
+
).option(
|
|
8817
|
+
"--infra <ref...>",
|
|
8818
|
+
"shared setup it touches (database | storage | auth | hosting | jobs)"
|
|
8819
|
+
).option("--scope <path...>", "files or folders THIS subtask owns").option(
|
|
8820
|
+
"--depends-on <id...>",
|
|
8821
|
+
"subtasks that must finish first (key or id)"
|
|
8822
|
+
).option(
|
|
8823
|
+
"--agent <id>",
|
|
8824
|
+
`run this step on a specific CLI (${AGENTS.join(" | ")}) instead of the role's own`
|
|
8825
|
+
).option("--model <id>", "the model that CLI should use for this step").option("--effort <level>", `how hard it thinks (${EFFORTS.join(" | ")})`).action(
|
|
8615
8826
|
action(async ({ ctx, args, opts }) => {
|
|
8616
8827
|
const parent = resolveTaskId(ctx, opts.task);
|
|
8617
8828
|
if (opts.role !== void 0) assertOneOf("--role", opts.role, ROLES);
|
|
8618
8829
|
if (opts.kind !== void 0) assertOneOf("--kind", opts.kind, KINDS2);
|
|
8830
|
+
if (opts.agent !== void 0) assertOneOf("--agent", opts.agent, AGENTS);
|
|
8831
|
+
if (opts.effort !== void 0)
|
|
8832
|
+
assertOneOf("--effort", opts.effort, EFFORTS);
|
|
8833
|
+
assertDelegatableModel("--model", opts.model);
|
|
8619
8834
|
const dependsOn = await resolveDeps(ctx, parent, opts.dependsOn ?? []);
|
|
8620
8835
|
const row = await api(ctx, "/v1/project-tasks", {
|
|
8621
8836
|
body: {
|
|
@@ -8627,35 +8842,78 @@ function registerTask(program3) {
|
|
|
8627
8842
|
scopePaths: opts.scope,
|
|
8628
8843
|
dependsOn,
|
|
8629
8844
|
targets: [
|
|
8630
|
-
...(opts.app ?? []).map((appId) => ({
|
|
8631
|
-
|
|
8845
|
+
...(opts.app ?? []).map((appId) => ({
|
|
8846
|
+
kind: "app",
|
|
8847
|
+
appId
|
|
8848
|
+
})),
|
|
8849
|
+
...(opts.infra ?? []).map((ref) => ({
|
|
8850
|
+
kind: "infra",
|
|
8851
|
+
ref
|
|
8852
|
+
}))
|
|
8632
8853
|
]
|
|
8633
8854
|
}
|
|
8634
8855
|
});
|
|
8635
|
-
|
|
8636
|
-
|
|
8637
|
-
|
|
8856
|
+
const runner = opts.agent !== void 0 || opts.model !== void 0 || opts.effort !== void 0 ? await api(
|
|
8857
|
+
ctx,
|
|
8858
|
+
`/v1/project-tasks/${encodeURIComponent(row.id)}`,
|
|
8859
|
+
{
|
|
8860
|
+
method: "PATCH",
|
|
8861
|
+
body: {
|
|
8862
|
+
agentOverride: opts.agent,
|
|
8863
|
+
agentModelOverride: opts.model,
|
|
8864
|
+
agentEffortOverride: opts.effort
|
|
8865
|
+
}
|
|
8866
|
+
}
|
|
8867
|
+
) : null;
|
|
8868
|
+
ok(runner ?? row, () => {
|
|
8869
|
+
line(
|
|
8870
|
+
`${import_picocolors29.default.green("added")} ${import_picocolors29.default.bold(row.title)} ${import_picocolors29.default.dim(row.key ?? row.id)}`
|
|
8871
|
+
);
|
|
8872
|
+
if (row.role) line(import_picocolors29.default.dim(`role: ${row.role}`));
|
|
8873
|
+
if (runner) {
|
|
8874
|
+
line(
|
|
8875
|
+
import_picocolors29.default.dim(
|
|
8876
|
+
`runs on: ${[opts.agent, opts.model, opts.effort].filter(Boolean).join(" \xB7 ")}`
|
|
8877
|
+
)
|
|
8878
|
+
);
|
|
8879
|
+
}
|
|
8638
8880
|
});
|
|
8639
8881
|
})
|
|
8640
8882
|
);
|
|
8641
8883
|
subtask.command("list [taskId]").description("The subtasks of a task, in order").action(
|
|
8642
8884
|
action(async ({ ctx, args }) => {
|
|
8643
8885
|
const id = resolveTaskId(ctx, args[0]);
|
|
8644
|
-
const row = await api(
|
|
8886
|
+
const row = await api(
|
|
8887
|
+
ctx,
|
|
8888
|
+
`/v1/project-tasks/${encodeURIComponent(id)}`
|
|
8889
|
+
);
|
|
8645
8890
|
const rows = row.subtasks ?? [];
|
|
8646
8891
|
ok(rows, () => {
|
|
8647
8892
|
if (!rows.length) {
|
|
8648
|
-
line(
|
|
8893
|
+
line(import_picocolors29.default.dim("No subtasks yet."));
|
|
8649
8894
|
return;
|
|
8650
8895
|
}
|
|
8651
8896
|
rows.forEach((r, i) => line(formatSubtask(r, i + 1)));
|
|
8652
8897
|
});
|
|
8653
8898
|
})
|
|
8654
8899
|
);
|
|
8655
|
-
subtask.command("update <id>").description("Change a subtask \u2014 its title, its role, what it touches").option("--title <text>").option("--note <text>").option("--role <value>", ROLES.join(" | ")).option("--kind <value>", KINDS2.join(" | ")).option("--scope <path...>", "replaces the subtask's scope entirely").
|
|
8900
|
+
subtask.command("update <id>").description("Change a subtask \u2014 its title, its role, what it touches").option("--title <text>").option("--note <text>").option("--role <value>", ROLES.join(" | ")).option("--kind <value>", KINDS2.join(" | ")).option("--scope <path...>", "replaces the subtask's scope entirely").option(
|
|
8901
|
+
"--agent <id>",
|
|
8902
|
+
`run this step on a specific CLI (${AGENTS.join(" | ")}); "default" hands it back to the role's own`
|
|
8903
|
+
).option("--model <id>", 'the model that CLI should use; "default" clears it').option(
|
|
8904
|
+
"--effort <level>",
|
|
8905
|
+
`how hard it thinks (${EFFORTS.join(" | ")}); "default" clears it`
|
|
8906
|
+
).action(
|
|
8656
8907
|
action(async ({ ctx, args, opts }) => {
|
|
8657
8908
|
if (opts.role !== void 0) assertOneOf("--role", opts.role, ROLES);
|
|
8658
8909
|
if (opts.kind !== void 0) assertOneOf("--kind", opts.kind, KINDS2);
|
|
8910
|
+
if (opts.agent !== void 0 && opts.agent !== "default")
|
|
8911
|
+
assertOneOf("--agent", opts.agent, AGENTS);
|
|
8912
|
+
if (opts.effort !== void 0 && opts.effort !== "default")
|
|
8913
|
+
assertOneOf("--effort", opts.effort, EFFORTS);
|
|
8914
|
+
if (opts.model !== "default")
|
|
8915
|
+
assertDelegatableModel("--model", opts.model);
|
|
8916
|
+
const clearable = (value) => value === void 0 ? void 0 : value === "default" ? null : value;
|
|
8659
8917
|
const row = await api(
|
|
8660
8918
|
ctx,
|
|
8661
8919
|
`/v1/project-tasks/${encodeURIComponent(args[0])}`,
|
|
@@ -8666,11 +8924,14 @@ function registerTask(program3) {
|
|
|
8666
8924
|
summary: opts.note,
|
|
8667
8925
|
role: opts.role,
|
|
8668
8926
|
category: opts.kind,
|
|
8669
|
-
scopePaths: opts.scope
|
|
8927
|
+
scopePaths: opts.scope,
|
|
8928
|
+
agentOverride: clearable(opts.agent),
|
|
8929
|
+
agentModelOverride: clearable(opts.model),
|
|
8930
|
+
agentEffortOverride: clearable(opts.effort)
|
|
8670
8931
|
}
|
|
8671
8932
|
}
|
|
8672
8933
|
);
|
|
8673
|
-
ok(row, () => line(`${
|
|
8934
|
+
ok(row, () => line(`${import_picocolors29.default.green("updated")} ${import_picocolors29.default.bold(row.title)}`));
|
|
8674
8935
|
})
|
|
8675
8936
|
);
|
|
8676
8937
|
subtask.command("remove <id>").description("Remove a subtask (only before the work starts)").action(
|
|
@@ -8678,10 +8939,12 @@ function registerTask(program3) {
|
|
|
8678
8939
|
await api(ctx, `/v1/project-tasks/${encodeURIComponent(args[0])}`, {
|
|
8679
8940
|
method: "DELETE"
|
|
8680
8941
|
});
|
|
8681
|
-
ok({ removed: args[0] }, () => line(
|
|
8942
|
+
ok({ removed: args[0] }, () => line(import_picocolors29.default.green("removed")));
|
|
8682
8943
|
})
|
|
8683
8944
|
);
|
|
8684
|
-
task.command("move <id> <status>").description(
|
|
8945
|
+
task.command("move <id> <status>").description(
|
|
8946
|
+
`Move a task or step along the board (${STATUSES2.join(" | ")})`
|
|
8947
|
+
).action(
|
|
8685
8948
|
action(async ({ ctx, args }) => {
|
|
8686
8949
|
assertOneOf("<status>", args[1], STATUSES2);
|
|
8687
8950
|
const row = await api(
|
|
@@ -8689,7 +8952,10 @@ function registerTask(program3) {
|
|
|
8689
8952
|
`/v1/project-tasks/${encodeURIComponent(args[0])}/move`,
|
|
8690
8953
|
{ body: { status: args[1] } }
|
|
8691
8954
|
);
|
|
8692
|
-
ok(
|
|
8955
|
+
ok(
|
|
8956
|
+
row,
|
|
8957
|
+
() => line(`${import_picocolors29.default.green("moved")} ${import_picocolors29.default.bold(row.title)} \u2192 ${args[1]}`)
|
|
8958
|
+
);
|
|
8693
8959
|
})
|
|
8694
8960
|
);
|
|
8695
8961
|
task.command("resume [id]").description(
|
|
@@ -8704,18 +8970,18 @@ function registerTask(program3) {
|
|
|
8704
8970
|
);
|
|
8705
8971
|
ok(row, () => {
|
|
8706
8972
|
if (!row?.queued) {
|
|
8707
|
-
line(
|
|
8973
|
+
line(import_picocolors29.default.yellow("could not resume it \u2014 check the step id"));
|
|
8708
8974
|
return;
|
|
8709
8975
|
}
|
|
8710
8976
|
const started = row.started ?? 0;
|
|
8711
8977
|
if (started > 0) {
|
|
8712
8978
|
line(
|
|
8713
|
-
`${
|
|
8979
|
+
`${import_picocolors29.default.green("resumed")} \u2014 ${started} step${started === 1 ? "" : "s"} started`
|
|
8714
8980
|
);
|
|
8715
8981
|
return;
|
|
8716
8982
|
}
|
|
8717
8983
|
line(
|
|
8718
|
-
`${
|
|
8984
|
+
`${import_picocolors29.default.green("resumed")} \u2014 it is queued, but nothing started yet. Check the plan is approved and that no step is blocking the rest.`
|
|
8719
8985
|
);
|
|
8720
8986
|
});
|
|
8721
8987
|
})
|
|
@@ -8729,18 +8995,20 @@ function registerTask(program3) {
|
|
|
8729
8995
|
);
|
|
8730
8996
|
ok(row, () => {
|
|
8731
8997
|
if (row?.reopened) {
|
|
8732
|
-
line(`${
|
|
8998
|
+
line(`${import_picocolors29.default.green("sent back")} \u2014 it will be picked up again`);
|
|
8733
8999
|
return;
|
|
8734
9000
|
}
|
|
8735
9001
|
line(
|
|
8736
|
-
|
|
9002
|
+
import_picocolors29.default.yellow(
|
|
8737
9003
|
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"
|
|
8738
9004
|
)
|
|
8739
9005
|
);
|
|
8740
9006
|
});
|
|
8741
9007
|
})
|
|
8742
9008
|
);
|
|
8743
|
-
task.command("can-start [id]").description(
|
|
9009
|
+
task.command("can-start [id]").description(
|
|
9010
|
+
"Ask whether work on this task may begin. Refuses until the owner approves."
|
|
9011
|
+
).action(
|
|
8744
9012
|
action(async ({ ctx, args }) => {
|
|
8745
9013
|
const id = resolveTaskId(ctx, args[0]);
|
|
8746
9014
|
const row = await api(
|
|
@@ -8748,7 +9016,7 @@ function registerTask(program3) {
|
|
|
8748
9016
|
`/v1/project-tasks/${encodeURIComponent(id)}/dispatch-check`,
|
|
8749
9017
|
{ method: "POST" }
|
|
8750
9018
|
);
|
|
8751
|
-
ok(row, () => line(
|
|
9019
|
+
ok(row, () => line(import_picocolors29.default.green("approved \u2014 you may start")));
|
|
8752
9020
|
})
|
|
8753
9021
|
);
|
|
8754
9022
|
task.command("start [id]").description(
|
|
@@ -8756,22 +9024,20 @@ function registerTask(program3) {
|
|
|
8756
9024
|
).action(
|
|
8757
9025
|
action(async ({ ctx, args }) => {
|
|
8758
9026
|
const id = resolveTaskId(ctx, args[0]);
|
|
8759
|
-
const row = await api(
|
|
8760
|
-
|
|
8761
|
-
|
|
8762
|
-
{ method: "POST" }
|
|
8763
|
-
);
|
|
9027
|
+
const row = await api(ctx, `/v1/project-tasks/${encodeURIComponent(id)}/start`, {
|
|
9028
|
+
method: "POST"
|
|
9029
|
+
});
|
|
8764
9030
|
ok(row, () => {
|
|
8765
9031
|
const started = row?.started ?? null;
|
|
8766
9032
|
if (started && started > 0) {
|
|
8767
9033
|
line(
|
|
8768
|
-
|
|
9034
|
+
import_picocolors29.default.green(
|
|
8769
9035
|
`started ${started} step${started === 1 ? "" : "s"} \u2014 they are running now`
|
|
8770
9036
|
)
|
|
8771
9037
|
);
|
|
8772
9038
|
return;
|
|
8773
9039
|
}
|
|
8774
|
-
line(
|
|
9040
|
+
line(import_picocolors29.default.yellow(row?.note ?? "Nothing started."));
|
|
8775
9041
|
});
|
|
8776
9042
|
})
|
|
8777
9043
|
);
|
|
@@ -8786,7 +9052,9 @@ function registerTask(program3) {
|
|
|
8786
9052
|
);
|
|
8787
9053
|
ok({ awaiting: row2.approval_state === "awaiting", task: row2 }, () => {
|
|
8788
9054
|
line(
|
|
8789
|
-
row2.approval_state === "awaiting" ?
|
|
9055
|
+
row2.approval_state === "awaiting" ? import_picocolors29.default.yellow(
|
|
9056
|
+
"The plan is waiting on the owner. They see it in the task."
|
|
9057
|
+
) : `Already ${row2.approval_state}.`
|
|
8790
9058
|
);
|
|
8791
9059
|
});
|
|
8792
9060
|
return;
|
|
@@ -8807,7 +9075,10 @@ function registerTask(program3) {
|
|
|
8807
9075
|
}
|
|
8808
9076
|
}
|
|
8809
9077
|
);
|
|
8810
|
-
ok(
|
|
9078
|
+
ok(
|
|
9079
|
+
row,
|
|
9080
|
+
() => line(`${import_picocolors29.default.green(row.approval_state)} ${import_picocolors29.default.bold(row.title)}`)
|
|
9081
|
+
);
|
|
8811
9082
|
})
|
|
8812
9083
|
);
|
|
8813
9084
|
task.command("done [id]").description("Record what a subtask produced, and move it to ready").option("--summary <text>", "what changed, in the owner's words").action(
|
|
@@ -8822,7 +9093,7 @@ function registerTask(program3) {
|
|
|
8822
9093
|
`/v1/project-tasks/${encodeURIComponent(id)}/move`,
|
|
8823
9094
|
{ body: { status: "ready" } }
|
|
8824
9095
|
);
|
|
8825
|
-
ok(row, () => line(`${
|
|
9096
|
+
ok(row, () => line(`${import_picocolors29.default.green("ready")} ${import_picocolors29.default.bold(row.title)}`));
|
|
8826
9097
|
})
|
|
8827
9098
|
);
|
|
8828
9099
|
}
|
|
@@ -8867,24 +9138,24 @@ function assertOneOf(flag, value, allowed) {
|
|
|
8867
9138
|
}
|
|
8868
9139
|
}
|
|
8869
9140
|
function formatRow2(r) {
|
|
8870
|
-
const key =
|
|
8871
|
-
const steps = r.subtaskTotal ?
|
|
8872
|
-
const gate = r.approval_state === "awaiting" ?
|
|
9141
|
+
const key = import_picocolors29.default.dim((r.key ?? r.id.slice(0, 8)).padEnd(10));
|
|
9142
|
+
const steps = r.subtaskTotal ? import_picocolors29.default.dim(` ${r.subtaskDone}/${r.subtaskTotal}`) : "";
|
|
9143
|
+
const gate = r.approval_state === "awaiting" ? import_picocolors29.default.yellow(" awaiting approval") : "";
|
|
8873
9144
|
return `${key} ${statusTag2(r.status)} ${r.title}${steps}${gate}`;
|
|
8874
9145
|
}
|
|
8875
9146
|
function formatSubtask(r, index) {
|
|
8876
|
-
const n =
|
|
8877
|
-
const role = r.role ?
|
|
8878
|
-
const scope = r.scope_paths?.length ?
|
|
9147
|
+
const n = import_picocolors29.default.dim(String(index).padStart(2, "0"));
|
|
9148
|
+
const role = r.role ? import_picocolors29.default.dim(` [${r.role}]`) : "";
|
|
9149
|
+
const scope = r.scope_paths?.length ? import_picocolors29.default.dim(` owns: ${r.scope_paths.join(", ")}`) : "";
|
|
8879
9150
|
const head = `${n} ${statusTag2(r.status)} ${r.title}${role}${scope}`;
|
|
8880
9151
|
const summary = (r.result_summary ?? "").trim();
|
|
8881
9152
|
if (!summary) return head;
|
|
8882
9153
|
const wrapped = summary.split("\n").map((l) => ` ${l}`).join("\n");
|
|
8883
9154
|
return `${head}
|
|
8884
|
-
${
|
|
9155
|
+
${import_picocolors29.default.dim(wrapped)}`;
|
|
8885
9156
|
}
|
|
8886
9157
|
function printTask(row, goal) {
|
|
8887
|
-
line(`${
|
|
9158
|
+
line(`${import_picocolors29.default.bold(row.title)} ${import_picocolors29.default.dim(row.key ?? row.id)}`);
|
|
8888
9159
|
line(`${statusTag2(row.status)} approval: ${row.approval_state}`);
|
|
8889
9160
|
if (row.summary) line(`
|
|
8890
9161
|
${row.summary}`);
|
|
@@ -8897,49 +9168,53 @@ touches: ${row.targets.map((t) => t.appName ?? t.ref ?? t.kind).join(", ")}`
|
|
|
8897
9168
|
}
|
|
8898
9169
|
if (row.subtasks?.length) {
|
|
8899
9170
|
line(`
|
|
8900
|
-
${
|
|
9171
|
+
${import_picocolors29.default.bold("subtasks")}`);
|
|
8901
9172
|
row.subtasks.forEach((s, i) => line(formatSubtask(s, i + 1)));
|
|
8902
9173
|
line(
|
|
8903
|
-
|
|
9174
|
+
import_picocolors29.default.dim(
|
|
8904
9175
|
`
|
|
8905
9176
|
Run \`workser artifact list\` to see what these subtasks produced,`
|
|
8906
9177
|
)
|
|
8907
9178
|
);
|
|
8908
9179
|
line(
|
|
8909
|
-
|
|
9180
|
+
import_picocolors29.default.dim(
|
|
8910
9181
|
`or \`workser artifact list --step <id>\` for one subtask's output alone.`
|
|
8911
9182
|
)
|
|
8912
9183
|
);
|
|
8913
9184
|
} else {
|
|
8914
|
-
line(
|
|
9185
|
+
line(import_picocolors29.default.dim("\nNo subtasks yet."));
|
|
8915
9186
|
}
|
|
8916
9187
|
}
|
|
8917
9188
|
function printGoalContext(row, goal) {
|
|
8918
9189
|
const mine = row.phase ?? null;
|
|
8919
9190
|
line(`
|
|
8920
|
-
${
|
|
8921
|
-
if (goal.outcome) line(
|
|
9191
|
+
${import_picocolors29.default.bold("part of")}: ${goal.title}`);
|
|
9192
|
+
if (goal.outcome) line(import_picocolors29.default.dim(`done means: ${goal.outcome}`));
|
|
8922
9193
|
const progress = goal.progress ?? [];
|
|
8923
9194
|
for (const p of progress) {
|
|
8924
9195
|
const where = p.total === 0 ? "not started" : `${p.done} of ${p.total} done`;
|
|
8925
|
-
const here = mine && p.name === mine ?
|
|
8926
|
-
const mark = p.state === "done" ?
|
|
9196
|
+
const here = mine && p.name === mine ? import_picocolors29.default.cyan(" <- this task") : "";
|
|
9197
|
+
const mark = p.state === "done" ? import_picocolors29.default.green("*") : import_picocolors29.default.dim("-");
|
|
8927
9198
|
line(` ${mark} ${p.name} \u2014 ${where}${here}`);
|
|
8928
9199
|
}
|
|
8929
9200
|
const next = progress.find((p) => p.state !== "done");
|
|
8930
9201
|
const running = progress.some((p) => p.state === "working");
|
|
8931
9202
|
if (next && !running) {
|
|
8932
9203
|
line(
|
|
8933
|
-
|
|
9204
|
+
import_picocolors29.default.dim(
|
|
8934
9205
|
`
|
|
8935
9206
|
Nothing is running. The next part waiting is "${next.name}" \u2014 offer it to them in a sentence rather than starting it unasked.`
|
|
8936
9207
|
)
|
|
8937
9208
|
);
|
|
8938
9209
|
} else if (!next) {
|
|
8939
|
-
line(
|
|
9210
|
+
line(
|
|
9211
|
+
import_picocolors29.default.dim(
|
|
9212
|
+
"\nEvery part of this plan is done. Say so, and offer to wrap it up."
|
|
9213
|
+
)
|
|
9214
|
+
);
|
|
8940
9215
|
}
|
|
8941
9216
|
line(
|
|
8942
|
-
|
|
9217
|
+
import_picocolors29.default.dim(
|
|
8943
9218
|
"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."
|
|
8944
9219
|
)
|
|
8945
9220
|
);
|
|
@@ -8947,22 +9222,22 @@ Nothing is running. The next part waiting is "${next.name}" \u2014 offer it to t
|
|
|
8947
9222
|
function statusTag2(status) {
|
|
8948
9223
|
switch (status) {
|
|
8949
9224
|
case "ready":
|
|
8950
|
-
return
|
|
9225
|
+
return import_picocolors29.default.green("[ready]");
|
|
8951
9226
|
case "working":
|
|
8952
|
-
return
|
|
9227
|
+
return import_picocolors29.default.blue("[working]");
|
|
8953
9228
|
case "checking":
|
|
8954
|
-
return
|
|
9229
|
+
return import_picocolors29.default.cyan("[checking]");
|
|
8955
9230
|
case "accepted":
|
|
8956
|
-
return
|
|
9231
|
+
return import_picocolors29.default.green("[accepted]");
|
|
8957
9232
|
case "archived":
|
|
8958
|
-
return
|
|
9233
|
+
return import_picocolors29.default.dim("[archived]");
|
|
8959
9234
|
default:
|
|
8960
|
-
return
|
|
9235
|
+
return import_picocolors29.default.dim("[todo]");
|
|
8961
9236
|
}
|
|
8962
9237
|
}
|
|
8963
9238
|
|
|
8964
9239
|
// src/commands/goal.ts
|
|
8965
|
-
var
|
|
9240
|
+
var import_picocolors30 = __toESM(require_picocolors(), 1);
|
|
8966
9241
|
var STATUSES3 = ["proposed", "agreed", "working", "delivered", "abandoned"];
|
|
8967
9242
|
function registerGoal(program3) {
|
|
8968
9243
|
const goal = program3.command("goal").description("Business goals and the phases that deliver them");
|
|
@@ -8974,7 +9249,7 @@ function registerGoal(program3) {
|
|
|
8974
9249
|
}) ?? [];
|
|
8975
9250
|
ok(rows, () => {
|
|
8976
9251
|
if (!rows.length) {
|
|
8977
|
-
line(
|
|
9252
|
+
line(import_picocolors30.default.dim("No goals yet \u2014 every task here stands on its own."));
|
|
8978
9253
|
return;
|
|
8979
9254
|
}
|
|
8980
9255
|
for (const g of rows) line(formatGoal(g));
|
|
@@ -9051,10 +9326,10 @@ function registerGoal(program3) {
|
|
|
9051
9326
|
}
|
|
9052
9327
|
});
|
|
9053
9328
|
ok(row, () => {
|
|
9054
|
-
success(`Proposed ${
|
|
9329
|
+
success(`Proposed ${import_picocolors30.default.bold(row?.title ?? "goal")}`);
|
|
9055
9330
|
printGoal(row);
|
|
9056
9331
|
line(
|
|
9057
|
-
|
|
9332
|
+
import_picocolors30.default.dim(
|
|
9058
9333
|
"\nNothing has been created yet. The owner agrees the shape first."
|
|
9059
9334
|
)
|
|
9060
9335
|
);
|
|
@@ -9083,7 +9358,7 @@ function registerGoal(program3) {
|
|
|
9083
9358
|
ok(
|
|
9084
9359
|
row,
|
|
9085
9360
|
() => line(
|
|
9086
|
-
row?.recorded ? met === true ?
|
|
9361
|
+
row?.recorded ? met === true ? import_picocolors30.default.green("recorded \u2014 met") : met === false ? import_picocolors30.default.yellow("recorded \u2014 not met") : import_picocolors30.default.dim("recorded \u2014 back to unchecked") : import_picocolors30.default.yellow(
|
|
9087
9362
|
"couldn't record it \u2014 check the goal id, the phase name and the criterion id"
|
|
9088
9363
|
)
|
|
9089
9364
|
)
|
|
@@ -9117,42 +9392,42 @@ function registerGoal(program3) {
|
|
|
9117
9392
|
function appScope(g) {
|
|
9118
9393
|
const n = g.appIds?.length ?? 0;
|
|
9119
9394
|
if (!n) return "";
|
|
9120
|
-
return
|
|
9395
|
+
return import_picocolors30.default.dim(` ${n} part${n === 1 ? "" : "s"} of the system`);
|
|
9121
9396
|
}
|
|
9122
9397
|
function formatGoal(g) {
|
|
9123
|
-
const where = g.currentPhase && g.status !== "delivered" ?
|
|
9124
|
-
const count = g.taskTotal != null ?
|
|
9125
|
-
return `${statusTag3(g.status)} ${g.title}${appScope(g)}${where}${count} ${
|
|
9398
|
+
const where = g.currentPhase && g.status !== "delivered" ? import_picocolors30.default.dim(` now: ${g.currentPhase}`) : "";
|
|
9399
|
+
const count = g.taskTotal != null ? import_picocolors30.default.dim(` ${g.taskDone}/${g.taskTotal} done`) : "";
|
|
9400
|
+
return `${statusTag3(g.status)} ${g.title}${appScope(g)}${where}${count} ${import_picocolors30.default.dim(g.id)}`;
|
|
9126
9401
|
}
|
|
9127
9402
|
function printGoal(g) {
|
|
9128
9403
|
if (!g) return;
|
|
9129
|
-
line(`${
|
|
9404
|
+
line(`${import_picocolors30.default.bold(g.title)} ${import_picocolors30.default.dim(g.id)}`);
|
|
9130
9405
|
line(statusTag3(g.status));
|
|
9131
9406
|
if (g.outcome) line(`
|
|
9132
9407
|
done means: ${g.outcome}`);
|
|
9133
9408
|
const progress = g.progress ?? [];
|
|
9134
9409
|
if (!progress.length) {
|
|
9135
|
-
line(
|
|
9410
|
+
line(import_picocolors30.default.dim("\nNo phases agreed yet."));
|
|
9136
9411
|
return;
|
|
9137
9412
|
}
|
|
9138
9413
|
line(`
|
|
9139
|
-
${
|
|
9414
|
+
${import_picocolors30.default.bold("phases")}`);
|
|
9140
9415
|
for (const p of progress) {
|
|
9141
|
-
const bar2 = p.total > 0 ? `${p.done}/${p.total} done` :
|
|
9142
|
-
const mark = p.state === "done" ?
|
|
9416
|
+
const bar2 = p.total > 0 ? `${p.done}/${p.total} done` : import_picocolors30.default.dim("nothing filed yet");
|
|
9417
|
+
const mark = p.state === "done" ? import_picocolors30.default.green("done") : p.state === "working" ? import_picocolors30.default.blue("working") : import_picocolors30.default.dim("waiting");
|
|
9143
9418
|
line(
|
|
9144
|
-
` ${
|
|
9419
|
+
` ${import_picocolors30.default.dim(String(p.index).padStart(2, "0"))} ${p.name} ${mark} ${import_picocolors30.default.dim(bar2)}`
|
|
9145
9420
|
);
|
|
9146
9421
|
for (const c of p.criteria ?? []) {
|
|
9147
|
-
const tick = c.met === true ?
|
|
9148
|
-
line(` ${tick} ${c.text} ${
|
|
9149
|
-
if (c.note) line(
|
|
9422
|
+
const tick = c.met === true ? import_picocolors30.default.green("\u2713") : c.met === false ? import_picocolors30.default.red("\u2717") : import_picocolors30.default.dim("\xB7");
|
|
9423
|
+
line(` ${tick} ${c.text} ${import_picocolors30.default.dim(c.id)}`);
|
|
9424
|
+
if (c.note) line(import_picocolors30.default.dim(` ${c.note}`));
|
|
9150
9425
|
}
|
|
9151
9426
|
}
|
|
9152
9427
|
const current = progress.find((p) => p.name === g.currentPhase);
|
|
9153
9428
|
if (current) {
|
|
9154
9429
|
line(
|
|
9155
|
-
|
|
9430
|
+
import_picocolors30.default.dim(
|
|
9156
9431
|
`
|
|
9157
9432
|
${current.name} \u2014 ${current.done} of ${current.total} done (phase ${current.index} of ${progress.length}).`
|
|
9158
9433
|
)
|
|
@@ -9162,15 +9437,15 @@ ${current.name} \u2014 ${current.done} of ${current.total} done (phase ${current
|
|
|
9162
9437
|
function statusTag3(status) {
|
|
9163
9438
|
switch (status) {
|
|
9164
9439
|
case "agreed":
|
|
9165
|
-
return
|
|
9440
|
+
return import_picocolors30.default.cyan("[agreed]");
|
|
9166
9441
|
case "working":
|
|
9167
|
-
return
|
|
9442
|
+
return import_picocolors30.default.blue("[working]");
|
|
9168
9443
|
case "delivered":
|
|
9169
|
-
return
|
|
9444
|
+
return import_picocolors30.default.green("[delivered]");
|
|
9170
9445
|
case "abandoned":
|
|
9171
|
-
return
|
|
9446
|
+
return import_picocolors30.default.dim("[abandoned]");
|
|
9172
9447
|
default:
|
|
9173
|
-
return
|
|
9448
|
+
return import_picocolors30.default.yellow("[proposed]");
|
|
9174
9449
|
}
|
|
9175
9450
|
}
|
|
9176
9451
|
|
|
@@ -9345,7 +9620,7 @@ function stripLeadingGlobalOptions(argv) {
|
|
|
9345
9620
|
}
|
|
9346
9621
|
|
|
9347
9622
|
// src/commands/decision.ts
|
|
9348
|
-
var
|
|
9623
|
+
var import_picocolors31 = __toESM(require_picocolors(), 1);
|
|
9349
9624
|
function registerDecision(program3) {
|
|
9350
9625
|
const decision = program3.command("decision").description("Read and record the project's architecture decisions");
|
|
9351
9626
|
decision.command("list").description("Every decision on record \u2014 read this before changing how something works").option("--limit <n>", "cap the number returned (newest first)").action(
|
|
@@ -9358,11 +9633,11 @@ function registerDecision(program3) {
|
|
|
9358
9633
|
rows = applyLimit(rows, opts.limit);
|
|
9359
9634
|
ok(rows, () => {
|
|
9360
9635
|
if (!rows.length) {
|
|
9361
|
-
line(
|
|
9636
|
+
line(import_picocolors31.default.dim("No decisions recorded yet."));
|
|
9362
9637
|
return;
|
|
9363
9638
|
}
|
|
9364
9639
|
for (const r of rows) {
|
|
9365
|
-
line(`${
|
|
9640
|
+
line(`${import_picocolors31.default.dim(r.id)} ${import_picocolors31.default.dim(shortDate(r.createdAt))} ${r.title}`);
|
|
9366
9641
|
line(` ${truncate(r.decision, 100)}`);
|
|
9367
9642
|
}
|
|
9368
9643
|
});
|
|
@@ -9376,16 +9651,16 @@ function registerDecision(program3) {
|
|
|
9376
9651
|
`/v1/projects/${projectId}/architecture-decisions/${args[0]}`
|
|
9377
9652
|
);
|
|
9378
9653
|
ok(row, () => {
|
|
9379
|
-
line(`${
|
|
9380
|
-
line(
|
|
9654
|
+
line(`${import_picocolors31.default.bold(row.title)} ${import_picocolors31.default.dim(row.id)}`);
|
|
9655
|
+
line(import_picocolors31.default.dim(`${row.status} \xB7 ${shortDate(row.createdAt)}`));
|
|
9381
9656
|
line(`
|
|
9382
|
-
${
|
|
9657
|
+
${import_picocolors31.default.bold("Context")}
|
|
9383
9658
|
${row.context}`);
|
|
9384
9659
|
line(`
|
|
9385
|
-
${
|
|
9660
|
+
${import_picocolors31.default.bold("Decision")}
|
|
9386
9661
|
${row.decision}`);
|
|
9387
9662
|
if (row.consequences) line(`
|
|
9388
|
-
${
|
|
9663
|
+
${import_picocolors31.default.bold("Consequences")}
|
|
9389
9664
|
${row.consequences}`);
|
|
9390
9665
|
});
|
|
9391
9666
|
})
|
|
@@ -9414,7 +9689,7 @@ ${row.consequences}`);
|
|
|
9414
9689
|
refId: row?.id,
|
|
9415
9690
|
output: { decision: row }
|
|
9416
9691
|
});
|
|
9417
|
-
ok(row, () => line(`Recorded decision ${
|
|
9692
|
+
ok(row, () => line(`Recorded decision ${import_picocolors31.default.bold(row?.id ?? "")} \u2014 ${title}`));
|
|
9418
9693
|
})
|
|
9419
9694
|
);
|
|
9420
9695
|
const requirement = program3.command("requirement").description("Read and record the project's requirements");
|
|
@@ -9426,11 +9701,11 @@ ${row.consequences}`);
|
|
|
9426
9701
|
rows = applyLimit(rows, opts.limit);
|
|
9427
9702
|
ok(rows, () => {
|
|
9428
9703
|
if (!rows.length) {
|
|
9429
|
-
line(
|
|
9704
|
+
line(import_picocolors31.default.dim("No requirements recorded yet."));
|
|
9430
9705
|
return;
|
|
9431
9706
|
}
|
|
9432
9707
|
for (const r of rows) {
|
|
9433
|
-
line(`${
|
|
9708
|
+
line(`${import_picocolors31.default.dim(r.id)} ${r.status.padEnd(9)} ${r.title}`);
|
|
9434
9709
|
}
|
|
9435
9710
|
});
|
|
9436
9711
|
})
|
|
@@ -9443,8 +9718,8 @@ ${row.consequences}`);
|
|
|
9443
9718
|
`/v1/projects/${projectId}/requirements/${args[0]}`
|
|
9444
9719
|
);
|
|
9445
9720
|
ok(row, () => {
|
|
9446
|
-
line(`${
|
|
9447
|
-
line(
|
|
9721
|
+
line(`${import_picocolors31.default.bold(row.title)} ${import_picocolors31.default.dim(row.id)}`);
|
|
9722
|
+
line(import_picocolors31.default.dim(`${row.status} \xB7 ${shortDate(row.createdAt)}`));
|
|
9448
9723
|
line(`
|
|
9449
9724
|
${row.body}`);
|
|
9450
9725
|
});
|
|
@@ -9470,7 +9745,7 @@ ${row.body}`);
|
|
|
9470
9745
|
refId: row?.id,
|
|
9471
9746
|
output: { requirement: row }
|
|
9472
9747
|
});
|
|
9473
|
-
ok(row, () => line(`Recorded requirement ${
|
|
9748
|
+
ok(row, () => line(`Recorded requirement ${import_picocolors31.default.bold(row?.id ?? "")} \u2014 ${title}`));
|
|
9474
9749
|
})
|
|
9475
9750
|
);
|
|
9476
9751
|
requirement.command("update <id>").description(
|
|
@@ -9499,7 +9774,7 @@ ${row.body}`);
|
|
|
9499
9774
|
code: "bad_request"
|
|
9500
9775
|
});
|
|
9501
9776
|
}
|
|
9502
|
-
ok(row, () => line(`Updated requirement ${
|
|
9777
|
+
ok(row, () => line(`Updated requirement ${import_picocolors31.default.bold(row.id)} \u2014 ${row.title} (${row.status})`));
|
|
9503
9778
|
})
|
|
9504
9779
|
);
|
|
9505
9780
|
}
|
|
@@ -9522,7 +9797,7 @@ function shortDate(iso) {
|
|
|
9522
9797
|
}
|
|
9523
9798
|
|
|
9524
9799
|
// src/commands/doc.ts
|
|
9525
|
-
var
|
|
9800
|
+
var import_picocolors32 = __toESM(require_picocolors(), 1);
|
|
9526
9801
|
|
|
9527
9802
|
// src/mermaid-fences.ts
|
|
9528
9803
|
function hasDiagram(code) {
|
|
@@ -9567,13 +9842,13 @@ function registerDoc(program3) {
|
|
|
9567
9842
|
}) ?? [];
|
|
9568
9843
|
ok(rows, () => {
|
|
9569
9844
|
if (!rows.length) {
|
|
9570
|
-
line(
|
|
9845
|
+
line(import_picocolors32.default.dim("No documents yet."));
|
|
9571
9846
|
return;
|
|
9572
9847
|
}
|
|
9573
9848
|
for (const r of rows) {
|
|
9574
|
-
const link = r.workItemId ?
|
|
9575
|
-
const file = r.filePath ?
|
|
9576
|
-
line(`${
|
|
9849
|
+
const link = r.workItemId ? import_picocolors32.default.dim(` \u21B3 ${r.workItemId}`) : "";
|
|
9850
|
+
const file = r.filePath ? import_picocolors32.default.dim(` ${r.filePath}`) : "";
|
|
9851
|
+
line(`${import_picocolors32.default.dim(r.id)} ${r.title}${link}${file}`);
|
|
9577
9852
|
}
|
|
9578
9853
|
});
|
|
9579
9854
|
})
|
|
@@ -9587,17 +9862,17 @@ function registerDoc(program3) {
|
|
|
9587
9862
|
);
|
|
9588
9863
|
if (opts.markdown) {
|
|
9589
9864
|
ok({ id: row.id, title: row.title, filePath: row.filePath }, () => {
|
|
9590
|
-
line(`${
|
|
9865
|
+
line(`${import_picocolors32.default.bold(row.title)} ${import_picocolors32.default.dim(row.id)}`);
|
|
9591
9866
|
line(
|
|
9592
|
-
row.filePath ? `Read it at ${
|
|
9867
|
+
row.filePath ? `Read it at ${import_picocolors32.default.bold(row.filePath)} (relative to the project folder).` : import_picocolors32.default.dim("This document has no markdown mirror on disk yet.")
|
|
9593
9868
|
);
|
|
9594
9869
|
});
|
|
9595
9870
|
return;
|
|
9596
9871
|
}
|
|
9597
9872
|
ok(row, () => {
|
|
9598
|
-
line(`${
|
|
9599
|
-
if (row.workItemId) line(
|
|
9600
|
-
if (row.filePath) line(
|
|
9873
|
+
line(`${import_picocolors32.default.bold(row.title)} ${import_picocolors32.default.dim(row.id)}`);
|
|
9874
|
+
if (row.workItemId) line(import_picocolors32.default.dim(`linked to work item ${row.workItemId}`));
|
|
9875
|
+
if (row.filePath) line(import_picocolors32.default.dim(`markdown mirror: ${row.filePath}`));
|
|
9601
9876
|
line("");
|
|
9602
9877
|
line(row.contentJson);
|
|
9603
9878
|
});
|
|
@@ -9626,7 +9901,7 @@ function registerDoc(program3) {
|
|
|
9626
9901
|
refId: row?.id,
|
|
9627
9902
|
output: { document: row }
|
|
9628
9903
|
});
|
|
9629
|
-
ok(row, () => line(`Created document ${
|
|
9904
|
+
ok(row, () => line(`Created document ${import_picocolors32.default.bold(row?.id ?? "")} \u2014 ${title}`));
|
|
9630
9905
|
})
|
|
9631
9906
|
);
|
|
9632
9907
|
doc.command("diagram <id>").description(
|
|
@@ -9652,19 +9927,19 @@ function registerDoc(program3) {
|
|
|
9652
9927
|
diagrams: diagrams.map((code) => ({ kind: diagramKind(code), code }))
|
|
9653
9928
|
};
|
|
9654
9929
|
ok(payload, () => {
|
|
9655
|
-
line(`${
|
|
9930
|
+
line(`${import_picocolors32.default.bold(row.title)} ${import_picocolors32.default.dim(row.id)}`);
|
|
9656
9931
|
if (markdown === null) {
|
|
9657
9932
|
line(
|
|
9658
|
-
|
|
9933
|
+
import_picocolors32.default.dim(
|
|
9659
9934
|
row.filePath ? `Could not read ${row.filePath} from this folder.` : "This document has no markdown mirror on disk yet."
|
|
9660
9935
|
)
|
|
9661
9936
|
);
|
|
9662
9937
|
} else if (!diagrams.length) {
|
|
9663
|
-
line(
|
|
9938
|
+
line(import_picocolors32.default.dim("No diagrams in this document."));
|
|
9664
9939
|
} else {
|
|
9665
9940
|
for (const [i, code] of diagrams.entries()) {
|
|
9666
9941
|
const kind = diagramKind(code) ?? "diagram";
|
|
9667
|
-
line(`${
|
|
9942
|
+
line(`${import_picocolors32.default.dim(String(i + 1))} ${kind} ${import_picocolors32.default.dim(`${code.split("\n").length} lines`)}`);
|
|
9668
9943
|
}
|
|
9669
9944
|
}
|
|
9670
9945
|
});
|
|
@@ -9700,7 +9975,7 @@ function registerDoc(program3) {
|
|
|
9700
9975
|
code: "bad_request"
|
|
9701
9976
|
});
|
|
9702
9977
|
}
|
|
9703
|
-
ok(row, () => line(`Updated document ${
|
|
9978
|
+
ok(row, () => line(`Updated document ${import_picocolors32.default.bold(row.id)} \u2014 ${row.title}`));
|
|
9704
9979
|
})
|
|
9705
9980
|
);
|
|
9706
9981
|
}
|
|
@@ -9714,7 +9989,7 @@ function readMirror(cwd, filePath) {
|
|
|
9714
9989
|
}
|
|
9715
9990
|
|
|
9716
9991
|
// src/commands/design.ts
|
|
9717
|
-
var
|
|
9992
|
+
var import_picocolors33 = __toESM(require_picocolors(), 1);
|
|
9718
9993
|
function registerDesign(program3) {
|
|
9719
9994
|
const design = program3.command("design").description("Read the project's brand (colours, fonts, logo)");
|
|
9720
9995
|
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(
|
|
@@ -9728,11 +10003,11 @@ function registerDesign(program3) {
|
|
|
9728
10003
|
if (opts.raw) {
|
|
9729
10004
|
ok(files, () => {
|
|
9730
10005
|
if (!files.length) {
|
|
9731
|
-
line(
|
|
10006
|
+
line(import_picocolors33.default.dim("No brand set for this project."));
|
|
9732
10007
|
return;
|
|
9733
10008
|
}
|
|
9734
10009
|
for (const f of files) {
|
|
9735
|
-
line(
|
|
10010
|
+
line(import_picocolors33.default.bold(f.path));
|
|
9736
10011
|
line(f.contents);
|
|
9737
10012
|
line("");
|
|
9738
10013
|
}
|
|
@@ -9749,21 +10024,21 @@ function registerDesign(program3) {
|
|
|
9749
10024
|
} : { hasBrand: false, colors: {}, fonts: {}, brand: {}, files: [] };
|
|
9750
10025
|
ok(summary, () => {
|
|
9751
10026
|
if (!tokens) {
|
|
9752
|
-
line(
|
|
10027
|
+
line(import_picocolors33.default.dim("No brand set for this project \u2014 choose sensible styling yourself."));
|
|
9753
10028
|
return;
|
|
9754
10029
|
}
|
|
9755
10030
|
for (const [name, value] of Object.entries(tokens.brand)) {
|
|
9756
|
-
line(`${
|
|
10031
|
+
line(`${import_picocolors33.default.dim(name.padEnd(12))} ${value}`);
|
|
9757
10032
|
}
|
|
9758
10033
|
for (const [name, value] of Object.entries(tokens.color)) {
|
|
9759
|
-
line(`${
|
|
10034
|
+
line(`${import_picocolors33.default.dim(`color.${name}`.padEnd(12))} ${value}`);
|
|
9760
10035
|
}
|
|
9761
10036
|
for (const [name, value] of Object.entries(tokens.font)) {
|
|
9762
|
-
line(`${
|
|
10037
|
+
line(`${import_picocolors33.default.dim(`font.${name}`.padEnd(12))} ${value}`);
|
|
9763
10038
|
}
|
|
9764
10039
|
line("");
|
|
9765
10040
|
line(
|
|
9766
|
-
|
|
10041
|
+
import_picocolors33.default.dim(
|
|
9767
10042
|
`Generated into the working tree as ${files.map((f) => f.path).join(", ")} \u2014 wire those in, never edit them.`
|
|
9768
10043
|
)
|
|
9769
10044
|
);
|
|
@@ -9794,7 +10069,7 @@ function unwrap(group) {
|
|
|
9794
10069
|
}
|
|
9795
10070
|
|
|
9796
10071
|
// src/commands/api.ts
|
|
9797
|
-
var
|
|
10072
|
+
var import_picocolors34 = __toESM(require_picocolors(), 1);
|
|
9798
10073
|
import { readdirSync, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
|
|
9799
10074
|
import { join as join3, relative, sep } from "path";
|
|
9800
10075
|
|
|
@@ -9905,13 +10180,13 @@ function registerApi(program3) {
|
|
|
9905
10180
|
const cmd = program3.command("api").description("Call this service and check it describes its own routes");
|
|
9906
10181
|
cmd.command("list").description("The requests saved with this service, in api/requests.json").option("--app <webAppId>", "the service, when this folder holds more than one").action(
|
|
9907
10182
|
action(async ({ ctx, opts }) => {
|
|
9908
|
-
const appId =
|
|
10183
|
+
const appId = requireApp2(opts.app);
|
|
9909
10184
|
const res = await api(ctx, `/v1/apps/${encodeURIComponent(appId)}/api/requests`);
|
|
9910
10185
|
ok(res, () => {
|
|
9911
|
-
for (const note of res?.notes ?? []) line(
|
|
10186
|
+
for (const note of res?.notes ?? []) line(import_picocolors34.default.dim(note));
|
|
9912
10187
|
for (const r of res?.requests ?? []) {
|
|
9913
10188
|
line(
|
|
9914
|
-
`${
|
|
10189
|
+
`${import_picocolors34.default.dim(r.method.padEnd(6))}${r.path}${r.note ? import_picocolors34.default.dim(` ${r.note}`) : ""}`
|
|
9915
10190
|
);
|
|
9916
10191
|
}
|
|
9917
10192
|
});
|
|
@@ -9929,7 +10204,7 @@ function registerApi(program3) {
|
|
|
9929
10204
|
"local (default), preview or production \u2014 the host comes from here, never from the path"
|
|
9930
10205
|
).action(
|
|
9931
10206
|
action(async ({ ctx, args, opts }) => {
|
|
9932
|
-
const appId =
|
|
10207
|
+
const appId = requireApp2(opts.app);
|
|
9933
10208
|
const res = await api(
|
|
9934
10209
|
ctx,
|
|
9935
10210
|
`/v1/apps/${encodeURIComponent(appId)}/api/call`,
|
|
@@ -9945,14 +10220,14 @@ function registerApi(program3) {
|
|
|
9945
10220
|
);
|
|
9946
10221
|
ok(res, () => {
|
|
9947
10222
|
if (!res?.ok) {
|
|
9948
|
-
line(
|
|
10223
|
+
line(import_picocolors34.default.red(res?.error ?? "The service did not answer."));
|
|
9949
10224
|
return;
|
|
9950
10225
|
}
|
|
9951
10226
|
const code = `${res.status}${res.statusText ? ` ${res.statusText}` : ""}`;
|
|
9952
|
-
const colour2 = res.status && res.status < 300 ?
|
|
9953
|
-
line(`${colour2(code)} ${
|
|
10227
|
+
const colour2 = res.status && res.status < 300 ? import_picocolors34.default.green : res.status && res.status < 500 ? import_picocolors34.default.yellow : import_picocolors34.default.red;
|
|
10228
|
+
line(`${colour2(code)} ${import_picocolors34.default.dim(`${res.durationMs}ms ${res.url}`)}`);
|
|
9954
10229
|
if (res.body) line(res.body);
|
|
9955
|
-
if (res.truncated) line(
|
|
10230
|
+
if (res.truncated) line(import_picocolors34.default.dim("(answer truncated)"));
|
|
9956
10231
|
});
|
|
9957
10232
|
if (!res?.ok) process.exitCode = 1;
|
|
9958
10233
|
})
|
|
@@ -9972,15 +10247,15 @@ function registerApi(program3) {
|
|
|
9972
10247
|
for (const r of report.routes) {
|
|
9973
10248
|
const known = report.missing.some((m) => m.path === r.path);
|
|
9974
10249
|
line(
|
|
9975
|
-
`${known ?
|
|
10250
|
+
`${known ? import_picocolors34.default.yellow("undocumented") : import_picocolors34.default.green("documented ")} ${r.path}${import_picocolors34.default.dim(` ${r.file}`)}`
|
|
9976
10251
|
);
|
|
9977
10252
|
}
|
|
9978
10253
|
for (const p of report.stale) {
|
|
9979
|
-
line(`${
|
|
10254
|
+
line(`${import_picocolors34.default.dim("in spec only ")} ${p}`);
|
|
9980
10255
|
}
|
|
9981
10256
|
line("");
|
|
9982
10257
|
if (report.ok && specFile) success(summary);
|
|
9983
|
-
else line(
|
|
10258
|
+
else line(import_picocolors34.default.yellow(summary));
|
|
9984
10259
|
});
|
|
9985
10260
|
if (opts.check && !report.ok) {
|
|
9986
10261
|
throw new WorkserError(summary, { code: "bad_request" });
|
|
@@ -9996,7 +10271,7 @@ function collectHeader(raw, previous) {
|
|
|
9996
10271
|
if (at <= 0) return previous;
|
|
9997
10272
|
return { ...previous, [raw.slice(0, at).trim()]: raw.slice(at + 1).trim() };
|
|
9998
10273
|
}
|
|
9999
|
-
function
|
|
10274
|
+
function requireApp2(app) {
|
|
10000
10275
|
const value = typeof app === "string" ? app.trim() : "";
|
|
10001
10276
|
if (value) return value;
|
|
10002
10277
|
throw new WorkserError(
|
|
@@ -10051,7 +10326,7 @@ function listRepoFiles(root, maxDepth = 8) {
|
|
|
10051
10326
|
}
|
|
10052
10327
|
|
|
10053
10328
|
// src/commands/analysis.ts
|
|
10054
|
-
var
|
|
10329
|
+
var import_picocolors35 = __toESM(require_picocolors(), 1);
|
|
10055
10330
|
import { readFileSync as readFileSync4 } from "fs";
|
|
10056
10331
|
function registerAnalysis(program3) {
|
|
10057
10332
|
const cmd = program3.command("analysis").description("Run Python analysis locally, recorded in the task");
|
|
@@ -10061,14 +10336,14 @@ function registerAnalysis(program3) {
|
|
|
10061
10336
|
const res = await api(ctx, path);
|
|
10062
10337
|
ok(res, () => {
|
|
10063
10338
|
line(
|
|
10064
|
-
`${res?.available ?
|
|
10339
|
+
`${res?.available ? import_picocolors35.default.green("python") : import_picocolors35.default.red("python")} ${res?.version ?? "not found"} ${import_picocolors35.default.dim(res?.python ?? "")}`
|
|
10065
10340
|
);
|
|
10066
10341
|
for (const lib of res?.libraries ?? []) {
|
|
10067
10342
|
line(
|
|
10068
|
-
`${lib.present ?
|
|
10343
|
+
`${lib.present ? import_picocolors35.default.green(lib.name) : import_picocolors35.default.yellow(lib.name)}${import_picocolors35.default.dim(lib.present ? "" : " missing")}`
|
|
10069
10344
|
);
|
|
10070
10345
|
}
|
|
10071
|
-
for (const note of res?.notes ?? []) line(
|
|
10346
|
+
for (const note of res?.notes ?? []) line(import_picocolors35.default.dim(note));
|
|
10072
10347
|
});
|
|
10073
10348
|
if (!res?.available) process.exitCode = 1;
|
|
10074
10349
|
})
|
|
@@ -10090,15 +10365,15 @@ function registerAnalysis(program3) {
|
|
|
10090
10365
|
);
|
|
10091
10366
|
ok(res, () => {
|
|
10092
10367
|
if (res?.stdout) line(res.stdout.replace(/\n$/, ""));
|
|
10093
|
-
if (res?.stderr) line(
|
|
10094
|
-
if (res?.truncated) line(
|
|
10368
|
+
if (res?.stderr) line(import_picocolors35.default.dim(res.stderr.replace(/\n$/, "")));
|
|
10369
|
+
if (res?.truncated) line(import_picocolors35.default.dim("(output truncated)"));
|
|
10095
10370
|
const took = `${Math.round((res?.durationMs ?? 0) / 100) / 10}s`;
|
|
10096
10371
|
line(
|
|
10097
|
-
res?.ok ?
|
|
10372
|
+
res?.ok ? import_picocolors35.default.green(`\u2713 ${res.summary ?? "It finished."}`) + import_picocolors35.default.dim(` ${took}`) : import_picocolors35.default.yellow(res?.summary ?? "It did not finish.") + import_picocolors35.default.dim(` ${took}`)
|
|
10098
10373
|
);
|
|
10099
10374
|
if (res && !res.sandboxed) {
|
|
10100
10375
|
line(
|
|
10101
|
-
|
|
10376
|
+
import_picocolors35.default.dim(
|
|
10102
10377
|
"This platform has no OS sandbox, so the script ran with your own file access."
|
|
10103
10378
|
)
|
|
10104
10379
|
);
|
|
@@ -10126,7 +10401,7 @@ function readCode(file, inline) {
|
|
|
10126
10401
|
}
|
|
10127
10402
|
|
|
10128
10403
|
// src/commands/scan.ts
|
|
10129
|
-
var
|
|
10404
|
+
var import_picocolors36 = __toESM(require_picocolors(), 1);
|
|
10130
10405
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
10131
10406
|
import { existsSync as existsSync3, readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync3 } from "fs";
|
|
10132
10407
|
import { join as join4, relative as relative2, sep as sep2 } from "path";
|
|
@@ -10410,22 +10685,22 @@ function runPermissions(cwd, findings, checked, skipped) {
|
|
|
10410
10685
|
}
|
|
10411
10686
|
function print2(report, summary) {
|
|
10412
10687
|
for (const s of report.skipped) {
|
|
10413
|
-
line(`${
|
|
10688
|
+
line(`${import_picocolors36.default.yellow("not checked")} ${s.check}${import_picocolors36.default.dim(` \u2014 ${s.reason}`)}`);
|
|
10414
10689
|
}
|
|
10415
10690
|
for (const f of report.findings) {
|
|
10416
|
-
const where = f.file ?
|
|
10691
|
+
const where = f.file ? import_picocolors36.default.dim(` ${f.file}${f.line ? `:${f.line}` : ""}`) : "";
|
|
10417
10692
|
line(`${severityTag(f.severity)} ${f.title}${where}`);
|
|
10418
|
-
line(` ${
|
|
10693
|
+
line(` ${import_picocolors36.default.dim(f.fix)}`);
|
|
10419
10694
|
}
|
|
10420
10695
|
if (report.findings.length || report.skipped.length) line("");
|
|
10421
10696
|
if (report.ok && !report.skipped.length) success(summary);
|
|
10422
|
-
else if (report.ok) line(
|
|
10423
|
-
else line(
|
|
10697
|
+
else if (report.ok) line(import_picocolors36.default.yellow(summary));
|
|
10698
|
+
else line(import_picocolors36.default.red(summary));
|
|
10424
10699
|
}
|
|
10425
10700
|
function severityTag(severity) {
|
|
10426
|
-
if (severity === "high") return
|
|
10427
|
-
if (severity === "medium") return
|
|
10428
|
-
return
|
|
10701
|
+
if (severity === "high") return import_picocolors36.default.red("serious ");
|
|
10702
|
+
if (severity === "medium") return import_picocolors36.default.yellow("worth fixing");
|
|
10703
|
+
return import_picocolors36.default.dim("minor ");
|
|
10429
10704
|
}
|
|
10430
10705
|
function git(cwd, args) {
|
|
10431
10706
|
try {
|
|
@@ -10486,7 +10761,7 @@ function listRepoFiles2(root, maxDepth = 8) {
|
|
|
10486
10761
|
}
|
|
10487
10762
|
|
|
10488
10763
|
// src/commands/health.ts
|
|
10489
|
-
var
|
|
10764
|
+
var import_picocolors37 = __toESM(require_picocolors(), 1);
|
|
10490
10765
|
function registerHealth(program3) {
|
|
10491
10766
|
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(
|
|
10492
10767
|
action(async ({ ctx, opts }) => {
|
|
@@ -10500,16 +10775,16 @@ function registerHealth(program3) {
|
|
|
10500
10775
|
}
|
|
10501
10776
|
function print3(res) {
|
|
10502
10777
|
if (!res?.checks?.length) {
|
|
10503
|
-
line(
|
|
10778
|
+
line(import_picocolors37.default.dim(res?.note ?? "Nothing to check."));
|
|
10504
10779
|
return;
|
|
10505
10780
|
}
|
|
10506
10781
|
for (const c of res.checks) {
|
|
10507
|
-
const mark = c.ok ?
|
|
10508
|
-
const timing =
|
|
10509
|
-
const detail = c.ok ? timing :
|
|
10510
|
-
line(` ${mark} ${c.appName} ${
|
|
10782
|
+
const mark = c.ok ? import_picocolors37.default.green("up ") : import_picocolors37.default.red("down");
|
|
10783
|
+
const timing = import_picocolors37.default.dim(`${c.ms}ms`);
|
|
10784
|
+
const detail = c.ok ? timing : import_picocolors37.default.dim(`${c.error ?? "no answer"}${c.failures > 1 ? ` \xB7 ${c.failures} in a row` : ""}`);
|
|
10785
|
+
line(` ${mark} ${c.appName} ${import_picocolors37.default.dim(`(${c.environment})`)} ${c.url} ${detail}`);
|
|
10511
10786
|
if (c.incidentOpened) {
|
|
10512
|
-
line(
|
|
10787
|
+
line(import_picocolors37.default.yellow(` An incident has been opened on the board for this.`));
|
|
10513
10788
|
}
|
|
10514
10789
|
}
|
|
10515
10790
|
const down = res.checks.filter((c) => !c.ok);
|
|
@@ -10522,14 +10797,14 @@ function print3(res) {
|
|
|
10522
10797
|
}
|
|
10523
10798
|
const production = down.filter((c) => c.environment === "production").length;
|
|
10524
10799
|
line(
|
|
10525
|
-
|
|
10800
|
+
import_picocolors37.default.red(
|
|
10526
10801
|
`${down.length} of ${res.checks.length} not answering` + (production ? ` \u2014 ${production} customer-facing.` : " (preview only).")
|
|
10527
10802
|
)
|
|
10528
10803
|
);
|
|
10529
10804
|
}
|
|
10530
10805
|
|
|
10531
10806
|
// src/commands/urls.ts
|
|
10532
|
-
var
|
|
10807
|
+
var import_picocolors38 = __toESM(require_picocolors(), 1);
|
|
10533
10808
|
function registerUrls(program3) {
|
|
10534
10809
|
program3.command("urls").description("The stable preview and production addresses of every app in this project").option("--app <webAppId>", "just one app").action(
|
|
10535
10810
|
action(async ({ ctx, opts }) => {
|
|
@@ -10543,20 +10818,20 @@ function registerUrls(program3) {
|
|
|
10543
10818
|
const summary = urlsSummary(rows);
|
|
10544
10819
|
ok({ rows, summary }, () => {
|
|
10545
10820
|
for (const row of rows) {
|
|
10546
|
-
const label =
|
|
10547
|
-
const value = row.url ?
|
|
10821
|
+
const label = import_picocolors38.default.dim(row.environment.padEnd(10));
|
|
10822
|
+
const value = row.url ? import_picocolors38.default.cyan(row.url) : import_picocolors38.default.dim(row.note ?? "not published");
|
|
10548
10823
|
line(` ${row.appName.padEnd(22)} ${label} ${value}`);
|
|
10549
10824
|
}
|
|
10550
10825
|
line("");
|
|
10551
10826
|
if (rows.some((r) => r.url)) success(summary);
|
|
10552
|
-
else line(
|
|
10827
|
+
else line(import_picocolors38.default.yellow(summary));
|
|
10553
10828
|
});
|
|
10554
10829
|
})
|
|
10555
10830
|
);
|
|
10556
10831
|
}
|
|
10557
10832
|
|
|
10558
10833
|
// src/commands/deployments.ts
|
|
10559
|
-
var
|
|
10834
|
+
var import_picocolors39 = __toESM(require_picocolors(), 1);
|
|
10560
10835
|
function registerDeployments(program3) {
|
|
10561
10836
|
const cmd = program3.command("deployments").description("Deployment history, and putting a build in front of customers");
|
|
10562
10837
|
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(
|
|
@@ -10574,7 +10849,7 @@ function registerDeployments(program3) {
|
|
|
10574
10849
|
ok(res, () => {
|
|
10575
10850
|
if (!items.length) {
|
|
10576
10851
|
return line(
|
|
10577
|
-
|
|
10852
|
+
import_picocolors39.default.dim(
|
|
10578
10853
|
environment ? `Nothing has been deployed to ${environment} yet.` : "Nothing has been deployed yet. `workser deploy` builds the first one."
|
|
10579
10854
|
)
|
|
10580
10855
|
);
|
|
@@ -10594,13 +10869,13 @@ function registerDeployments(program3) {
|
|
|
10594
10869
|
).catch(() => null) : null;
|
|
10595
10870
|
ok({ ...dep, logs }, () => {
|
|
10596
10871
|
line(formatDeployment(dep));
|
|
10597
|
-
if (dep?.error_message) line(
|
|
10872
|
+
if (dep?.error_message) line(import_picocolors39.default.red(` ${dep.error_message}`));
|
|
10598
10873
|
const events = logs?.events ?? [];
|
|
10599
10874
|
for (const e of events) {
|
|
10600
|
-
line(` ${
|
|
10875
|
+
line(` ${import_picocolors39.default.dim(String(e.type ?? "log"))} ${e.text ?? ""}`);
|
|
10601
10876
|
}
|
|
10602
10877
|
if (opts.logs && !events.length) {
|
|
10603
|
-
line(
|
|
10878
|
+
line(import_picocolors39.default.dim(" That build produced no output."));
|
|
10604
10879
|
}
|
|
10605
10880
|
});
|
|
10606
10881
|
})
|
|
@@ -10644,16 +10919,16 @@ function printPromoted(res, version) {
|
|
|
10644
10919
|
const what = version === null ? "the latest build" : `version ${version}`;
|
|
10645
10920
|
const url = res.url ?? res.vercel_url;
|
|
10646
10921
|
success(`Production is being rebuilt from ${what}.`);
|
|
10647
|
-
if (url) line(
|
|
10648
|
-
line(
|
|
10922
|
+
if (url) line(import_picocolors39.default.dim(`It will be at ${url}`));
|
|
10923
|
+
line(import_picocolors39.default.dim("`workser deploy status` follows it."));
|
|
10649
10924
|
}
|
|
10650
10925
|
function formatDeployment(d) {
|
|
10651
10926
|
if (!d) return "";
|
|
10652
|
-
const version = d.version !== void 0 ?
|
|
10653
|
-
const env =
|
|
10927
|
+
const version = d.version !== void 0 ? import_picocolors39.default.yellow(`v${d.version}`) : import_picocolors39.default.dim("v?");
|
|
10928
|
+
const env = import_picocolors39.default.dim((d.environment ?? "?").padEnd(10));
|
|
10654
10929
|
const app = d.webAppName ? `${d.webAppName} ` : "";
|
|
10655
|
-
const when =
|
|
10656
|
-
const url = d.url ? " " +
|
|
10930
|
+
const when = import_picocolors39.default.dim(formatTime2(d.created_at));
|
|
10931
|
+
const url = d.url ? " " + import_picocolors39.default.cyan(d.url) : "";
|
|
10657
10932
|
return `${version} ${env} ${colorStatus(d.status ?? "")} ${app}${when}${url}`;
|
|
10658
10933
|
}
|
|
10659
10934
|
function formatTime2(t) {
|
|
@@ -10663,7 +10938,7 @@ function formatTime2(t) {
|
|
|
10663
10938
|
}
|
|
10664
10939
|
|
|
10665
10940
|
// src/commands/usage.ts
|
|
10666
|
-
var
|
|
10941
|
+
var import_picocolors40 = __toESM(require_picocolors(), 1);
|
|
10667
10942
|
|
|
10668
10943
|
// src/usage.ts
|
|
10669
10944
|
var NEAR_LIMIT_FRACTION = 0.8;
|
|
@@ -10758,7 +11033,7 @@ function registerUsage(program3) {
|
|
|
10758
11033
|
function print4(report) {
|
|
10759
11034
|
const dims = report.dimensions ?? [];
|
|
10760
11035
|
if (!dims.length) {
|
|
10761
|
-
return line(
|
|
11036
|
+
return line(import_picocolors40.default.dim("Nothing to measure for this project yet."));
|
|
10762
11037
|
}
|
|
10763
11038
|
const width = Math.max(...dims.map((d) => d.label.length));
|
|
10764
11039
|
for (const d of dims) {
|
|
@@ -10767,23 +11042,23 @@ function print4(report) {
|
|
|
10767
11042
|
line("");
|
|
10768
11043
|
const summary = usageSummary(report);
|
|
10769
11044
|
const worst = dims.map(usageState);
|
|
10770
|
-
if (worst.includes("over")) line(
|
|
11045
|
+
if (worst.includes("over")) line(import_picocolors40.default.red(summary));
|
|
10771
11046
|
else if (worst.includes("near") || worst.includes("unknown"))
|
|
10772
|
-
line(
|
|
11047
|
+
line(import_picocolors40.default.yellow(summary));
|
|
10773
11048
|
else success(summary);
|
|
10774
11049
|
}
|
|
10775
11050
|
function gauge(d, _labelWidth) {
|
|
10776
11051
|
const drawn = bar(d);
|
|
10777
|
-
return drawn ? ` ${
|
|
11052
|
+
return drawn ? ` ${import_picocolors40.default.dim(drawn)}` : "";
|
|
10778
11053
|
}
|
|
10779
11054
|
function colour(d) {
|
|
10780
11055
|
switch (usageState(d)) {
|
|
10781
11056
|
case "over":
|
|
10782
|
-
return d.kind === "hard" ?
|
|
11057
|
+
return d.kind === "hard" ? import_picocolors40.default.red : import_picocolors40.default.yellow;
|
|
10783
11058
|
case "near":
|
|
10784
|
-
return
|
|
11059
|
+
return import_picocolors40.default.yellow;
|
|
10785
11060
|
case "unknown":
|
|
10786
|
-
return
|
|
11061
|
+
return import_picocolors40.default.dim;
|
|
10787
11062
|
default:
|
|
10788
11063
|
return (s) => s;
|
|
10789
11064
|
}
|
|
@@ -10791,7 +11066,7 @@ function colour(d) {
|
|
|
10791
11066
|
|
|
10792
11067
|
// src/index.ts
|
|
10793
11068
|
var pkg = {
|
|
10794
|
-
version: true ? "0.6.
|
|
11069
|
+
version: true ? "0.6.9" : "0.0.0-dev"
|
|
10795
11070
|
};
|
|
10796
11071
|
var program2 = new Command();
|
|
10797
11072
|
program2.name("workser").description(
|
|
@@ -10816,6 +11091,7 @@ registerAuth(program2);
|
|
|
10816
11091
|
registerStorage(program2);
|
|
10817
11092
|
registerNeon(program2);
|
|
10818
11093
|
registerEnv(program2);
|
|
11094
|
+
registerKey(program2);
|
|
10819
11095
|
registerDeploy(program2);
|
|
10820
11096
|
registerVersions(program2);
|
|
10821
11097
|
registerLogs(program2);
|