@workser/cli 0.6.10 → 0.6.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +125 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8639,7 +8639,58 @@ function collect2(value, previous) {
|
|
|
8639
8639
|
|
|
8640
8640
|
// src/commands/task.ts
|
|
8641
8641
|
var import_picocolors29 = __toESM(require_picocolors(), 1);
|
|
8642
|
+
|
|
8643
|
+
// src/subtask-attachments.ts
|
|
8644
|
+
var MAX_REF_NOTE = 500;
|
|
8645
|
+
var MAX_REFS = 20;
|
|
8646
|
+
var URL_SCHEME = /^https?:\/\//i;
|
|
8647
|
+
function labelFor(type, value) {
|
|
8648
|
+
if (type === "url") {
|
|
8649
|
+
try {
|
|
8650
|
+
return new URL(value).hostname.replace(/^www\./, "");
|
|
8651
|
+
} catch {
|
|
8652
|
+
return value;
|
|
8653
|
+
}
|
|
8654
|
+
}
|
|
8655
|
+
const parts = value.split(/[\\/]/).filter(Boolean);
|
|
8656
|
+
return parts[parts.length - 1] || value;
|
|
8657
|
+
}
|
|
8658
|
+
function parseRef(raw) {
|
|
8659
|
+
const at = raw.indexOf("::");
|
|
8660
|
+
const value = (at === -1 ? raw : raw.slice(0, at)).trim();
|
|
8661
|
+
if (!value) return null;
|
|
8662
|
+
const note = at === -1 ? "" : raw.slice(at + 2).trim().slice(0, MAX_REF_NOTE);
|
|
8663
|
+
const type = URL_SCHEME.test(value) ? "url" : "file";
|
|
8664
|
+
return {
|
|
8665
|
+
type,
|
|
8666
|
+
value,
|
|
8667
|
+
label: labelFor(type, value),
|
|
8668
|
+
...note ? { note } : {}
|
|
8669
|
+
};
|
|
8670
|
+
}
|
|
8671
|
+
function parseRefs(raw) {
|
|
8672
|
+
if (!raw?.length) return [];
|
|
8673
|
+
const out = [];
|
|
8674
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8675
|
+
for (const item of raw) {
|
|
8676
|
+
const parsed = parseRef(item);
|
|
8677
|
+
if (!parsed) continue;
|
|
8678
|
+
if (seen.has(parsed.value)) continue;
|
|
8679
|
+
seen.add(parsed.value);
|
|
8680
|
+
out.push(parsed);
|
|
8681
|
+
}
|
|
8682
|
+
return out.slice(0, MAX_REFS);
|
|
8683
|
+
}
|
|
8684
|
+
|
|
8685
|
+
// src/commands/task.ts
|
|
8642
8686
|
var STATUSES2 = [
|
|
8687
|
+
/**
|
|
8688
|
+
* LISTED, NOT PLANNED. A goal's later phases get their tasks written down
|
|
8689
|
+
* when the plan is agreed, so the owner can read the whole shape — but those
|
|
8690
|
+
* rows have no subtasks and the runner must never pick them up. `todo` keeps
|
|
8691
|
+
* its meaning: the team may start this now.
|
|
8692
|
+
*/
|
|
8693
|
+
"backlog",
|
|
8643
8694
|
"todo",
|
|
8644
8695
|
"working",
|
|
8645
8696
|
"checking",
|
|
@@ -8647,6 +8698,8 @@ var STATUSES2 = [
|
|
|
8647
8698
|
"accepted",
|
|
8648
8699
|
"archived"
|
|
8649
8700
|
];
|
|
8701
|
+
var PRIORITIES2 = ["urgent", "high", "normal", "low"];
|
|
8702
|
+
var SIZES = ["small", "standard"];
|
|
8650
8703
|
var ROLES = [
|
|
8651
8704
|
"pm",
|
|
8652
8705
|
"architect",
|
|
@@ -8726,10 +8779,21 @@ function registerTask(program3) {
|
|
|
8726
8779
|
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(
|
|
8727
8780
|
"--phase <name>",
|
|
8728
8781
|
"which slice of that goal \u2014 must match one of its phase names"
|
|
8782
|
+
).option("--priority <value>", `how urgent (${PRIORITIES2.join(" | ")})`).option(
|
|
8783
|
+
"--size <value>",
|
|
8784
|
+
`small lets the channel start it without asking; standard asks (${SIZES.join(" | ")})`
|
|
8785
|
+
).option(
|
|
8786
|
+
"--status <value>",
|
|
8787
|
+
`start it somewhere other than 'todo' \u2014 use 'backlog' for a later phase's work (${STATUSES2.join(" | ")})`
|
|
8729
8788
|
).action(
|
|
8730
8789
|
action(async ({ ctx, args, opts }) => {
|
|
8731
8790
|
requireProject(ctx);
|
|
8732
8791
|
if (opts.kind !== void 0) assertOneOf("--kind", opts.kind, KINDS2);
|
|
8792
|
+
if (opts.priority !== void 0)
|
|
8793
|
+
assertOneOf("--priority", opts.priority, PRIORITIES2);
|
|
8794
|
+
if (opts.size !== void 0) assertOneOf("--size", opts.size, SIZES);
|
|
8795
|
+
if (opts.status !== void 0)
|
|
8796
|
+
assertOneOf("--status", opts.status, STATUSES2);
|
|
8733
8797
|
const hasChannelOrigin = Boolean(
|
|
8734
8798
|
ctx.projectChannelId && ctx.projectChannelMessageId
|
|
8735
8799
|
);
|
|
@@ -8743,6 +8807,11 @@ function registerTask(program3) {
|
|
|
8743
8807
|
// a goal has to be argued for, never assumed.
|
|
8744
8808
|
goalId: opts.goal,
|
|
8745
8809
|
phase: opts.phase,
|
|
8810
|
+
priority: opts.priority,
|
|
8811
|
+
size: opts.size,
|
|
8812
|
+
// `backlog` for a later phase's work: written down so the owner can
|
|
8813
|
+
// read the whole plan, with nothing for the runner to pick up.
|
|
8814
|
+
status: opts.status,
|
|
8746
8815
|
targets: [
|
|
8747
8816
|
...(opts.app ?? []).map((appId) => ({
|
|
8748
8817
|
kind: "app",
|
|
@@ -8817,6 +8886,9 @@ function registerTask(program3) {
|
|
|
8817
8886
|
"--infra <ref...>",
|
|
8818
8887
|
"shared setup it touches (database | storage | auth | hosting | jobs)"
|
|
8819
8888
|
).option("--scope <path...>", "files or folders THIS subtask owns").option(
|
|
8889
|
+
"--ref <spec...>",
|
|
8890
|
+
'what this step should READ first \u2014 a path or URL, optionally "::why it matters" (repeatable)'
|
|
8891
|
+
).option(
|
|
8820
8892
|
"--depends-on <id...>",
|
|
8821
8893
|
"subtasks that must finish first (key or id)"
|
|
8822
8894
|
).option(
|
|
@@ -8840,6 +8912,10 @@ function registerTask(program3) {
|
|
|
8840
8912
|
role: opts.role,
|
|
8841
8913
|
category: opts.kind,
|
|
8842
8914
|
scopePaths: opts.scope,
|
|
8915
|
+
// What to read before doing it. Parsed here rather than pushed at
|
|
8916
|
+
// the API so a malformed pointer is dropped where the agent can
|
|
8917
|
+
// still be told, not stored and drawn as an empty chip.
|
|
8918
|
+
attachments: parseRefs(opts.ref),
|
|
8843
8919
|
dependsOn,
|
|
8844
8920
|
targets: [
|
|
8845
8921
|
...(opts.app ?? []).map((appId) => ({
|
|
@@ -8898,6 +8974,9 @@ function registerTask(program3) {
|
|
|
8898
8974
|
})
|
|
8899
8975
|
);
|
|
8900
8976
|
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(
|
|
8977
|
+
"--ref <spec...>",
|
|
8978
|
+
"replaces what this step should READ first \u2014 same form as `subtask add --ref`"
|
|
8979
|
+
).option(
|
|
8901
8980
|
"--agent <id>",
|
|
8902
8981
|
`run this step on a specific CLI (${AGENTS.join(" | ")}); "default" hands it back to the role's own`
|
|
8903
8982
|
).option("--model <id>", 'the model that CLI should use; "default" clears it').option(
|
|
@@ -8925,6 +9004,10 @@ function registerTask(program3) {
|
|
|
8925
9004
|
role: opts.role,
|
|
8926
9005
|
category: opts.kind,
|
|
8927
9006
|
scopePaths: opts.scope,
|
|
9007
|
+
// Only sent when `--ref` was actually given: the PATCH replaces
|
|
9008
|
+
// the whole list, so passing `[]` for an untouched flag would
|
|
9009
|
+
// clear a brief the manager set on a previous call.
|
|
9010
|
+
attachments: opts.ref ? parseRefs(opts.ref) : void 0,
|
|
8928
9011
|
agentOverride: clearable(opts.agent),
|
|
8929
9012
|
agentModelOverride: clearable(opts.model),
|
|
8930
9013
|
agentEffortOverride: clearable(opts.effort)
|
|
@@ -9365,6 +9448,47 @@ function registerGoal(program3) {
|
|
|
9365
9448
|
);
|
|
9366
9449
|
})
|
|
9367
9450
|
);
|
|
9451
|
+
goal.command("adopt <id>").description(
|
|
9452
|
+
"File tasks that already exist under a part of this plan \u2014 for work done before the plan was written"
|
|
9453
|
+
).option("--task <id...>", "the tasks to file under it").option("--phase <name>", "which part of the plan they belong to").action(
|
|
9454
|
+
action(async ({ ctx, args, opts }) => {
|
|
9455
|
+
requireProject(ctx);
|
|
9456
|
+
const goalId = String(args[0]);
|
|
9457
|
+
const taskIds = opts.task ?? [];
|
|
9458
|
+
if (!taskIds.length) {
|
|
9459
|
+
throw new WorkserError(
|
|
9460
|
+
"Name the tasks to file, e.g. `--task WORK-12 WORK-13`."
|
|
9461
|
+
);
|
|
9462
|
+
}
|
|
9463
|
+
const goal2 = await api(
|
|
9464
|
+
ctx,
|
|
9465
|
+
`/v1/project-goals/${encodeURIComponent(goalId)}`
|
|
9466
|
+
);
|
|
9467
|
+
if (!goal2) throw new WorkserError(`No goal ${goalId}.`);
|
|
9468
|
+
const names = (goal2.phases ?? []).map(
|
|
9469
|
+
(p) => typeof p === "string" ? p : p.name
|
|
9470
|
+
);
|
|
9471
|
+
const phase = String(opts.phase ?? "").trim();
|
|
9472
|
+
if (!phase || !names.includes(phase)) {
|
|
9473
|
+
throw new WorkserError(
|
|
9474
|
+
`--phase must be one of this goal's parts: ${names.join(", ")}.`
|
|
9475
|
+
);
|
|
9476
|
+
}
|
|
9477
|
+
const filed = [];
|
|
9478
|
+
for (const taskId of taskIds) {
|
|
9479
|
+
await api(ctx, `/v1/project-tasks/${encodeURIComponent(taskId)}`, {
|
|
9480
|
+
method: "PATCH",
|
|
9481
|
+
body: { goalId, phase }
|
|
9482
|
+
});
|
|
9483
|
+
filed.push(taskId);
|
|
9484
|
+
}
|
|
9485
|
+
ok({ goalId, phase, filed }, () => {
|
|
9486
|
+
success(
|
|
9487
|
+
`Filed ${filed.length} ${filed.length === 1 ? "task" : "tasks"} under ${import_picocolors30.default.bold(phase)}`
|
|
9488
|
+
);
|
|
9489
|
+
});
|
|
9490
|
+
})
|
|
9491
|
+
);
|
|
9368
9492
|
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(
|
|
9369
9493
|
action(async ({ ctx, args, opts }) => {
|
|
9370
9494
|
if (opts.status && !STATUSES3.includes(opts.status)) {
|
|
@@ -11066,7 +11190,7 @@ function colour(d) {
|
|
|
11066
11190
|
|
|
11067
11191
|
// src/index.ts
|
|
11068
11192
|
var pkg = {
|
|
11069
|
-
version: true ? "0.6.
|
|
11193
|
+
version: true ? "0.6.12" : "0.0.0-dev"
|
|
11070
11194
|
};
|
|
11071
11195
|
var program2 = new Command();
|
|
11072
11196
|
program2.name("workser").description(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workser/cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.12",
|
|
4
4
|
"description": "Workser CLI — give your local AI agent native DevOps & infrastructure on Workser. The agent runs `workser …` to provision, deploy, and manage real apps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|