@workser/cli 0.6.11 → 0.6.13
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 +7 -0
- package/dist/index.js +347 -205
- package/package.json +1 -1
- package/skills/workser/SKILL.md +14 -12
package/dist/index.js
CHANGED
|
@@ -3583,6 +3583,7 @@ function ownerOnly(opts) {
|
|
|
3583
3583
|
}
|
|
3584
3584
|
|
|
3585
3585
|
// src/output.ts
|
|
3586
|
+
var OUT_OF_SCOPE_EXIT = 7;
|
|
3586
3587
|
var mode = "text";
|
|
3587
3588
|
var quiet = false;
|
|
3588
3589
|
function configureOutput(opts) {
|
|
@@ -3633,7 +3634,13 @@ function fail(err) {
|
|
|
3633
3634
|
} else if (e.status === 401 || e.code === "unauthorized") {
|
|
3634
3635
|
process.stderr.write(import_picocolors.default.dim(" Run `workser login` to authenticate.\n"));
|
|
3635
3636
|
} else if (e.code === "no_project") {
|
|
3636
|
-
process.stderr.write(import_picocolors.default.dim("
|
|
3637
|
+
process.stderr.write(import_picocolors.default.dim(" cd into the project's folder, or open it in Workser.\n"));
|
|
3638
|
+
} else if (e.code === "out_of_scope") {
|
|
3639
|
+
process.stderr.write(
|
|
3640
|
+
import_picocolors.default.dim(
|
|
3641
|
+
" You can move between your organization's projects; another organization's are not reachable.\n"
|
|
3642
|
+
)
|
|
3643
|
+
);
|
|
3637
3644
|
} else if (e.code === "awaiting_approval") {
|
|
3638
3645
|
process.stderr.write(import_picocolors.default.dim(" Approve the action in Workser Orbit, then retry.\n"));
|
|
3639
3646
|
} else if (e.code === "owner_only") {
|
|
@@ -3647,6 +3654,7 @@ function exitCodeFor(e) {
|
|
|
3647
3654
|
if (e.status === 401 || e.code === "unauthorized") return 3;
|
|
3648
3655
|
if (e.code === "awaiting_approval") return 5;
|
|
3649
3656
|
if (e.code === "owner_only") return OWNER_ONLY_EXIT;
|
|
3657
|
+
if (e.code === "out_of_scope") return OUT_OF_SCOPE_EXIT;
|
|
3650
3658
|
return 1;
|
|
3651
3659
|
}
|
|
3652
3660
|
|
|
@@ -5624,6 +5632,9 @@ async function api(ctx, path, opts = {}) {
|
|
|
5624
5632
|
if (ctx.mode === "daemon" && ctx.runId) {
|
|
5625
5633
|
headers["x-workser-run-id"] = ctx.runId;
|
|
5626
5634
|
}
|
|
5635
|
+
if (ctx.mode === "daemon" && ctx.cwd) {
|
|
5636
|
+
headers["x-workser-cwd"] = encodeURIComponent(ctx.cwd);
|
|
5637
|
+
}
|
|
5627
5638
|
if (opts.body !== void 0) headers["content-type"] = "application/json";
|
|
5628
5639
|
const method = opts.method ?? (opts.body !== void 0 ? "POST" : "GET");
|
|
5629
5640
|
const bodyText = opts.body !== void 0 ? JSON.stringify(opts.body) : void 0;
|
|
@@ -5709,6 +5720,12 @@ function registerStatus(program3) {
|
|
|
5709
5720
|
` project: ${data.project?.name ?? "\u2014"}` + (data.project?.id ? import_picocolors3.default.dim(` (${data.project.id})`) : "")
|
|
5710
5721
|
);
|
|
5711
5722
|
if (ctx.projectRoot) line(` folder: ${import_picocolors3.default.dim(ctx.projectRoot)}`);
|
|
5723
|
+
if (data.scope) {
|
|
5724
|
+
const why = data.scope.source === "folder" ? "this folder" : data.scope.source === "active" ? "the project open in Workser" : null;
|
|
5725
|
+
line(
|
|
5726
|
+
data.scope.orgId ? ` org: ${data.scope.orgId}` + (why ? import_picocolors3.default.dim(` (from ${why})`) : "") : ` org: ${import_picocolors3.default.yellow("unscoped \u2014 every project is reachable")}`
|
|
5727
|
+
);
|
|
5728
|
+
}
|
|
5712
5729
|
if (ctx.appId) {
|
|
5713
5730
|
line(
|
|
5714
5731
|
` app: ${ctx.appName ?? "\u2014"}` + import_picocolors3.default.dim(` (${ctx.appId})`)
|
|
@@ -5921,7 +5938,7 @@ function registerProject(program3) {
|
|
|
5921
5938
|
});
|
|
5922
5939
|
})
|
|
5923
5940
|
);
|
|
5924
|
-
project.command("list").description("List the
|
|
5941
|
+
project.command("list").description("List the projects in your organization").action(
|
|
5925
5942
|
action(async ({ ctx }) => {
|
|
5926
5943
|
const items = await api(ctx, `/v1/projects`);
|
|
5927
5944
|
ok(items, () => {
|
|
@@ -5930,6 +5947,11 @@ function registerProject(program3) {
|
|
|
5930
5947
|
const pinned = ctx.projectId && p.id === ctx.projectId ? import_picocolors4.default.green("\u25CF ") : " ";
|
|
5931
5948
|
line(`${pinned}${p.name ?? "\u2014"}${p.id ? import_picocolors4.default.dim(` (${p.id})`) : ""}`);
|
|
5932
5949
|
}
|
|
5950
|
+
line(
|
|
5951
|
+
import_picocolors4.default.dim(
|
|
5952
|
+
"\nYour organization's projects. Other organizations are not reachable from here."
|
|
5953
|
+
)
|
|
5954
|
+
);
|
|
5933
5955
|
});
|
|
5934
5956
|
})
|
|
5935
5957
|
);
|
|
@@ -7841,8 +7863,52 @@ function registerMemory(program3) {
|
|
|
7841
7863
|
);
|
|
7842
7864
|
}
|
|
7843
7865
|
|
|
7844
|
-
// src/commands/
|
|
7866
|
+
// src/commands/note.ts
|
|
7845
7867
|
var import_picocolors24 = __toESM(require_picocolors(), 1);
|
|
7868
|
+
function registerNote(program3) {
|
|
7869
|
+
program3.command("note <text>").description("Leave a fact the rest of the team will need").addHelpText(
|
|
7870
|
+
"after",
|
|
7871
|
+
'\nFor things that are true about the WORK, not about your step:\n workser note "the API base path is /api/v2, not /api"\n workser note "added STRIPE_KEY to local, preview and production"\n\nWhat your own step did goes in `workser task done --summary` instead.\n'
|
|
7872
|
+
).option(
|
|
7873
|
+
"--task <id>",
|
|
7874
|
+
"the plan to leave it on (default: the plan this step belongs to)"
|
|
7875
|
+
).action(
|
|
7876
|
+
action(async ({ ctx, args, opts }) => {
|
|
7877
|
+
const text = typeof args[0] === "string" ? args[0].trim() : "";
|
|
7878
|
+
if (!text) {
|
|
7879
|
+
info("Nothing to note \u2014 give it a sentence.");
|
|
7880
|
+
return;
|
|
7881
|
+
}
|
|
7882
|
+
const taskId = opts.task || ctx.parentTaskId || ctx.projectTaskId;
|
|
7883
|
+
if (!taskId) {
|
|
7884
|
+
info(
|
|
7885
|
+
"No plan to leave this on. Run it from inside a step, or pass --task <id>."
|
|
7886
|
+
);
|
|
7887
|
+
return;
|
|
7888
|
+
}
|
|
7889
|
+
const res = await api(ctx, "/v1/team-notes", {
|
|
7890
|
+
body: {
|
|
7891
|
+
cwd: ctx.cwd,
|
|
7892
|
+
taskId,
|
|
7893
|
+
text,
|
|
7894
|
+
role: ctx.agentRole,
|
|
7895
|
+
agent: ctx.agentType
|
|
7896
|
+
}
|
|
7897
|
+
}).catch(() => null);
|
|
7898
|
+
if (!res) {
|
|
7899
|
+
info("Couldn't save that note \u2014 carrying on.");
|
|
7900
|
+
return;
|
|
7901
|
+
}
|
|
7902
|
+
ok(res, () => {
|
|
7903
|
+
success("Noted for the team.");
|
|
7904
|
+
line(import_picocolors24.default.dim(` ${text}`));
|
|
7905
|
+
});
|
|
7906
|
+
})
|
|
7907
|
+
);
|
|
7908
|
+
}
|
|
7909
|
+
|
|
7910
|
+
// src/commands/business.ts
|
|
7911
|
+
var import_picocolors25 = __toESM(require_picocolors(), 1);
|
|
7846
7912
|
var RESOURCE_PATHS = {
|
|
7847
7913
|
"business-config": "business-config",
|
|
7848
7914
|
"business-settings": "business-settings",
|
|
@@ -7902,7 +7968,7 @@ function registerBusiness(program3) {
|
|
|
7902
7968
|
const projectId = requireProject(ctx);
|
|
7903
7969
|
const [resource] = args;
|
|
7904
7970
|
const res = await api(ctx, businessPath(projectId, resource), { body: JSON.parse(opts.body) });
|
|
7905
|
-
ok(res, () => line(`Created ${resource} ${
|
|
7971
|
+
ok(res, () => line(`Created ${resource} ${import_picocolors25.default.bold(res?.id ?? "")}.`));
|
|
7906
7972
|
})
|
|
7907
7973
|
);
|
|
7908
7974
|
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(
|
|
@@ -7944,7 +8010,7 @@ function businessPath(projectId, resource, subpath) {
|
|
|
7944
8010
|
}
|
|
7945
8011
|
|
|
7946
8012
|
// src/commands/artifact.ts
|
|
7947
|
-
var
|
|
8013
|
+
var import_picocolors26 = __toESM(require_picocolors(), 1);
|
|
7948
8014
|
import { existsSync as existsSync2, statSync } from "fs";
|
|
7949
8015
|
import { resolve as resolve3, basename as basename3 } from "path";
|
|
7950
8016
|
var KINDS = [
|
|
@@ -8041,7 +8107,7 @@ function registerArtifact(program3) {
|
|
|
8041
8107
|
ok(
|
|
8042
8108
|
res,
|
|
8043
8109
|
() => success(
|
|
8044
|
-
`Recorded ${
|
|
8110
|
+
`Recorded ${import_picocolors26.default.bold(res?.title ?? "artifact")}${res?.kind ? import_picocolors26.default.dim(` (${res.kind})`) : ""}`
|
|
8045
8111
|
)
|
|
8046
8112
|
);
|
|
8047
8113
|
})
|
|
@@ -8079,7 +8145,7 @@ function registerArtifact(program3) {
|
|
|
8079
8145
|
}
|
|
8080
8146
|
function printArtifacts(rows) {
|
|
8081
8147
|
if (!rows.length) {
|
|
8082
|
-
line(
|
|
8148
|
+
line(import_picocolors26.default.dim("Nothing produced yet."));
|
|
8083
8149
|
return;
|
|
8084
8150
|
}
|
|
8085
8151
|
const byStep = /* @__PURE__ */ new Map();
|
|
@@ -8089,26 +8155,26 @@ function printArtifacts(rows) {
|
|
|
8089
8155
|
byStep.set(r.subtask_id, list);
|
|
8090
8156
|
}
|
|
8091
8157
|
for (const [stepId, items] of byStep) {
|
|
8092
|
-
line(
|
|
8158
|
+
line(import_picocolors26.default.bold(`step ${stepId}`));
|
|
8093
8159
|
for (const a of items) {
|
|
8094
|
-
const flag = a.promoted_at ?
|
|
8160
|
+
const flag = a.promoted_at ? import_picocolors26.default.green(" *") : " ";
|
|
8095
8161
|
const where = a.local_path || a.cloud_url || "";
|
|
8096
8162
|
line(
|
|
8097
|
-
`${flag} ${
|
|
8163
|
+
`${flag} ${import_picocolors26.default.dim(`[${a.kind}]`)} ${a.title ?? "(untitled)"}` + (where ? import_picocolors26.default.dim(` ${where}`) : "")
|
|
8098
8164
|
);
|
|
8099
|
-
if (a.description) line(
|
|
8165
|
+
if (a.description) line(import_picocolors26.default.dim(` ${a.description}`));
|
|
8100
8166
|
}
|
|
8101
8167
|
line("");
|
|
8102
8168
|
}
|
|
8103
|
-
line(
|
|
8169
|
+
line(import_picocolors26.default.dim("* = handed over as a deliverable; the rest is working material."));
|
|
8104
8170
|
}
|
|
8105
8171
|
function printRun(run) {
|
|
8106
8172
|
if (!run) return;
|
|
8107
|
-
line(` run ${
|
|
8173
|
+
line(` run ${import_picocolors26.default.bold(run.runId)}`);
|
|
8108
8174
|
if (run.taskId) line(` task ${run.taskId}`);
|
|
8109
8175
|
if (run.conversationId) line(` chat ${run.conversationId}`);
|
|
8110
8176
|
if (run.projectId) line(` project ${run.projectId}`);
|
|
8111
|
-
if (run.cwd) line(` folder ${
|
|
8177
|
+
if (run.cwd) line(` folder ${import_picocolors26.default.dim(run.cwd)}`);
|
|
8112
8178
|
}
|
|
8113
8179
|
|
|
8114
8180
|
// src/commands/image.ts
|
|
@@ -8289,7 +8355,7 @@ function registerAudio(program3) {
|
|
|
8289
8355
|
}
|
|
8290
8356
|
|
|
8291
8357
|
// src/commands/ask.ts
|
|
8292
|
-
var
|
|
8358
|
+
var import_picocolors27 = __toESM(require_picocolors(), 1);
|
|
8293
8359
|
var TYPES = [
|
|
8294
8360
|
"input",
|
|
8295
8361
|
"choice",
|
|
@@ -8367,7 +8433,7 @@ function registerAsk(program3) {
|
|
|
8367
8433
|
code: "bad_request"
|
|
8368
8434
|
});
|
|
8369
8435
|
}
|
|
8370
|
-
info(
|
|
8436
|
+
info(import_picocolors27.default.dim("Waiting for the user to answer\u2026"));
|
|
8371
8437
|
const res = await api(ctx, `/v1/runs/${runTarget(ctx)}/ask`, {
|
|
8372
8438
|
body: {
|
|
8373
8439
|
type,
|
|
@@ -8395,12 +8461,12 @@ function deriveTitle(message) {
|
|
|
8395
8461
|
function printAnswer(res) {
|
|
8396
8462
|
if (!res) return;
|
|
8397
8463
|
if (res.status === "answered") {
|
|
8398
|
-
line(` ${
|
|
8464
|
+
line(` ${import_picocolors27.default.green("answered")}`);
|
|
8399
8465
|
const value = extract(res.response);
|
|
8400
8466
|
if (value) line(` ${value}`);
|
|
8401
8467
|
return;
|
|
8402
8468
|
}
|
|
8403
|
-
line(` ${
|
|
8469
|
+
line(` ${import_picocolors27.default.yellow(res.status)} ${import_picocolors27.default.dim(res.reason ?? "")}`);
|
|
8404
8470
|
}
|
|
8405
8471
|
function extract(response) {
|
|
8406
8472
|
if (response == null) return "";
|
|
@@ -8419,7 +8485,7 @@ function extract(response) {
|
|
|
8419
8485
|
}
|
|
8420
8486
|
|
|
8421
8487
|
// src/commands/search.ts
|
|
8422
|
-
var
|
|
8488
|
+
var import_picocolors28 = __toESM(require_picocolors(), 1);
|
|
8423
8489
|
function registerSearch(program3) {
|
|
8424
8490
|
program3.command("search <query>").description("Search the web (Google-grounded, server-side)").option("-n, --max-results <n>", "max results", "5").action(
|
|
8425
8491
|
action(async ({ ctx, args, opts }) => {
|
|
@@ -8432,9 +8498,9 @@ function registerSearch(program3) {
|
|
|
8432
8498
|
line("");
|
|
8433
8499
|
}
|
|
8434
8500
|
const results = res?.results ?? [];
|
|
8435
|
-
if (!results.length) return line(
|
|
8501
|
+
if (!results.length) return line(import_picocolors28.default.dim("No results."));
|
|
8436
8502
|
for (const r of results) {
|
|
8437
|
-
line(`${r.title ||
|
|
8503
|
+
line(`${r.title || import_picocolors28.default.dim("(untitled)")} ${import_picocolors28.default.dim(r.url)}`);
|
|
8438
8504
|
}
|
|
8439
8505
|
});
|
|
8440
8506
|
})
|
|
@@ -8442,7 +8508,7 @@ function registerSearch(program3) {
|
|
|
8442
8508
|
}
|
|
8443
8509
|
|
|
8444
8510
|
// src/commands/board.ts
|
|
8445
|
-
var
|
|
8511
|
+
var import_picocolors29 = __toESM(require_picocolors(), 1);
|
|
8446
8512
|
|
|
8447
8513
|
// src/commands/record-step.ts
|
|
8448
8514
|
async function recordEntityStep(ctx, opts) {
|
|
@@ -8481,7 +8547,7 @@ function registerBoard(program3) {
|
|
|
8481
8547
|
}
|
|
8482
8548
|
ok(rows, () => {
|
|
8483
8549
|
if (!rows.length) {
|
|
8484
|
-
line(
|
|
8550
|
+
line(import_picocolors29.default.dim("No cards on the Board yet."));
|
|
8485
8551
|
return;
|
|
8486
8552
|
}
|
|
8487
8553
|
for (const r of rows) line(formatRow(r));
|
|
@@ -8496,7 +8562,7 @@ function registerBoard(program3) {
|
|
|
8496
8562
|
`/v1/projects/${projectId}/work-items/${args[0]}`
|
|
8497
8563
|
);
|
|
8498
8564
|
ok(row, () => {
|
|
8499
|
-
line(`${
|
|
8565
|
+
line(`${import_picocolors29.default.bold(row.title)} ${import_picocolors29.default.dim(row.id)}`);
|
|
8500
8566
|
line(`${statusTag(row.status)} priority ${row.priority}`);
|
|
8501
8567
|
if (row.ownerHuman) line(`owner: ${row.ownerHuman}`);
|
|
8502
8568
|
if (row.labels?.length) line(`labels: ${row.labels.join(", ")}`);
|
|
@@ -8537,7 +8603,7 @@ ${row.description}`);
|
|
|
8537
8603
|
refId: row?.id,
|
|
8538
8604
|
output: { workItem: row }
|
|
8539
8605
|
});
|
|
8540
|
-
ok(row, () => line(`Created work item ${
|
|
8606
|
+
ok(row, () => line(`Created work item ${import_picocolors29.default.bold(row?.id ?? "")} \u2014 ${title}`));
|
|
8541
8607
|
})
|
|
8542
8608
|
);
|
|
8543
8609
|
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(
|
|
@@ -8571,7 +8637,7 @@ ${row.description}`);
|
|
|
8571
8637
|
);
|
|
8572
8638
|
}
|
|
8573
8639
|
const row = await patchItem(ctx, projectId, String(args[0]), body);
|
|
8574
|
-
ok(row, () => line(`Updated ${
|
|
8640
|
+
ok(row, () => line(`Updated ${import_picocolors29.default.bold(row.id)} \u2014 ${row.title} ${statusTag(row.status)}`));
|
|
8575
8641
|
})
|
|
8576
8642
|
);
|
|
8577
8643
|
board.command("move <id> <status>").description(
|
|
@@ -8582,14 +8648,14 @@ ${row.description}`);
|
|
|
8582
8648
|
const status = String(args[1]);
|
|
8583
8649
|
assertStatus(status);
|
|
8584
8650
|
const row = await patchItem(ctx, projectId, String(args[0]), { status });
|
|
8585
|
-
ok(row, () => line(`Moved ${
|
|
8651
|
+
ok(row, () => line(`Moved ${import_picocolors29.default.bold(row.title)} \u2192 ${statusTag(row.status)}`));
|
|
8586
8652
|
})
|
|
8587
8653
|
);
|
|
8588
8654
|
board.command("close <id>").description("Shorthand for `board move <id> done`").action(
|
|
8589
8655
|
action(async ({ ctx, args }) => {
|
|
8590
8656
|
const projectId = requireProject(ctx);
|
|
8591
8657
|
const row = await patchItem(ctx, projectId, String(args[0]), { status: "done" });
|
|
8592
|
-
ok(row, () => line(`Closed ${
|
|
8658
|
+
ok(row, () => line(`Closed ${import_picocolors29.default.bold(row.title)} ${statusTag(row.status)}`));
|
|
8593
8659
|
})
|
|
8594
8660
|
);
|
|
8595
8661
|
}
|
|
@@ -8622,23 +8688,23 @@ function assertPriority(value) {
|
|
|
8622
8688
|
}
|
|
8623
8689
|
}
|
|
8624
8690
|
function formatRow(r) {
|
|
8625
|
-
const labels = r.labels?.length ?
|
|
8626
|
-
const owner = r.ownerHuman ?
|
|
8627
|
-
return `${
|
|
8691
|
+
const labels = r.labels?.length ? import_picocolors29.default.dim(` [${r.labels.join(", ")}]`) : "";
|
|
8692
|
+
const owner = r.ownerHuman ? import_picocolors29.default.dim(` @${r.ownerHuman}`) : "";
|
|
8693
|
+
return `${import_picocolors29.default.dim(r.id)} ${statusTag(r.status)} ${r.title}${labels}${owner}`;
|
|
8628
8694
|
}
|
|
8629
8695
|
function statusTag(status) {
|
|
8630
8696
|
const label = status.padEnd(11);
|
|
8631
|
-
if (status === "done") return
|
|
8632
|
-
if (status === "in-progress") return
|
|
8633
|
-
if (status === "in-review") return
|
|
8634
|
-
return
|
|
8697
|
+
if (status === "done") return import_picocolors29.default.green(label);
|
|
8698
|
+
if (status === "in-progress") return import_picocolors29.default.yellow(label);
|
|
8699
|
+
if (status === "in-review") return import_picocolors29.default.cyan(label);
|
|
8700
|
+
return import_picocolors29.default.dim(label);
|
|
8635
8701
|
}
|
|
8636
8702
|
function collect2(value, previous) {
|
|
8637
8703
|
return [...previous, value];
|
|
8638
8704
|
}
|
|
8639
8705
|
|
|
8640
8706
|
// src/commands/task.ts
|
|
8641
|
-
var
|
|
8707
|
+
var import_picocolors30 = __toESM(require_picocolors(), 1);
|
|
8642
8708
|
|
|
8643
8709
|
// src/subtask-attachments.ts
|
|
8644
8710
|
var MAX_REF_NOTE = 500;
|
|
@@ -8684,6 +8750,13 @@ function parseRefs(raw) {
|
|
|
8684
8750
|
|
|
8685
8751
|
// src/commands/task.ts
|
|
8686
8752
|
var STATUSES2 = [
|
|
8753
|
+
/**
|
|
8754
|
+
* LISTED, NOT PLANNED. A goal's later phases get their tasks written down
|
|
8755
|
+
* when the plan is agreed, so the owner can read the whole shape — but those
|
|
8756
|
+
* rows have no subtasks and the runner must never pick them up. `todo` keeps
|
|
8757
|
+
* its meaning: the team may start this now.
|
|
8758
|
+
*/
|
|
8759
|
+
"backlog",
|
|
8687
8760
|
"todo",
|
|
8688
8761
|
"working",
|
|
8689
8762
|
"checking",
|
|
@@ -8691,6 +8764,8 @@ var STATUSES2 = [
|
|
|
8691
8764
|
"accepted",
|
|
8692
8765
|
"archived"
|
|
8693
8766
|
];
|
|
8767
|
+
var PRIORITIES2 = ["urgent", "high", "normal", "low"];
|
|
8768
|
+
var SIZES = ["small", "standard"];
|
|
8694
8769
|
var ROLES = [
|
|
8695
8770
|
"pm",
|
|
8696
8771
|
"architect",
|
|
@@ -8743,7 +8818,7 @@ function registerTask(program3) {
|
|
|
8743
8818
|
}) ?? [];
|
|
8744
8819
|
ok(rows, () => {
|
|
8745
8820
|
if (!rows.length) {
|
|
8746
|
-
line(
|
|
8821
|
+
line(import_picocolors30.default.dim("No tasks on the board yet."));
|
|
8747
8822
|
return;
|
|
8748
8823
|
}
|
|
8749
8824
|
for (const r of rows) line(formatRow2(r));
|
|
@@ -8770,10 +8845,21 @@ function registerTask(program3) {
|
|
|
8770
8845
|
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(
|
|
8771
8846
|
"--phase <name>",
|
|
8772
8847
|
"which slice of that goal \u2014 must match one of its phase names"
|
|
8848
|
+
).option("--priority <value>", `how urgent (${PRIORITIES2.join(" | ")})`).option(
|
|
8849
|
+
"--size <value>",
|
|
8850
|
+
`small lets the channel start it without asking; standard asks (${SIZES.join(" | ")})`
|
|
8851
|
+
).option(
|
|
8852
|
+
"--status <value>",
|
|
8853
|
+
`start it somewhere other than 'todo' \u2014 use 'backlog' for a later phase's work (${STATUSES2.join(" | ")})`
|
|
8773
8854
|
).action(
|
|
8774
8855
|
action(async ({ ctx, args, opts }) => {
|
|
8775
8856
|
requireProject(ctx);
|
|
8776
8857
|
if (opts.kind !== void 0) assertOneOf("--kind", opts.kind, KINDS2);
|
|
8858
|
+
if (opts.priority !== void 0)
|
|
8859
|
+
assertOneOf("--priority", opts.priority, PRIORITIES2);
|
|
8860
|
+
if (opts.size !== void 0) assertOneOf("--size", opts.size, SIZES);
|
|
8861
|
+
if (opts.status !== void 0)
|
|
8862
|
+
assertOneOf("--status", opts.status, STATUSES2);
|
|
8777
8863
|
const hasChannelOrigin = Boolean(
|
|
8778
8864
|
ctx.projectChannelId && ctx.projectChannelMessageId
|
|
8779
8865
|
);
|
|
@@ -8787,6 +8873,11 @@ function registerTask(program3) {
|
|
|
8787
8873
|
// a goal has to be argued for, never assumed.
|
|
8788
8874
|
goalId: opts.goal,
|
|
8789
8875
|
phase: opts.phase,
|
|
8876
|
+
priority: opts.priority,
|
|
8877
|
+
size: opts.size,
|
|
8878
|
+
// `backlog` for a later phase's work: written down so the owner can
|
|
8879
|
+
// read the whole plan, with nothing for the runner to pick up.
|
|
8880
|
+
status: opts.status,
|
|
8790
8881
|
targets: [
|
|
8791
8882
|
...(opts.app ?? []).map((appId) => ({
|
|
8792
8883
|
kind: "app",
|
|
@@ -8836,10 +8927,10 @@ function registerTask(program3) {
|
|
|
8836
8927
|
};
|
|
8837
8928
|
ok(result, () => {
|
|
8838
8929
|
line(
|
|
8839
|
-
`${
|
|
8930
|
+
`${import_picocolors30.default.green("opened")} ${import_picocolors30.default.bold(row.title)} ${import_picocolors30.default.dim(row.key ?? row.id)}`
|
|
8840
8931
|
);
|
|
8841
8932
|
if (channelMessage)
|
|
8842
|
-
line(
|
|
8933
|
+
line(import_picocolors30.default.dim("posted to the channel as Project Manager"));
|
|
8843
8934
|
if (channelMessageError) {
|
|
8844
8935
|
warn(
|
|
8845
8936
|
`Task opened, but its Project Manager card could not be posted: ${channelMessageError.message}`
|
|
@@ -8918,12 +9009,12 @@ function registerTask(program3) {
|
|
|
8918
9009
|
) : null;
|
|
8919
9010
|
ok(runner ?? row, () => {
|
|
8920
9011
|
line(
|
|
8921
|
-
`${
|
|
9012
|
+
`${import_picocolors30.default.green("added")} ${import_picocolors30.default.bold(row.title)} ${import_picocolors30.default.dim(row.key ?? row.id)}`
|
|
8922
9013
|
);
|
|
8923
|
-
if (row.role) line(
|
|
9014
|
+
if (row.role) line(import_picocolors30.default.dim(`role: ${row.role}`));
|
|
8924
9015
|
if (runner) {
|
|
8925
9016
|
line(
|
|
8926
|
-
|
|
9017
|
+
import_picocolors30.default.dim(
|
|
8927
9018
|
`runs on: ${[opts.agent, opts.model, opts.effort].filter(Boolean).join(" \xB7 ")}`
|
|
8928
9019
|
)
|
|
8929
9020
|
);
|
|
@@ -8941,7 +9032,7 @@ function registerTask(program3) {
|
|
|
8941
9032
|
const rows = row.subtasks ?? [];
|
|
8942
9033
|
ok(rows, () => {
|
|
8943
9034
|
if (!rows.length) {
|
|
8944
|
-
line(
|
|
9035
|
+
line(import_picocolors30.default.dim("No subtasks yet."));
|
|
8945
9036
|
return;
|
|
8946
9037
|
}
|
|
8947
9038
|
rows.forEach((r, i) => line(formatSubtask(r, i + 1)));
|
|
@@ -8989,7 +9080,7 @@ function registerTask(program3) {
|
|
|
8989
9080
|
}
|
|
8990
9081
|
}
|
|
8991
9082
|
);
|
|
8992
|
-
ok(row, () => line(`${
|
|
9083
|
+
ok(row, () => line(`${import_picocolors30.default.green("updated")} ${import_picocolors30.default.bold(row.title)}`));
|
|
8993
9084
|
})
|
|
8994
9085
|
);
|
|
8995
9086
|
subtask.command("remove <id>").description("Remove a subtask (only before the work starts)").action(
|
|
@@ -8997,7 +9088,7 @@ function registerTask(program3) {
|
|
|
8997
9088
|
await api(ctx, `/v1/project-tasks/${encodeURIComponent(args[0])}`, {
|
|
8998
9089
|
method: "DELETE"
|
|
8999
9090
|
});
|
|
9000
|
-
ok({ removed: args[0] }, () => line(
|
|
9091
|
+
ok({ removed: args[0] }, () => line(import_picocolors30.default.green("removed")));
|
|
9001
9092
|
})
|
|
9002
9093
|
);
|
|
9003
9094
|
task.command("move <id> <status>").description(
|
|
@@ -9012,7 +9103,7 @@ function registerTask(program3) {
|
|
|
9012
9103
|
);
|
|
9013
9104
|
ok(
|
|
9014
9105
|
row,
|
|
9015
|
-
() => line(`${
|
|
9106
|
+
() => line(`${import_picocolors30.default.green("moved")} ${import_picocolors30.default.bold(row.title)} \u2192 ${args[1]}`)
|
|
9016
9107
|
);
|
|
9017
9108
|
})
|
|
9018
9109
|
);
|
|
@@ -9028,18 +9119,18 @@ function registerTask(program3) {
|
|
|
9028
9119
|
);
|
|
9029
9120
|
ok(row, () => {
|
|
9030
9121
|
if (!row?.queued) {
|
|
9031
|
-
line(
|
|
9122
|
+
line(import_picocolors30.default.yellow("could not resume it \u2014 check the step id"));
|
|
9032
9123
|
return;
|
|
9033
9124
|
}
|
|
9034
9125
|
const started = row.started ?? 0;
|
|
9035
9126
|
if (started > 0) {
|
|
9036
9127
|
line(
|
|
9037
|
-
`${
|
|
9128
|
+
`${import_picocolors30.default.green("resumed")} \u2014 ${started} step${started === 1 ? "" : "s"} started`
|
|
9038
9129
|
);
|
|
9039
9130
|
return;
|
|
9040
9131
|
}
|
|
9041
9132
|
line(
|
|
9042
|
-
`${
|
|
9133
|
+
`${import_picocolors30.default.green("resumed")} \u2014 it is queued, but nothing started yet. Check the plan is approved and that no step is blocking the rest.`
|
|
9043
9134
|
);
|
|
9044
9135
|
});
|
|
9045
9136
|
})
|
|
@@ -9053,11 +9144,11 @@ function registerTask(program3) {
|
|
|
9053
9144
|
);
|
|
9054
9145
|
ok(row, () => {
|
|
9055
9146
|
if (row?.reopened) {
|
|
9056
|
-
line(`${
|
|
9147
|
+
line(`${import_picocolors30.default.green("sent back")} \u2014 it will be picked up again`);
|
|
9057
9148
|
return;
|
|
9058
9149
|
}
|
|
9059
9150
|
line(
|
|
9060
|
-
|
|
9151
|
+
import_picocolors30.default.yellow(
|
|
9061
9152
|
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"
|
|
9062
9153
|
)
|
|
9063
9154
|
);
|
|
@@ -9074,7 +9165,7 @@ function registerTask(program3) {
|
|
|
9074
9165
|
`/v1/project-tasks/${encodeURIComponent(id)}/dispatch-check`,
|
|
9075
9166
|
{ method: "POST" }
|
|
9076
9167
|
);
|
|
9077
|
-
ok(row, () => line(
|
|
9168
|
+
ok(row, () => line(import_picocolors30.default.green("approved \u2014 you may start")));
|
|
9078
9169
|
})
|
|
9079
9170
|
);
|
|
9080
9171
|
task.command("start [id]").description(
|
|
@@ -9089,13 +9180,13 @@ function registerTask(program3) {
|
|
|
9089
9180
|
const started = row?.started ?? null;
|
|
9090
9181
|
if (started && started > 0) {
|
|
9091
9182
|
line(
|
|
9092
|
-
|
|
9183
|
+
import_picocolors30.default.green(
|
|
9093
9184
|
`started ${started} step${started === 1 ? "" : "s"} \u2014 they are running now`
|
|
9094
9185
|
)
|
|
9095
9186
|
);
|
|
9096
9187
|
return;
|
|
9097
9188
|
}
|
|
9098
|
-
line(
|
|
9189
|
+
line(import_picocolors30.default.yellow(row?.note ?? "Nothing started."));
|
|
9099
9190
|
});
|
|
9100
9191
|
})
|
|
9101
9192
|
);
|
|
@@ -9110,7 +9201,7 @@ function registerTask(program3) {
|
|
|
9110
9201
|
);
|
|
9111
9202
|
ok({ awaiting: row2.approval_state === "awaiting", task: row2 }, () => {
|
|
9112
9203
|
line(
|
|
9113
|
-
row2.approval_state === "awaiting" ?
|
|
9204
|
+
row2.approval_state === "awaiting" ? import_picocolors30.default.yellow(
|
|
9114
9205
|
"The plan is waiting on the owner. They see it in the task."
|
|
9115
9206
|
) : `Already ${row2.approval_state}.`
|
|
9116
9207
|
);
|
|
@@ -9135,7 +9226,7 @@ function registerTask(program3) {
|
|
|
9135
9226
|
);
|
|
9136
9227
|
ok(
|
|
9137
9228
|
row,
|
|
9138
|
-
() => line(`${
|
|
9229
|
+
() => line(`${import_picocolors30.default.green(row.approval_state)} ${import_picocolors30.default.bold(row.title)}`)
|
|
9139
9230
|
);
|
|
9140
9231
|
})
|
|
9141
9232
|
);
|
|
@@ -9151,7 +9242,7 @@ function registerTask(program3) {
|
|
|
9151
9242
|
`/v1/project-tasks/${encodeURIComponent(id)}/move`,
|
|
9152
9243
|
{ body: { status: "ready" } }
|
|
9153
9244
|
);
|
|
9154
|
-
ok(row, () => line(`${
|
|
9245
|
+
ok(row, () => line(`${import_picocolors30.default.green("ready")} ${import_picocolors30.default.bold(row.title)}`));
|
|
9155
9246
|
})
|
|
9156
9247
|
);
|
|
9157
9248
|
}
|
|
@@ -9196,24 +9287,24 @@ function assertOneOf(flag, value, allowed) {
|
|
|
9196
9287
|
}
|
|
9197
9288
|
}
|
|
9198
9289
|
function formatRow2(r) {
|
|
9199
|
-
const key =
|
|
9200
|
-
const steps = r.subtaskTotal ?
|
|
9201
|
-
const gate = r.approval_state === "awaiting" ?
|
|
9290
|
+
const key = import_picocolors30.default.dim((r.key ?? r.id.slice(0, 8)).padEnd(10));
|
|
9291
|
+
const steps = r.subtaskTotal ? import_picocolors30.default.dim(` ${r.subtaskDone}/${r.subtaskTotal}`) : "";
|
|
9292
|
+
const gate = r.approval_state === "awaiting" ? import_picocolors30.default.yellow(" awaiting approval") : "";
|
|
9202
9293
|
return `${key} ${statusTag2(r.status)} ${r.title}${steps}${gate}`;
|
|
9203
9294
|
}
|
|
9204
9295
|
function formatSubtask(r, index) {
|
|
9205
|
-
const n =
|
|
9206
|
-
const role = r.role ?
|
|
9207
|
-
const scope = r.scope_paths?.length ?
|
|
9296
|
+
const n = import_picocolors30.default.dim(String(index).padStart(2, "0"));
|
|
9297
|
+
const role = r.role ? import_picocolors30.default.dim(` [${r.role}]`) : "";
|
|
9298
|
+
const scope = r.scope_paths?.length ? import_picocolors30.default.dim(` owns: ${r.scope_paths.join(", ")}`) : "";
|
|
9208
9299
|
const head = `${n} ${statusTag2(r.status)} ${r.title}${role}${scope}`;
|
|
9209
9300
|
const summary = (r.result_summary ?? "").trim();
|
|
9210
9301
|
if (!summary) return head;
|
|
9211
9302
|
const wrapped = summary.split("\n").map((l) => ` ${l}`).join("\n");
|
|
9212
9303
|
return `${head}
|
|
9213
|
-
${
|
|
9304
|
+
${import_picocolors30.default.dim(wrapped)}`;
|
|
9214
9305
|
}
|
|
9215
9306
|
function printTask(row, goal) {
|
|
9216
|
-
line(`${
|
|
9307
|
+
line(`${import_picocolors30.default.bold(row.title)} ${import_picocolors30.default.dim(row.key ?? row.id)}`);
|
|
9217
9308
|
line(`${statusTag2(row.status)} approval: ${row.approval_state}`);
|
|
9218
9309
|
if (row.summary) line(`
|
|
9219
9310
|
${row.summary}`);
|
|
@@ -9226,53 +9317,53 @@ touches: ${row.targets.map((t) => t.appName ?? t.ref ?? t.kind).join(", ")}`
|
|
|
9226
9317
|
}
|
|
9227
9318
|
if (row.subtasks?.length) {
|
|
9228
9319
|
line(`
|
|
9229
|
-
${
|
|
9320
|
+
${import_picocolors30.default.bold("subtasks")}`);
|
|
9230
9321
|
row.subtasks.forEach((s, i) => line(formatSubtask(s, i + 1)));
|
|
9231
9322
|
line(
|
|
9232
|
-
|
|
9323
|
+
import_picocolors30.default.dim(
|
|
9233
9324
|
`
|
|
9234
9325
|
Run \`workser artifact list\` to see what these subtasks produced,`
|
|
9235
9326
|
)
|
|
9236
9327
|
);
|
|
9237
9328
|
line(
|
|
9238
|
-
|
|
9329
|
+
import_picocolors30.default.dim(
|
|
9239
9330
|
`or \`workser artifact list --step <id>\` for one subtask's output alone.`
|
|
9240
9331
|
)
|
|
9241
9332
|
);
|
|
9242
9333
|
} else {
|
|
9243
|
-
line(
|
|
9334
|
+
line(import_picocolors30.default.dim("\nNo subtasks yet."));
|
|
9244
9335
|
}
|
|
9245
9336
|
}
|
|
9246
9337
|
function printGoalContext(row, goal) {
|
|
9247
9338
|
const mine = row.phase ?? null;
|
|
9248
9339
|
line(`
|
|
9249
|
-
${
|
|
9250
|
-
if (goal.outcome) line(
|
|
9340
|
+
${import_picocolors30.default.bold("part of")}: ${goal.title}`);
|
|
9341
|
+
if (goal.outcome) line(import_picocolors30.default.dim(`done means: ${goal.outcome}`));
|
|
9251
9342
|
const progress = goal.progress ?? [];
|
|
9252
9343
|
for (const p of progress) {
|
|
9253
9344
|
const where = p.total === 0 ? "not started" : `${p.done} of ${p.total} done`;
|
|
9254
|
-
const here = mine && p.name === mine ?
|
|
9255
|
-
const mark = p.state === "done" ?
|
|
9345
|
+
const here = mine && p.name === mine ? import_picocolors30.default.cyan(" <- this task") : "";
|
|
9346
|
+
const mark = p.state === "done" ? import_picocolors30.default.green("*") : import_picocolors30.default.dim("-");
|
|
9256
9347
|
line(` ${mark} ${p.name} \u2014 ${where}${here}`);
|
|
9257
9348
|
}
|
|
9258
9349
|
const next = progress.find((p) => p.state !== "done");
|
|
9259
9350
|
const running = progress.some((p) => p.state === "working");
|
|
9260
9351
|
if (next && !running) {
|
|
9261
9352
|
line(
|
|
9262
|
-
|
|
9353
|
+
import_picocolors30.default.dim(
|
|
9263
9354
|
`
|
|
9264
9355
|
Nothing is running. The next part waiting is "${next.name}" \u2014 offer it to them in a sentence rather than starting it unasked.`
|
|
9265
9356
|
)
|
|
9266
9357
|
);
|
|
9267
9358
|
} else if (!next) {
|
|
9268
9359
|
line(
|
|
9269
|
-
|
|
9360
|
+
import_picocolors30.default.dim(
|
|
9270
9361
|
"\nEvery part of this plan is done. Say so, and offer to wrap it up."
|
|
9271
9362
|
)
|
|
9272
9363
|
);
|
|
9273
9364
|
}
|
|
9274
9365
|
line(
|
|
9275
|
-
|
|
9366
|
+
import_picocolors30.default.dim(
|
|
9276
9367
|
"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."
|
|
9277
9368
|
)
|
|
9278
9369
|
);
|
|
@@ -9280,22 +9371,22 @@ Nothing is running. The next part waiting is "${next.name}" \u2014 offer it to t
|
|
|
9280
9371
|
function statusTag2(status) {
|
|
9281
9372
|
switch (status) {
|
|
9282
9373
|
case "ready":
|
|
9283
|
-
return
|
|
9374
|
+
return import_picocolors30.default.green("[ready]");
|
|
9284
9375
|
case "working":
|
|
9285
|
-
return
|
|
9376
|
+
return import_picocolors30.default.blue("[working]");
|
|
9286
9377
|
case "checking":
|
|
9287
|
-
return
|
|
9378
|
+
return import_picocolors30.default.cyan("[checking]");
|
|
9288
9379
|
case "accepted":
|
|
9289
|
-
return
|
|
9380
|
+
return import_picocolors30.default.green("[accepted]");
|
|
9290
9381
|
case "archived":
|
|
9291
|
-
return
|
|
9382
|
+
return import_picocolors30.default.dim("[archived]");
|
|
9292
9383
|
default:
|
|
9293
|
-
return
|
|
9384
|
+
return import_picocolors30.default.dim("[todo]");
|
|
9294
9385
|
}
|
|
9295
9386
|
}
|
|
9296
9387
|
|
|
9297
9388
|
// src/commands/goal.ts
|
|
9298
|
-
var
|
|
9389
|
+
var import_picocolors31 = __toESM(require_picocolors(), 1);
|
|
9299
9390
|
var STATUSES3 = ["proposed", "agreed", "working", "delivered", "abandoned"];
|
|
9300
9391
|
function registerGoal(program3) {
|
|
9301
9392
|
const goal = program3.command("goal").description("Business goals and the phases that deliver them");
|
|
@@ -9307,7 +9398,7 @@ function registerGoal(program3) {
|
|
|
9307
9398
|
}) ?? [];
|
|
9308
9399
|
ok(rows, () => {
|
|
9309
9400
|
if (!rows.length) {
|
|
9310
|
-
line(
|
|
9401
|
+
line(import_picocolors31.default.dim("No goals yet \u2014 every task here stands on its own."));
|
|
9311
9402
|
return;
|
|
9312
9403
|
}
|
|
9313
9404
|
for (const g of rows) line(formatGoal(g));
|
|
@@ -9384,10 +9475,10 @@ function registerGoal(program3) {
|
|
|
9384
9475
|
}
|
|
9385
9476
|
});
|
|
9386
9477
|
ok(row, () => {
|
|
9387
|
-
success(`Proposed ${
|
|
9478
|
+
success(`Proposed ${import_picocolors31.default.bold(row?.title ?? "goal")}`);
|
|
9388
9479
|
printGoal(row);
|
|
9389
9480
|
line(
|
|
9390
|
-
|
|
9481
|
+
import_picocolors31.default.dim(
|
|
9391
9482
|
"\nNothing has been created yet. The owner agrees the shape first."
|
|
9392
9483
|
)
|
|
9393
9484
|
);
|
|
@@ -9416,13 +9507,54 @@ function registerGoal(program3) {
|
|
|
9416
9507
|
ok(
|
|
9417
9508
|
row,
|
|
9418
9509
|
() => line(
|
|
9419
|
-
row?.recorded ? met === true ?
|
|
9510
|
+
row?.recorded ? met === true ? import_picocolors31.default.green("recorded \u2014 met") : met === false ? import_picocolors31.default.yellow("recorded \u2014 not met") : import_picocolors31.default.dim("recorded \u2014 back to unchecked") : import_picocolors31.default.yellow(
|
|
9420
9511
|
"couldn't record it \u2014 check the goal id, the phase name and the criterion id"
|
|
9421
9512
|
)
|
|
9422
9513
|
)
|
|
9423
9514
|
);
|
|
9424
9515
|
})
|
|
9425
9516
|
);
|
|
9517
|
+
goal.command("adopt <id>").description(
|
|
9518
|
+
"File tasks that already exist under a part of this plan \u2014 for work done before the plan was written"
|
|
9519
|
+
).option("--task <id...>", "the tasks to file under it").option("--phase <name>", "which part of the plan they belong to").action(
|
|
9520
|
+
action(async ({ ctx, args, opts }) => {
|
|
9521
|
+
requireProject(ctx);
|
|
9522
|
+
const goalId = String(args[0]);
|
|
9523
|
+
const taskIds = opts.task ?? [];
|
|
9524
|
+
if (!taskIds.length) {
|
|
9525
|
+
throw new WorkserError(
|
|
9526
|
+
"Name the tasks to file, e.g. `--task WORK-12 WORK-13`."
|
|
9527
|
+
);
|
|
9528
|
+
}
|
|
9529
|
+
const goal2 = await api(
|
|
9530
|
+
ctx,
|
|
9531
|
+
`/v1/project-goals/${encodeURIComponent(goalId)}`
|
|
9532
|
+
);
|
|
9533
|
+
if (!goal2) throw new WorkserError(`No goal ${goalId}.`);
|
|
9534
|
+
const names = (goal2.phases ?? []).map(
|
|
9535
|
+
(p) => typeof p === "string" ? p : p.name
|
|
9536
|
+
);
|
|
9537
|
+
const phase = String(opts.phase ?? "").trim();
|
|
9538
|
+
if (!phase || !names.includes(phase)) {
|
|
9539
|
+
throw new WorkserError(
|
|
9540
|
+
`--phase must be one of this goal's parts: ${names.join(", ")}.`
|
|
9541
|
+
);
|
|
9542
|
+
}
|
|
9543
|
+
const filed = [];
|
|
9544
|
+
for (const taskId of taskIds) {
|
|
9545
|
+
await api(ctx, `/v1/project-tasks/${encodeURIComponent(taskId)}`, {
|
|
9546
|
+
method: "PATCH",
|
|
9547
|
+
body: { goalId, phase }
|
|
9548
|
+
});
|
|
9549
|
+
filed.push(taskId);
|
|
9550
|
+
}
|
|
9551
|
+
ok({ goalId, phase, filed }, () => {
|
|
9552
|
+
success(
|
|
9553
|
+
`Filed ${filed.length} ${filed.length === 1 ? "task" : "tasks"} under ${import_picocolors31.default.bold(phase)}`
|
|
9554
|
+
);
|
|
9555
|
+
});
|
|
9556
|
+
})
|
|
9557
|
+
);
|
|
9426
9558
|
goal.command("update <id>").description("Change the shape, or move the goal along").option("--title <text>", "the owner's words for what they want").option("--outcome <text>", "what 'done' means").option("--phase <name...>", "replace the ordered phase list").option("--status <value>", `one of: ${STATUSES3.join(" | ")}`).action(
|
|
9427
9559
|
action(async ({ ctx, args, opts }) => {
|
|
9428
9560
|
if (opts.status && !STATUSES3.includes(opts.status)) {
|
|
@@ -9450,42 +9582,42 @@ function registerGoal(program3) {
|
|
|
9450
9582
|
function appScope(g) {
|
|
9451
9583
|
const n = g.appIds?.length ?? 0;
|
|
9452
9584
|
if (!n) return "";
|
|
9453
|
-
return
|
|
9585
|
+
return import_picocolors31.default.dim(` ${n} part${n === 1 ? "" : "s"} of the system`);
|
|
9454
9586
|
}
|
|
9455
9587
|
function formatGoal(g) {
|
|
9456
|
-
const where = g.currentPhase && g.status !== "delivered" ?
|
|
9457
|
-
const count = g.taskTotal != null ?
|
|
9458
|
-
return `${statusTag3(g.status)} ${g.title}${appScope(g)}${where}${count} ${
|
|
9588
|
+
const where = g.currentPhase && g.status !== "delivered" ? import_picocolors31.default.dim(` now: ${g.currentPhase}`) : "";
|
|
9589
|
+
const count = g.taskTotal != null ? import_picocolors31.default.dim(` ${g.taskDone}/${g.taskTotal} done`) : "";
|
|
9590
|
+
return `${statusTag3(g.status)} ${g.title}${appScope(g)}${where}${count} ${import_picocolors31.default.dim(g.id)}`;
|
|
9459
9591
|
}
|
|
9460
9592
|
function printGoal(g) {
|
|
9461
9593
|
if (!g) return;
|
|
9462
|
-
line(`${
|
|
9594
|
+
line(`${import_picocolors31.default.bold(g.title)} ${import_picocolors31.default.dim(g.id)}`);
|
|
9463
9595
|
line(statusTag3(g.status));
|
|
9464
9596
|
if (g.outcome) line(`
|
|
9465
9597
|
done means: ${g.outcome}`);
|
|
9466
9598
|
const progress = g.progress ?? [];
|
|
9467
9599
|
if (!progress.length) {
|
|
9468
|
-
line(
|
|
9600
|
+
line(import_picocolors31.default.dim("\nNo phases agreed yet."));
|
|
9469
9601
|
return;
|
|
9470
9602
|
}
|
|
9471
9603
|
line(`
|
|
9472
|
-
${
|
|
9604
|
+
${import_picocolors31.default.bold("phases")}`);
|
|
9473
9605
|
for (const p of progress) {
|
|
9474
|
-
const bar2 = p.total > 0 ? `${p.done}/${p.total} done` :
|
|
9475
|
-
const mark = p.state === "done" ?
|
|
9606
|
+
const bar2 = p.total > 0 ? `${p.done}/${p.total} done` : import_picocolors31.default.dim("nothing filed yet");
|
|
9607
|
+
const mark = p.state === "done" ? import_picocolors31.default.green("done") : p.state === "working" ? import_picocolors31.default.blue("working") : import_picocolors31.default.dim("waiting");
|
|
9476
9608
|
line(
|
|
9477
|
-
` ${
|
|
9609
|
+
` ${import_picocolors31.default.dim(String(p.index).padStart(2, "0"))} ${p.name} ${mark} ${import_picocolors31.default.dim(bar2)}`
|
|
9478
9610
|
);
|
|
9479
9611
|
for (const c of p.criteria ?? []) {
|
|
9480
|
-
const tick = c.met === true ?
|
|
9481
|
-
line(` ${tick} ${c.text} ${
|
|
9482
|
-
if (c.note) line(
|
|
9612
|
+
const tick = c.met === true ? import_picocolors31.default.green("\u2713") : c.met === false ? import_picocolors31.default.red("\u2717") : import_picocolors31.default.dim("\xB7");
|
|
9613
|
+
line(` ${tick} ${c.text} ${import_picocolors31.default.dim(c.id)}`);
|
|
9614
|
+
if (c.note) line(import_picocolors31.default.dim(` ${c.note}`));
|
|
9483
9615
|
}
|
|
9484
9616
|
}
|
|
9485
9617
|
const current = progress.find((p) => p.name === g.currentPhase);
|
|
9486
9618
|
if (current) {
|
|
9487
9619
|
line(
|
|
9488
|
-
|
|
9620
|
+
import_picocolors31.default.dim(
|
|
9489
9621
|
`
|
|
9490
9622
|
${current.name} \u2014 ${current.done} of ${current.total} done (phase ${current.index} of ${progress.length}).`
|
|
9491
9623
|
)
|
|
@@ -9495,15 +9627,15 @@ ${current.name} \u2014 ${current.done} of ${current.total} done (phase ${current
|
|
|
9495
9627
|
function statusTag3(status) {
|
|
9496
9628
|
switch (status) {
|
|
9497
9629
|
case "agreed":
|
|
9498
|
-
return
|
|
9630
|
+
return import_picocolors31.default.cyan("[agreed]");
|
|
9499
9631
|
case "working":
|
|
9500
|
-
return
|
|
9632
|
+
return import_picocolors31.default.blue("[working]");
|
|
9501
9633
|
case "delivered":
|
|
9502
|
-
return
|
|
9634
|
+
return import_picocolors31.default.green("[delivered]");
|
|
9503
9635
|
case "abandoned":
|
|
9504
|
-
return
|
|
9636
|
+
return import_picocolors31.default.dim("[abandoned]");
|
|
9505
9637
|
default:
|
|
9506
|
-
return
|
|
9638
|
+
return import_picocolors31.default.yellow("[proposed]");
|
|
9507
9639
|
}
|
|
9508
9640
|
}
|
|
9509
9641
|
|
|
@@ -9556,7 +9688,15 @@ var READS = [
|
|
|
9556
9688
|
// have `create` subcommands — these write the project's RECORD, not the
|
|
9557
9689
|
// project. What stops a reviewer editing code is its filesystem mode, and
|
|
9558
9690
|
// that is untouched.
|
|
9559
|
-
"artifact"
|
|
9691
|
+
"artifact",
|
|
9692
|
+
// LEAVING A FACT FOR THE TEAM IS NOT CHANGING THE PROJECT — the same
|
|
9693
|
+
// argument as `artifact` directly above, and it belongs in READS rather than
|
|
9694
|
+
// BUILDS on purpose. The roles that DISCOVER things are the reading ones: a
|
|
9695
|
+
// tester that found the real cause, an analyst that found the actual column
|
|
9696
|
+
// name, a security engineer that found where a key is read from. A shared
|
|
9697
|
+
// memory only builders could write to would be missing most of what is worth
|
|
9698
|
+
// sharing. See the daemon's `team-memory.ts`.
|
|
9699
|
+
"note"
|
|
9560
9700
|
];
|
|
9561
9701
|
var BUILDS = [
|
|
9562
9702
|
...READS,
|
|
@@ -9576,6 +9716,7 @@ var BUILDS = [
|
|
|
9576
9716
|
];
|
|
9577
9717
|
var ROLE_VERBS = {
|
|
9578
9718
|
pm: [...READS, "ask", "app"],
|
|
9719
|
+
// `note` reaches this via READS.
|
|
9579
9720
|
architect: [...BUILDS, "versions"],
|
|
9580
9721
|
web: BUILDS,
|
|
9581
9722
|
api: BUILDS,
|
|
@@ -9678,7 +9819,7 @@ function stripLeadingGlobalOptions(argv) {
|
|
|
9678
9819
|
}
|
|
9679
9820
|
|
|
9680
9821
|
// src/commands/decision.ts
|
|
9681
|
-
var
|
|
9822
|
+
var import_picocolors32 = __toESM(require_picocolors(), 1);
|
|
9682
9823
|
function registerDecision(program3) {
|
|
9683
9824
|
const decision = program3.command("decision").description("Read and record the project's architecture decisions");
|
|
9684
9825
|
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(
|
|
@@ -9691,11 +9832,11 @@ function registerDecision(program3) {
|
|
|
9691
9832
|
rows = applyLimit(rows, opts.limit);
|
|
9692
9833
|
ok(rows, () => {
|
|
9693
9834
|
if (!rows.length) {
|
|
9694
|
-
line(
|
|
9835
|
+
line(import_picocolors32.default.dim("No decisions recorded yet."));
|
|
9695
9836
|
return;
|
|
9696
9837
|
}
|
|
9697
9838
|
for (const r of rows) {
|
|
9698
|
-
line(`${
|
|
9839
|
+
line(`${import_picocolors32.default.dim(r.id)} ${import_picocolors32.default.dim(shortDate(r.createdAt))} ${r.title}`);
|
|
9699
9840
|
line(` ${truncate(r.decision, 100)}`);
|
|
9700
9841
|
}
|
|
9701
9842
|
});
|
|
@@ -9709,16 +9850,16 @@ function registerDecision(program3) {
|
|
|
9709
9850
|
`/v1/projects/${projectId}/architecture-decisions/${args[0]}`
|
|
9710
9851
|
);
|
|
9711
9852
|
ok(row, () => {
|
|
9712
|
-
line(`${
|
|
9713
|
-
line(
|
|
9853
|
+
line(`${import_picocolors32.default.bold(row.title)} ${import_picocolors32.default.dim(row.id)}`);
|
|
9854
|
+
line(import_picocolors32.default.dim(`${row.status} \xB7 ${shortDate(row.createdAt)}`));
|
|
9714
9855
|
line(`
|
|
9715
|
-
${
|
|
9856
|
+
${import_picocolors32.default.bold("Context")}
|
|
9716
9857
|
${row.context}`);
|
|
9717
9858
|
line(`
|
|
9718
|
-
${
|
|
9859
|
+
${import_picocolors32.default.bold("Decision")}
|
|
9719
9860
|
${row.decision}`);
|
|
9720
9861
|
if (row.consequences) line(`
|
|
9721
|
-
${
|
|
9862
|
+
${import_picocolors32.default.bold("Consequences")}
|
|
9722
9863
|
${row.consequences}`);
|
|
9723
9864
|
});
|
|
9724
9865
|
})
|
|
@@ -9747,7 +9888,7 @@ ${row.consequences}`);
|
|
|
9747
9888
|
refId: row?.id,
|
|
9748
9889
|
output: { decision: row }
|
|
9749
9890
|
});
|
|
9750
|
-
ok(row, () => line(`Recorded decision ${
|
|
9891
|
+
ok(row, () => line(`Recorded decision ${import_picocolors32.default.bold(row?.id ?? "")} \u2014 ${title}`));
|
|
9751
9892
|
})
|
|
9752
9893
|
);
|
|
9753
9894
|
const requirement = program3.command("requirement").description("Read and record the project's requirements");
|
|
@@ -9759,11 +9900,11 @@ ${row.consequences}`);
|
|
|
9759
9900
|
rows = applyLimit(rows, opts.limit);
|
|
9760
9901
|
ok(rows, () => {
|
|
9761
9902
|
if (!rows.length) {
|
|
9762
|
-
line(
|
|
9903
|
+
line(import_picocolors32.default.dim("No requirements recorded yet."));
|
|
9763
9904
|
return;
|
|
9764
9905
|
}
|
|
9765
9906
|
for (const r of rows) {
|
|
9766
|
-
line(`${
|
|
9907
|
+
line(`${import_picocolors32.default.dim(r.id)} ${r.status.padEnd(9)} ${r.title}`);
|
|
9767
9908
|
}
|
|
9768
9909
|
});
|
|
9769
9910
|
})
|
|
@@ -9776,8 +9917,8 @@ ${row.consequences}`);
|
|
|
9776
9917
|
`/v1/projects/${projectId}/requirements/${args[0]}`
|
|
9777
9918
|
);
|
|
9778
9919
|
ok(row, () => {
|
|
9779
|
-
line(`${
|
|
9780
|
-
line(
|
|
9920
|
+
line(`${import_picocolors32.default.bold(row.title)} ${import_picocolors32.default.dim(row.id)}`);
|
|
9921
|
+
line(import_picocolors32.default.dim(`${row.status} \xB7 ${shortDate(row.createdAt)}`));
|
|
9781
9922
|
line(`
|
|
9782
9923
|
${row.body}`);
|
|
9783
9924
|
});
|
|
@@ -9803,7 +9944,7 @@ ${row.body}`);
|
|
|
9803
9944
|
refId: row?.id,
|
|
9804
9945
|
output: { requirement: row }
|
|
9805
9946
|
});
|
|
9806
|
-
ok(row, () => line(`Recorded requirement ${
|
|
9947
|
+
ok(row, () => line(`Recorded requirement ${import_picocolors32.default.bold(row?.id ?? "")} \u2014 ${title}`));
|
|
9807
9948
|
})
|
|
9808
9949
|
);
|
|
9809
9950
|
requirement.command("update <id>").description(
|
|
@@ -9832,7 +9973,7 @@ ${row.body}`);
|
|
|
9832
9973
|
code: "bad_request"
|
|
9833
9974
|
});
|
|
9834
9975
|
}
|
|
9835
|
-
ok(row, () => line(`Updated requirement ${
|
|
9976
|
+
ok(row, () => line(`Updated requirement ${import_picocolors32.default.bold(row.id)} \u2014 ${row.title} (${row.status})`));
|
|
9836
9977
|
})
|
|
9837
9978
|
);
|
|
9838
9979
|
}
|
|
@@ -9855,7 +9996,7 @@ function shortDate(iso) {
|
|
|
9855
9996
|
}
|
|
9856
9997
|
|
|
9857
9998
|
// src/commands/doc.ts
|
|
9858
|
-
var
|
|
9999
|
+
var import_picocolors33 = __toESM(require_picocolors(), 1);
|
|
9859
10000
|
|
|
9860
10001
|
// src/mermaid-fences.ts
|
|
9861
10002
|
function hasDiagram(code) {
|
|
@@ -9900,13 +10041,13 @@ function registerDoc(program3) {
|
|
|
9900
10041
|
}) ?? [];
|
|
9901
10042
|
ok(rows, () => {
|
|
9902
10043
|
if (!rows.length) {
|
|
9903
|
-
line(
|
|
10044
|
+
line(import_picocolors33.default.dim("No documents yet."));
|
|
9904
10045
|
return;
|
|
9905
10046
|
}
|
|
9906
10047
|
for (const r of rows) {
|
|
9907
|
-
const link = r.workItemId ?
|
|
9908
|
-
const file = r.filePath ?
|
|
9909
|
-
line(`${
|
|
10048
|
+
const link = r.workItemId ? import_picocolors33.default.dim(` \u21B3 ${r.workItemId}`) : "";
|
|
10049
|
+
const file = r.filePath ? import_picocolors33.default.dim(` ${r.filePath}`) : "";
|
|
10050
|
+
line(`${import_picocolors33.default.dim(r.id)} ${r.title}${link}${file}`);
|
|
9910
10051
|
}
|
|
9911
10052
|
});
|
|
9912
10053
|
})
|
|
@@ -9920,17 +10061,17 @@ function registerDoc(program3) {
|
|
|
9920
10061
|
);
|
|
9921
10062
|
if (opts.markdown) {
|
|
9922
10063
|
ok({ id: row.id, title: row.title, filePath: row.filePath }, () => {
|
|
9923
|
-
line(`${
|
|
10064
|
+
line(`${import_picocolors33.default.bold(row.title)} ${import_picocolors33.default.dim(row.id)}`);
|
|
9924
10065
|
line(
|
|
9925
|
-
row.filePath ? `Read it at ${
|
|
10066
|
+
row.filePath ? `Read it at ${import_picocolors33.default.bold(row.filePath)} (relative to the project folder).` : import_picocolors33.default.dim("This document has no markdown mirror on disk yet.")
|
|
9926
10067
|
);
|
|
9927
10068
|
});
|
|
9928
10069
|
return;
|
|
9929
10070
|
}
|
|
9930
10071
|
ok(row, () => {
|
|
9931
|
-
line(`${
|
|
9932
|
-
if (row.workItemId) line(
|
|
9933
|
-
if (row.filePath) line(
|
|
10072
|
+
line(`${import_picocolors33.default.bold(row.title)} ${import_picocolors33.default.dim(row.id)}`);
|
|
10073
|
+
if (row.workItemId) line(import_picocolors33.default.dim(`linked to work item ${row.workItemId}`));
|
|
10074
|
+
if (row.filePath) line(import_picocolors33.default.dim(`markdown mirror: ${row.filePath}`));
|
|
9934
10075
|
line("");
|
|
9935
10076
|
line(row.contentJson);
|
|
9936
10077
|
});
|
|
@@ -9959,7 +10100,7 @@ function registerDoc(program3) {
|
|
|
9959
10100
|
refId: row?.id,
|
|
9960
10101
|
output: { document: row }
|
|
9961
10102
|
});
|
|
9962
|
-
ok(row, () => line(`Created document ${
|
|
10103
|
+
ok(row, () => line(`Created document ${import_picocolors33.default.bold(row?.id ?? "")} \u2014 ${title}`));
|
|
9963
10104
|
})
|
|
9964
10105
|
);
|
|
9965
10106
|
doc.command("diagram <id>").description(
|
|
@@ -9985,19 +10126,19 @@ function registerDoc(program3) {
|
|
|
9985
10126
|
diagrams: diagrams.map((code) => ({ kind: diagramKind(code), code }))
|
|
9986
10127
|
};
|
|
9987
10128
|
ok(payload, () => {
|
|
9988
|
-
line(`${
|
|
10129
|
+
line(`${import_picocolors33.default.bold(row.title)} ${import_picocolors33.default.dim(row.id)}`);
|
|
9989
10130
|
if (markdown === null) {
|
|
9990
10131
|
line(
|
|
9991
|
-
|
|
10132
|
+
import_picocolors33.default.dim(
|
|
9992
10133
|
row.filePath ? `Could not read ${row.filePath} from this folder.` : "This document has no markdown mirror on disk yet."
|
|
9993
10134
|
)
|
|
9994
10135
|
);
|
|
9995
10136
|
} else if (!diagrams.length) {
|
|
9996
|
-
line(
|
|
10137
|
+
line(import_picocolors33.default.dim("No diagrams in this document."));
|
|
9997
10138
|
} else {
|
|
9998
10139
|
for (const [i, code] of diagrams.entries()) {
|
|
9999
10140
|
const kind = diagramKind(code) ?? "diagram";
|
|
10000
|
-
line(`${
|
|
10141
|
+
line(`${import_picocolors33.default.dim(String(i + 1))} ${kind} ${import_picocolors33.default.dim(`${code.split("\n").length} lines`)}`);
|
|
10001
10142
|
}
|
|
10002
10143
|
}
|
|
10003
10144
|
});
|
|
@@ -10033,7 +10174,7 @@ function registerDoc(program3) {
|
|
|
10033
10174
|
code: "bad_request"
|
|
10034
10175
|
});
|
|
10035
10176
|
}
|
|
10036
|
-
ok(row, () => line(`Updated document ${
|
|
10177
|
+
ok(row, () => line(`Updated document ${import_picocolors33.default.bold(row.id)} \u2014 ${row.title}`));
|
|
10037
10178
|
})
|
|
10038
10179
|
);
|
|
10039
10180
|
}
|
|
@@ -10047,7 +10188,7 @@ function readMirror(cwd, filePath) {
|
|
|
10047
10188
|
}
|
|
10048
10189
|
|
|
10049
10190
|
// src/commands/design.ts
|
|
10050
|
-
var
|
|
10191
|
+
var import_picocolors34 = __toESM(require_picocolors(), 1);
|
|
10051
10192
|
function registerDesign(program3) {
|
|
10052
10193
|
const design = program3.command("design").description("Read the project's brand (colours, fonts, logo)");
|
|
10053
10194
|
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(
|
|
@@ -10061,11 +10202,11 @@ function registerDesign(program3) {
|
|
|
10061
10202
|
if (opts.raw) {
|
|
10062
10203
|
ok(files, () => {
|
|
10063
10204
|
if (!files.length) {
|
|
10064
|
-
line(
|
|
10205
|
+
line(import_picocolors34.default.dim("No brand set for this project."));
|
|
10065
10206
|
return;
|
|
10066
10207
|
}
|
|
10067
10208
|
for (const f of files) {
|
|
10068
|
-
line(
|
|
10209
|
+
line(import_picocolors34.default.bold(f.path));
|
|
10069
10210
|
line(f.contents);
|
|
10070
10211
|
line("");
|
|
10071
10212
|
}
|
|
@@ -10082,21 +10223,21 @@ function registerDesign(program3) {
|
|
|
10082
10223
|
} : { hasBrand: false, colors: {}, fonts: {}, brand: {}, files: [] };
|
|
10083
10224
|
ok(summary, () => {
|
|
10084
10225
|
if (!tokens) {
|
|
10085
|
-
line(
|
|
10226
|
+
line(import_picocolors34.default.dim("No brand set for this project \u2014 choose sensible styling yourself."));
|
|
10086
10227
|
return;
|
|
10087
10228
|
}
|
|
10088
10229
|
for (const [name, value] of Object.entries(tokens.brand)) {
|
|
10089
|
-
line(`${
|
|
10230
|
+
line(`${import_picocolors34.default.dim(name.padEnd(12))} ${value}`);
|
|
10090
10231
|
}
|
|
10091
10232
|
for (const [name, value] of Object.entries(tokens.color)) {
|
|
10092
|
-
line(`${
|
|
10233
|
+
line(`${import_picocolors34.default.dim(`color.${name}`.padEnd(12))} ${value}`);
|
|
10093
10234
|
}
|
|
10094
10235
|
for (const [name, value] of Object.entries(tokens.font)) {
|
|
10095
|
-
line(`${
|
|
10236
|
+
line(`${import_picocolors34.default.dim(`font.${name}`.padEnd(12))} ${value}`);
|
|
10096
10237
|
}
|
|
10097
10238
|
line("");
|
|
10098
10239
|
line(
|
|
10099
|
-
|
|
10240
|
+
import_picocolors34.default.dim(
|
|
10100
10241
|
`Generated into the working tree as ${files.map((f) => f.path).join(", ")} \u2014 wire those in, never edit them.`
|
|
10101
10242
|
)
|
|
10102
10243
|
);
|
|
@@ -10127,7 +10268,7 @@ function unwrap(group) {
|
|
|
10127
10268
|
}
|
|
10128
10269
|
|
|
10129
10270
|
// src/commands/api.ts
|
|
10130
|
-
var
|
|
10271
|
+
var import_picocolors35 = __toESM(require_picocolors(), 1);
|
|
10131
10272
|
import { readdirSync, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
|
|
10132
10273
|
import { join as join3, relative, sep } from "path";
|
|
10133
10274
|
|
|
@@ -10241,10 +10382,10 @@ function registerApi(program3) {
|
|
|
10241
10382
|
const appId = requireApp2(opts.app);
|
|
10242
10383
|
const res = await api(ctx, `/v1/apps/${encodeURIComponent(appId)}/api/requests`);
|
|
10243
10384
|
ok(res, () => {
|
|
10244
|
-
for (const note of res?.notes ?? []) line(
|
|
10385
|
+
for (const note of res?.notes ?? []) line(import_picocolors35.default.dim(note));
|
|
10245
10386
|
for (const r of res?.requests ?? []) {
|
|
10246
10387
|
line(
|
|
10247
|
-
`${
|
|
10388
|
+
`${import_picocolors35.default.dim(r.method.padEnd(6))}${r.path}${r.note ? import_picocolors35.default.dim(` ${r.note}`) : ""}`
|
|
10248
10389
|
);
|
|
10249
10390
|
}
|
|
10250
10391
|
});
|
|
@@ -10278,14 +10419,14 @@ function registerApi(program3) {
|
|
|
10278
10419
|
);
|
|
10279
10420
|
ok(res, () => {
|
|
10280
10421
|
if (!res?.ok) {
|
|
10281
|
-
line(
|
|
10422
|
+
line(import_picocolors35.default.red(res?.error ?? "The service did not answer."));
|
|
10282
10423
|
return;
|
|
10283
10424
|
}
|
|
10284
10425
|
const code = `${res.status}${res.statusText ? ` ${res.statusText}` : ""}`;
|
|
10285
|
-
const colour2 = res.status && res.status < 300 ?
|
|
10286
|
-
line(`${colour2(code)} ${
|
|
10426
|
+
const colour2 = res.status && res.status < 300 ? import_picocolors35.default.green : res.status && res.status < 500 ? import_picocolors35.default.yellow : import_picocolors35.default.red;
|
|
10427
|
+
line(`${colour2(code)} ${import_picocolors35.default.dim(`${res.durationMs}ms ${res.url}`)}`);
|
|
10287
10428
|
if (res.body) line(res.body);
|
|
10288
|
-
if (res.truncated) line(
|
|
10429
|
+
if (res.truncated) line(import_picocolors35.default.dim("(answer truncated)"));
|
|
10289
10430
|
});
|
|
10290
10431
|
if (!res?.ok) process.exitCode = 1;
|
|
10291
10432
|
})
|
|
@@ -10305,15 +10446,15 @@ function registerApi(program3) {
|
|
|
10305
10446
|
for (const r of report.routes) {
|
|
10306
10447
|
const known = report.missing.some((m) => m.path === r.path);
|
|
10307
10448
|
line(
|
|
10308
|
-
`${known ?
|
|
10449
|
+
`${known ? import_picocolors35.default.yellow("undocumented") : import_picocolors35.default.green("documented ")} ${r.path}${import_picocolors35.default.dim(` ${r.file}`)}`
|
|
10309
10450
|
);
|
|
10310
10451
|
}
|
|
10311
10452
|
for (const p of report.stale) {
|
|
10312
|
-
line(`${
|
|
10453
|
+
line(`${import_picocolors35.default.dim("in spec only ")} ${p}`);
|
|
10313
10454
|
}
|
|
10314
10455
|
line("");
|
|
10315
10456
|
if (report.ok && specFile) success(summary);
|
|
10316
|
-
else line(
|
|
10457
|
+
else line(import_picocolors35.default.yellow(summary));
|
|
10317
10458
|
});
|
|
10318
10459
|
if (opts.check && !report.ok) {
|
|
10319
10460
|
throw new WorkserError(summary, { code: "bad_request" });
|
|
@@ -10384,7 +10525,7 @@ function listRepoFiles(root, maxDepth = 8) {
|
|
|
10384
10525
|
}
|
|
10385
10526
|
|
|
10386
10527
|
// src/commands/analysis.ts
|
|
10387
|
-
var
|
|
10528
|
+
var import_picocolors36 = __toESM(require_picocolors(), 1);
|
|
10388
10529
|
import { readFileSync as readFileSync4 } from "fs";
|
|
10389
10530
|
function registerAnalysis(program3) {
|
|
10390
10531
|
const cmd = program3.command("analysis").description("Run Python analysis locally, recorded in the task");
|
|
@@ -10394,14 +10535,14 @@ function registerAnalysis(program3) {
|
|
|
10394
10535
|
const res = await api(ctx, path);
|
|
10395
10536
|
ok(res, () => {
|
|
10396
10537
|
line(
|
|
10397
|
-
`${res?.available ?
|
|
10538
|
+
`${res?.available ? import_picocolors36.default.green("python") : import_picocolors36.default.red("python")} ${res?.version ?? "not found"} ${import_picocolors36.default.dim(res?.python ?? "")}`
|
|
10398
10539
|
);
|
|
10399
10540
|
for (const lib of res?.libraries ?? []) {
|
|
10400
10541
|
line(
|
|
10401
|
-
`${lib.present ?
|
|
10542
|
+
`${lib.present ? import_picocolors36.default.green(lib.name) : import_picocolors36.default.yellow(lib.name)}${import_picocolors36.default.dim(lib.present ? "" : " missing")}`
|
|
10402
10543
|
);
|
|
10403
10544
|
}
|
|
10404
|
-
for (const note of res?.notes ?? []) line(
|
|
10545
|
+
for (const note of res?.notes ?? []) line(import_picocolors36.default.dim(note));
|
|
10405
10546
|
});
|
|
10406
10547
|
if (!res?.available) process.exitCode = 1;
|
|
10407
10548
|
})
|
|
@@ -10423,15 +10564,15 @@ function registerAnalysis(program3) {
|
|
|
10423
10564
|
);
|
|
10424
10565
|
ok(res, () => {
|
|
10425
10566
|
if (res?.stdout) line(res.stdout.replace(/\n$/, ""));
|
|
10426
|
-
if (res?.stderr) line(
|
|
10427
|
-
if (res?.truncated) line(
|
|
10567
|
+
if (res?.stderr) line(import_picocolors36.default.dim(res.stderr.replace(/\n$/, "")));
|
|
10568
|
+
if (res?.truncated) line(import_picocolors36.default.dim("(output truncated)"));
|
|
10428
10569
|
const took = `${Math.round((res?.durationMs ?? 0) / 100) / 10}s`;
|
|
10429
10570
|
line(
|
|
10430
|
-
res?.ok ?
|
|
10571
|
+
res?.ok ? import_picocolors36.default.green(`\u2713 ${res.summary ?? "It finished."}`) + import_picocolors36.default.dim(` ${took}`) : import_picocolors36.default.yellow(res?.summary ?? "It did not finish.") + import_picocolors36.default.dim(` ${took}`)
|
|
10431
10572
|
);
|
|
10432
10573
|
if (res && !res.sandboxed) {
|
|
10433
10574
|
line(
|
|
10434
|
-
|
|
10575
|
+
import_picocolors36.default.dim(
|
|
10435
10576
|
"This platform has no OS sandbox, so the script ran with your own file access."
|
|
10436
10577
|
)
|
|
10437
10578
|
);
|
|
@@ -10459,7 +10600,7 @@ function readCode(file, inline) {
|
|
|
10459
10600
|
}
|
|
10460
10601
|
|
|
10461
10602
|
// src/commands/scan.ts
|
|
10462
|
-
var
|
|
10603
|
+
var import_picocolors37 = __toESM(require_picocolors(), 1);
|
|
10463
10604
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
10464
10605
|
import { existsSync as existsSync3, readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync3 } from "fs";
|
|
10465
10606
|
import { join as join4, relative as relative2, sep as sep2 } from "path";
|
|
@@ -10743,22 +10884,22 @@ function runPermissions(cwd, findings, checked, skipped) {
|
|
|
10743
10884
|
}
|
|
10744
10885
|
function print2(report, summary) {
|
|
10745
10886
|
for (const s of report.skipped) {
|
|
10746
|
-
line(`${
|
|
10887
|
+
line(`${import_picocolors37.default.yellow("not checked")} ${s.check}${import_picocolors37.default.dim(` \u2014 ${s.reason}`)}`);
|
|
10747
10888
|
}
|
|
10748
10889
|
for (const f of report.findings) {
|
|
10749
|
-
const where = f.file ?
|
|
10890
|
+
const where = f.file ? import_picocolors37.default.dim(` ${f.file}${f.line ? `:${f.line}` : ""}`) : "";
|
|
10750
10891
|
line(`${severityTag(f.severity)} ${f.title}${where}`);
|
|
10751
|
-
line(` ${
|
|
10892
|
+
line(` ${import_picocolors37.default.dim(f.fix)}`);
|
|
10752
10893
|
}
|
|
10753
10894
|
if (report.findings.length || report.skipped.length) line("");
|
|
10754
10895
|
if (report.ok && !report.skipped.length) success(summary);
|
|
10755
|
-
else if (report.ok) line(
|
|
10756
|
-
else line(
|
|
10896
|
+
else if (report.ok) line(import_picocolors37.default.yellow(summary));
|
|
10897
|
+
else line(import_picocolors37.default.red(summary));
|
|
10757
10898
|
}
|
|
10758
10899
|
function severityTag(severity) {
|
|
10759
|
-
if (severity === "high") return
|
|
10760
|
-
if (severity === "medium") return
|
|
10761
|
-
return
|
|
10900
|
+
if (severity === "high") return import_picocolors37.default.red("serious ");
|
|
10901
|
+
if (severity === "medium") return import_picocolors37.default.yellow("worth fixing");
|
|
10902
|
+
return import_picocolors37.default.dim("minor ");
|
|
10762
10903
|
}
|
|
10763
10904
|
function git(cwd, args) {
|
|
10764
10905
|
try {
|
|
@@ -10819,7 +10960,7 @@ function listRepoFiles2(root, maxDepth = 8) {
|
|
|
10819
10960
|
}
|
|
10820
10961
|
|
|
10821
10962
|
// src/commands/health.ts
|
|
10822
|
-
var
|
|
10963
|
+
var import_picocolors38 = __toESM(require_picocolors(), 1);
|
|
10823
10964
|
function registerHealth(program3) {
|
|
10824
10965
|
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(
|
|
10825
10966
|
action(async ({ ctx, opts }) => {
|
|
@@ -10833,16 +10974,16 @@ function registerHealth(program3) {
|
|
|
10833
10974
|
}
|
|
10834
10975
|
function print3(res) {
|
|
10835
10976
|
if (!res?.checks?.length) {
|
|
10836
|
-
line(
|
|
10977
|
+
line(import_picocolors38.default.dim(res?.note ?? "Nothing to check."));
|
|
10837
10978
|
return;
|
|
10838
10979
|
}
|
|
10839
10980
|
for (const c of res.checks) {
|
|
10840
|
-
const mark = c.ok ?
|
|
10841
|
-
const timing =
|
|
10842
|
-
const detail = c.ok ? timing :
|
|
10843
|
-
line(` ${mark} ${c.appName} ${
|
|
10981
|
+
const mark = c.ok ? import_picocolors38.default.green("up ") : import_picocolors38.default.red("down");
|
|
10982
|
+
const timing = import_picocolors38.default.dim(`${c.ms}ms`);
|
|
10983
|
+
const detail = c.ok ? timing : import_picocolors38.default.dim(`${c.error ?? "no answer"}${c.failures > 1 ? ` \xB7 ${c.failures} in a row` : ""}`);
|
|
10984
|
+
line(` ${mark} ${c.appName} ${import_picocolors38.default.dim(`(${c.environment})`)} ${c.url} ${detail}`);
|
|
10844
10985
|
if (c.incidentOpened) {
|
|
10845
|
-
line(
|
|
10986
|
+
line(import_picocolors38.default.yellow(` An incident has been opened on the board for this.`));
|
|
10846
10987
|
}
|
|
10847
10988
|
}
|
|
10848
10989
|
const down = res.checks.filter((c) => !c.ok);
|
|
@@ -10855,14 +10996,14 @@ function print3(res) {
|
|
|
10855
10996
|
}
|
|
10856
10997
|
const production = down.filter((c) => c.environment === "production").length;
|
|
10857
10998
|
line(
|
|
10858
|
-
|
|
10999
|
+
import_picocolors38.default.red(
|
|
10859
11000
|
`${down.length} of ${res.checks.length} not answering` + (production ? ` \u2014 ${production} customer-facing.` : " (preview only).")
|
|
10860
11001
|
)
|
|
10861
11002
|
);
|
|
10862
11003
|
}
|
|
10863
11004
|
|
|
10864
11005
|
// src/commands/urls.ts
|
|
10865
|
-
var
|
|
11006
|
+
var import_picocolors39 = __toESM(require_picocolors(), 1);
|
|
10866
11007
|
function registerUrls(program3) {
|
|
10867
11008
|
program3.command("urls").description("The stable preview and production addresses of every app in this project").option("--app <webAppId>", "just one app").action(
|
|
10868
11009
|
action(async ({ ctx, opts }) => {
|
|
@@ -10876,20 +11017,20 @@ function registerUrls(program3) {
|
|
|
10876
11017
|
const summary = urlsSummary(rows);
|
|
10877
11018
|
ok({ rows, summary }, () => {
|
|
10878
11019
|
for (const row of rows) {
|
|
10879
|
-
const label =
|
|
10880
|
-
const value = row.url ?
|
|
11020
|
+
const label = import_picocolors39.default.dim(row.environment.padEnd(10));
|
|
11021
|
+
const value = row.url ? import_picocolors39.default.cyan(row.url) : import_picocolors39.default.dim(row.note ?? "not published");
|
|
10881
11022
|
line(` ${row.appName.padEnd(22)} ${label} ${value}`);
|
|
10882
11023
|
}
|
|
10883
11024
|
line("");
|
|
10884
11025
|
if (rows.some((r) => r.url)) success(summary);
|
|
10885
|
-
else line(
|
|
11026
|
+
else line(import_picocolors39.default.yellow(summary));
|
|
10886
11027
|
});
|
|
10887
11028
|
})
|
|
10888
11029
|
);
|
|
10889
11030
|
}
|
|
10890
11031
|
|
|
10891
11032
|
// src/commands/deployments.ts
|
|
10892
|
-
var
|
|
11033
|
+
var import_picocolors40 = __toESM(require_picocolors(), 1);
|
|
10893
11034
|
function registerDeployments(program3) {
|
|
10894
11035
|
const cmd = program3.command("deployments").description("Deployment history, and putting a build in front of customers");
|
|
10895
11036
|
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(
|
|
@@ -10907,7 +11048,7 @@ function registerDeployments(program3) {
|
|
|
10907
11048
|
ok(res, () => {
|
|
10908
11049
|
if (!items.length) {
|
|
10909
11050
|
return line(
|
|
10910
|
-
|
|
11051
|
+
import_picocolors40.default.dim(
|
|
10911
11052
|
environment ? `Nothing has been deployed to ${environment} yet.` : "Nothing has been deployed yet. `workser deploy` builds the first one."
|
|
10912
11053
|
)
|
|
10913
11054
|
);
|
|
@@ -10927,13 +11068,13 @@ function registerDeployments(program3) {
|
|
|
10927
11068
|
).catch(() => null) : null;
|
|
10928
11069
|
ok({ ...dep, logs }, () => {
|
|
10929
11070
|
line(formatDeployment(dep));
|
|
10930
|
-
if (dep?.error_message) line(
|
|
11071
|
+
if (dep?.error_message) line(import_picocolors40.default.red(` ${dep.error_message}`));
|
|
10931
11072
|
const events = logs?.events ?? [];
|
|
10932
11073
|
for (const e of events) {
|
|
10933
|
-
line(` ${
|
|
11074
|
+
line(` ${import_picocolors40.default.dim(String(e.type ?? "log"))} ${e.text ?? ""}`);
|
|
10934
11075
|
}
|
|
10935
11076
|
if (opts.logs && !events.length) {
|
|
10936
|
-
line(
|
|
11077
|
+
line(import_picocolors40.default.dim(" That build produced no output."));
|
|
10937
11078
|
}
|
|
10938
11079
|
});
|
|
10939
11080
|
})
|
|
@@ -10977,16 +11118,16 @@ function printPromoted(res, version) {
|
|
|
10977
11118
|
const what = version === null ? "the latest build" : `version ${version}`;
|
|
10978
11119
|
const url = res.url ?? res.vercel_url;
|
|
10979
11120
|
success(`Production is being rebuilt from ${what}.`);
|
|
10980
|
-
if (url) line(
|
|
10981
|
-
line(
|
|
11121
|
+
if (url) line(import_picocolors40.default.dim(`It will be at ${url}`));
|
|
11122
|
+
line(import_picocolors40.default.dim("`workser deploy status` follows it."));
|
|
10982
11123
|
}
|
|
10983
11124
|
function formatDeployment(d) {
|
|
10984
11125
|
if (!d) return "";
|
|
10985
|
-
const version = d.version !== void 0 ?
|
|
10986
|
-
const env =
|
|
11126
|
+
const version = d.version !== void 0 ? import_picocolors40.default.yellow(`v${d.version}`) : import_picocolors40.default.dim("v?");
|
|
11127
|
+
const env = import_picocolors40.default.dim((d.environment ?? "?").padEnd(10));
|
|
10987
11128
|
const app = d.webAppName ? `${d.webAppName} ` : "";
|
|
10988
|
-
const when =
|
|
10989
|
-
const url = d.url ? " " +
|
|
11129
|
+
const when = import_picocolors40.default.dim(formatTime2(d.created_at));
|
|
11130
|
+
const url = d.url ? " " + import_picocolors40.default.cyan(d.url) : "";
|
|
10990
11131
|
return `${version} ${env} ${colorStatus(d.status ?? "")} ${app}${when}${url}`;
|
|
10991
11132
|
}
|
|
10992
11133
|
function formatTime2(t) {
|
|
@@ -10996,7 +11137,7 @@ function formatTime2(t) {
|
|
|
10996
11137
|
}
|
|
10997
11138
|
|
|
10998
11139
|
// src/commands/usage.ts
|
|
10999
|
-
var
|
|
11140
|
+
var import_picocolors41 = __toESM(require_picocolors(), 1);
|
|
11000
11141
|
|
|
11001
11142
|
// src/usage.ts
|
|
11002
11143
|
var NEAR_LIMIT_FRACTION = 0.8;
|
|
@@ -11091,7 +11232,7 @@ function registerUsage(program3) {
|
|
|
11091
11232
|
function print4(report) {
|
|
11092
11233
|
const dims = report.dimensions ?? [];
|
|
11093
11234
|
if (!dims.length) {
|
|
11094
|
-
return line(
|
|
11235
|
+
return line(import_picocolors41.default.dim("Nothing to measure for this project yet."));
|
|
11095
11236
|
}
|
|
11096
11237
|
const width = Math.max(...dims.map((d) => d.label.length));
|
|
11097
11238
|
for (const d of dims) {
|
|
@@ -11100,23 +11241,23 @@ function print4(report) {
|
|
|
11100
11241
|
line("");
|
|
11101
11242
|
const summary = usageSummary(report);
|
|
11102
11243
|
const worst = dims.map(usageState);
|
|
11103
|
-
if (worst.includes("over")) line(
|
|
11244
|
+
if (worst.includes("over")) line(import_picocolors41.default.red(summary));
|
|
11104
11245
|
else if (worst.includes("near") || worst.includes("unknown"))
|
|
11105
|
-
line(
|
|
11246
|
+
line(import_picocolors41.default.yellow(summary));
|
|
11106
11247
|
else success(summary);
|
|
11107
11248
|
}
|
|
11108
11249
|
function gauge(d, _labelWidth) {
|
|
11109
11250
|
const drawn = bar(d);
|
|
11110
|
-
return drawn ? ` ${
|
|
11251
|
+
return drawn ? ` ${import_picocolors41.default.dim(drawn)}` : "";
|
|
11111
11252
|
}
|
|
11112
11253
|
function colour(d) {
|
|
11113
11254
|
switch (usageState(d)) {
|
|
11114
11255
|
case "over":
|
|
11115
|
-
return d.kind === "hard" ?
|
|
11256
|
+
return d.kind === "hard" ? import_picocolors41.default.red : import_picocolors41.default.yellow;
|
|
11116
11257
|
case "near":
|
|
11117
|
-
return
|
|
11258
|
+
return import_picocolors41.default.yellow;
|
|
11118
11259
|
case "unknown":
|
|
11119
|
-
return
|
|
11260
|
+
return import_picocolors41.default.dim;
|
|
11120
11261
|
default:
|
|
11121
11262
|
return (s) => s;
|
|
11122
11263
|
}
|
|
@@ -11124,7 +11265,7 @@ function colour(d) {
|
|
|
11124
11265
|
|
|
11125
11266
|
// src/index.ts
|
|
11126
11267
|
var pkg = {
|
|
11127
|
-
version: true ? "0.6.
|
|
11268
|
+
version: true ? "0.6.13" : "0.0.0-dev"
|
|
11128
11269
|
};
|
|
11129
11270
|
var program2 = new Command();
|
|
11130
11271
|
program2.name("workser").description(
|
|
@@ -11171,6 +11312,7 @@ registerWorkflow(program2);
|
|
|
11171
11312
|
registerConnection(program2);
|
|
11172
11313
|
registerTool(program2);
|
|
11173
11314
|
registerMemory(program2);
|
|
11315
|
+
registerNote(program2);
|
|
11174
11316
|
registerBusiness(program2);
|
|
11175
11317
|
registerArtifact(program2);
|
|
11176
11318
|
registerImage(program2);
|