@workser/cli 0.6.7 → 0.6.8

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 CHANGED
@@ -100,6 +100,15 @@ workser audio understand "<query>" [--url <u>|--file <p>] [-t <task>] # transcr
100
100
 
101
101
  workser ask "<question>" [--type <t>] [--option <o>] # ask the user, WAIT for the answer
102
102
 
103
+ # Tasks and subtasks (the plan shown in Orbit)
104
+ workser task show [id] # inspect the task and its current plan
105
+ workser task subtask list [taskId] # list the task's subtasks
106
+ workser task subtask add "<title>" --role <role> # add one proposed subtask
107
+ workser task subtask update <id> --role <role> # fix its teammate after creation
108
+ workser task subtask update <id> --title "…" --note "…" --scope <paths...>
109
+ workser task subtask remove <id> # remove it before work starts
110
+ workser task start [id] # starts only an already-approved plan
111
+
103
112
  # owner-only (will return owner_only / exit 6 — ask the user to do these in Orbit):
104
113
  # project create, project use, env rm, domain set
105
114
  ```
@@ -119,12 +128,12 @@ workser doc create "<title>" --markdown <text> | doc update <id> --markdown <tex
119
128
  already doing and what this project chose on purpose, so you don't re-file work or
120
129
  quietly reverse a decision.
121
130
 
122
- **A plan with phases goes on the Board before you build it.** The moment you split a
123
- task into more than one phase: one `board create` card per phase (only the one you're
124
- doing goes to `in-progress`), the plan itself as one `doc create --markdown` with
125
- **no `--work-item`**, because a linked doc is shown on its card and hidden from the
126
- Docs panel — and a `decision create` if the plan settled a real tradeoff. A plan that
127
- lives only in your reply is gone as soon as the conversation scrolls.
131
+ **A plan with phases goes on this task's Subtasks list, not the Board.** Use one
132
+ `task subtask add` per phase. If you spot a bad title, role, note, or file scope after
133
+ creation, correct that existing row with `task subtask update <id>`; do not say it is
134
+ locked, create a replacement, or duplicate the plan. Write the plan narrative once
135
+ as `doc create --markdown` with no `--work-item`, and record a real tradeoff with
136
+ `decision create`.
128
137
 
129
138
  **Keep it true as you work.** `board move <id> in-progress` when you pick it up,
130
139
  `in-review` when it's ready to look at, `board close <id>` when it's done and
package/dist/index.js CHANGED
@@ -8494,15 +8494,33 @@ function collect2(value, previous) {
8494
8494
 
8495
8495
  // src/commands/task.ts
8496
8496
  var import_picocolors28 = __toESM(require_picocolors(), 1);
8497
- var STATUSES2 = ["todo", "working", "checking", "ready", "accepted", "archived"];
8497
+ var STATUSES2 = [
8498
+ "todo",
8499
+ "working",
8500
+ "checking",
8501
+ "ready",
8502
+ "accepted",
8503
+ "archived"
8504
+ ];
8498
8505
  var ROLES = ["pm", "architect", "web", "api", "automation", "qa"];
8499
- var KINDS2 = ["data_reports", "web", "mobile", "service", "automation", "docs"];
8506
+ var KINDS2 = [
8507
+ "data_reports",
8508
+ "web",
8509
+ "mobile",
8510
+ "service",
8511
+ "automation",
8512
+ "docs"
8513
+ ];
8500
8514
  function registerTask(program3) {
8501
8515
  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("--status <value>", `only tasks in this status (${STATUSES2.join(" | ")})`).option("--label <value>", "only tasks carrying this label").option("--limit <n>", "cap the number of tasks returned").action(
8516
+ task.command("list").description("List the board's tasks \u2014 run this before starting anything").option(
8517
+ "--status <value>",
8518
+ `only tasks in this status (${STATUSES2.join(" | ")})`
8519
+ ).option("--label <value>", "only tasks carrying this label").option("--limit <n>", "cap the number of tasks returned").action(
8503
8520
  action(async ({ ctx, opts }) => {
8504
8521
  requireProject(ctx);
8505
- if (opts.status !== void 0) assertOneOf("--status", opts.status, STATUSES2);
8522
+ if (opts.status !== void 0)
8523
+ assertOneOf("--status", opts.status, STATUSES2);
8506
8524
  const rows = await api(ctx, "/v1/project-tasks", {
8507
8525
  query: {
8508
8526
  status: opts.status,
@@ -8524,7 +8542,10 @@ function registerTask(program3) {
8524
8542
  ).action(
8525
8543
  action(async ({ ctx, args }) => {
8526
8544
  const id = args[0] || ctx.parentTaskId || resolveTaskId(ctx);
8527
- const row = await api(ctx, `/v1/project-tasks/${encodeURIComponent(id)}`);
8545
+ const row = await api(
8546
+ ctx,
8547
+ `/v1/project-tasks/${encodeURIComponent(id)}`
8548
+ );
8528
8549
  const goalId = row.goal_id;
8529
8550
  const goal = goalId ? await api(
8530
8551
  ctx,
@@ -8554,8 +8575,14 @@ function registerTask(program3) {
8554
8575
  goalId: opts.goal,
8555
8576
  phase: opts.phase,
8556
8577
  targets: [
8557
- ...(opts.app ?? []).map((appId) => ({ kind: "app", appId })),
8558
- ...(opts.infra ?? []).map((ref) => ({ kind: "infra", ref }))
8578
+ ...(opts.app ?? []).map((appId) => ({
8579
+ kind: "app",
8580
+ appId
8581
+ })),
8582
+ ...(opts.infra ?? []).map((ref) => ({
8583
+ kind: "infra",
8584
+ ref
8585
+ }))
8559
8586
  ],
8560
8587
  ...hasChannelOrigin ? {
8561
8588
  channelId: ctx.projectChannelId,
@@ -8595,8 +8622,11 @@ function registerTask(program3) {
8595
8622
  ...channelMessageError ? { channelMessageError } : {}
8596
8623
  };
8597
8624
  ok(result, () => {
8598
- line(`${import_picocolors28.default.green("opened")} ${import_picocolors28.default.bold(row.title)} ${import_picocolors28.default.dim(row.key ?? row.id)}`);
8599
- if (channelMessage) line(import_picocolors28.default.dim("posted to the channel as Project Manager"));
8625
+ line(
8626
+ `${import_picocolors28.default.green("opened")} ${import_picocolors28.default.bold(row.title)} ${import_picocolors28.default.dim(row.key ?? row.id)}`
8627
+ );
8628
+ if (channelMessage)
8629
+ line(import_picocolors28.default.dim("posted to the channel as Project Manager"));
8600
8630
  if (channelMessageError) {
8601
8631
  warn(
8602
8632
  `Task opened, but its Project Manager card could not be posted: ${channelMessageError.message}`
@@ -8608,10 +8638,19 @@ function registerTask(program3) {
8608
8638
  const subtask = task.command("subtask").description("The subtasks a task is broken into");
8609
8639
  subtask.command("add <title>").description(
8610
8640
  'Add one subtask, e.g. `workser task subtask add "Build the upload screen" --role web`'
8611
- ).option("--task <id>", "the parent task (defaults to the task this run is inside)").option("--role <value>", `who does it (${ROLES.join(" | ")})`).option("--kind <value>", `what it produces (${KINDS2.join(" | ")})`).option("--note <text>", "one sentence on what this subtask does").option(
8641
+ ).option(
8642
+ "--task <id>",
8643
+ "the parent task (defaults to the task this run is inside)"
8644
+ ).option("--role <value>", `who does it (${ROLES.join(" | ")})`).option("--kind <value>", `what it produces (${KINDS2.join(" | ")})`).option("--note <text>", "one sentence on what this subtask does").option(
8612
8645
  "--app <id...>",
8613
8646
  "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("--infra <ref...>", "shared setup it touches (database | storage | auth | hosting | jobs)").option("--scope <path...>", "files or folders THIS subtask owns").option("--depends-on <id...>", "subtasks that must finish first (key or id)").action(
8647
+ ).option(
8648
+ "--infra <ref...>",
8649
+ "shared setup it touches (database | storage | auth | hosting | jobs)"
8650
+ ).option("--scope <path...>", "files or folders THIS subtask owns").option(
8651
+ "--depends-on <id...>",
8652
+ "subtasks that must finish first (key or id)"
8653
+ ).action(
8615
8654
  action(async ({ ctx, args, opts }) => {
8616
8655
  const parent = resolveTaskId(ctx, opts.task);
8617
8656
  if (opts.role !== void 0) assertOneOf("--role", opts.role, ROLES);
@@ -8627,13 +8666,21 @@ function registerTask(program3) {
8627
8666
  scopePaths: opts.scope,
8628
8667
  dependsOn,
8629
8668
  targets: [
8630
- ...(opts.app ?? []).map((appId) => ({ kind: "app", appId })),
8631
- ...(opts.infra ?? []).map((ref) => ({ kind: "infra", ref }))
8669
+ ...(opts.app ?? []).map((appId) => ({
8670
+ kind: "app",
8671
+ appId
8672
+ })),
8673
+ ...(opts.infra ?? []).map((ref) => ({
8674
+ kind: "infra",
8675
+ ref
8676
+ }))
8632
8677
  ]
8633
8678
  }
8634
8679
  });
8635
8680
  ok(row, () => {
8636
- line(`${import_picocolors28.default.green("added")} ${import_picocolors28.default.bold(row.title)} ${import_picocolors28.default.dim(row.key ?? row.id)}`);
8681
+ line(
8682
+ `${import_picocolors28.default.green("added")} ${import_picocolors28.default.bold(row.title)} ${import_picocolors28.default.dim(row.key ?? row.id)}`
8683
+ );
8637
8684
  if (row.role) line(import_picocolors28.default.dim(`role: ${row.role}`));
8638
8685
  });
8639
8686
  })
@@ -8641,7 +8688,10 @@ function registerTask(program3) {
8641
8688
  subtask.command("list [taskId]").description("The subtasks of a task, in order").action(
8642
8689
  action(async ({ ctx, args }) => {
8643
8690
  const id = resolveTaskId(ctx, args[0]);
8644
- const row = await api(ctx, `/v1/project-tasks/${encodeURIComponent(id)}`);
8691
+ const row = await api(
8692
+ ctx,
8693
+ `/v1/project-tasks/${encodeURIComponent(id)}`
8694
+ );
8645
8695
  const rows = row.subtasks ?? [];
8646
8696
  ok(rows, () => {
8647
8697
  if (!rows.length) {
@@ -8681,7 +8731,9 @@ function registerTask(program3) {
8681
8731
  ok({ removed: args[0] }, () => line(import_picocolors28.default.green("removed")));
8682
8732
  })
8683
8733
  );
8684
- task.command("move <id> <status>").description(`Move a task or step along the board (${STATUSES2.join(" | ")})`).action(
8734
+ task.command("move <id> <status>").description(
8735
+ `Move a task or step along the board (${STATUSES2.join(" | ")})`
8736
+ ).action(
8685
8737
  action(async ({ ctx, args }) => {
8686
8738
  assertOneOf("<status>", args[1], STATUSES2);
8687
8739
  const row = await api(
@@ -8689,7 +8741,10 @@ function registerTask(program3) {
8689
8741
  `/v1/project-tasks/${encodeURIComponent(args[0])}/move`,
8690
8742
  { body: { status: args[1] } }
8691
8743
  );
8692
- ok(row, () => line(`${import_picocolors28.default.green("moved")} ${import_picocolors28.default.bold(row.title)} \u2192 ${args[1]}`));
8744
+ ok(
8745
+ row,
8746
+ () => line(`${import_picocolors28.default.green("moved")} ${import_picocolors28.default.bold(row.title)} \u2192 ${args[1]}`)
8747
+ );
8693
8748
  })
8694
8749
  );
8695
8750
  task.command("resume [id]").description(
@@ -8740,7 +8795,9 @@ function registerTask(program3) {
8740
8795
  });
8741
8796
  })
8742
8797
  );
8743
- task.command("can-start [id]").description("Ask whether work on this task may begin. Refuses until the owner approves.").action(
8798
+ task.command("can-start [id]").description(
8799
+ "Ask whether work on this task may begin. Refuses until the owner approves."
8800
+ ).action(
8744
8801
  action(async ({ ctx, args }) => {
8745
8802
  const id = resolveTaskId(ctx, args[0]);
8746
8803
  const row = await api(
@@ -8756,11 +8813,9 @@ function registerTask(program3) {
8756
8813
  ).action(
8757
8814
  action(async ({ ctx, args }) => {
8758
8815
  const id = resolveTaskId(ctx, args[0]);
8759
- const row = await api(
8760
- ctx,
8761
- `/v1/project-tasks/${encodeURIComponent(id)}/start`,
8762
- { method: "POST" }
8763
- );
8816
+ const row = await api(ctx, `/v1/project-tasks/${encodeURIComponent(id)}/start`, {
8817
+ method: "POST"
8818
+ });
8764
8819
  ok(row, () => {
8765
8820
  const started = row?.started ?? null;
8766
8821
  if (started && started > 0) {
@@ -8786,7 +8841,9 @@ function registerTask(program3) {
8786
8841
  );
8787
8842
  ok({ awaiting: row2.approval_state === "awaiting", task: row2 }, () => {
8788
8843
  line(
8789
- row2.approval_state === "awaiting" ? import_picocolors28.default.yellow("The plan is waiting on the owner. They see it in the task.") : `Already ${row2.approval_state}.`
8844
+ row2.approval_state === "awaiting" ? import_picocolors28.default.yellow(
8845
+ "The plan is waiting on the owner. They see it in the task."
8846
+ ) : `Already ${row2.approval_state}.`
8790
8847
  );
8791
8848
  });
8792
8849
  return;
@@ -8807,7 +8864,10 @@ function registerTask(program3) {
8807
8864
  }
8808
8865
  }
8809
8866
  );
8810
- ok(row, () => line(`${import_picocolors28.default.green(row.approval_state)} ${import_picocolors28.default.bold(row.title)}`));
8867
+ ok(
8868
+ row,
8869
+ () => line(`${import_picocolors28.default.green(row.approval_state)} ${import_picocolors28.default.bold(row.title)}`)
8870
+ );
8811
8871
  })
8812
8872
  );
8813
8873
  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(
@@ -8936,7 +8996,11 @@ Nothing is running. The next part waiting is "${next.name}" \u2014 offer it to t
8936
8996
  )
8937
8997
  );
8938
8998
  } else if (!next) {
8939
- line(import_picocolors28.default.dim("\nEvery part of this plan is done. Say so, and offer to wrap it up."));
8999
+ line(
9000
+ import_picocolors28.default.dim(
9001
+ "\nEvery part of this plan is done. Say so, and offer to wrap it up."
9002
+ )
9003
+ );
8940
9004
  }
8941
9005
  line(
8942
9006
  import_picocolors28.default.dim(
@@ -10791,7 +10855,7 @@ function colour(d) {
10791
10855
 
10792
10856
  // src/index.ts
10793
10857
  var pkg = {
10794
- version: true ? "0.6.7" : "0.0.0-dev"
10858
+ version: true ? "0.6.8" : "0.0.0-dev"
10795
10859
  };
10796
10860
  var program2 = new Command();
10797
10861
  program2.name("workser").description(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workser/cli",
3
- "version": "0.6.7",
3
+ "version": "0.6.8",
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",
@@ -77,6 +77,9 @@ pick or switch it.
77
77
  3. **A phased plan goes on the subtask list, never the Board.** Phases are
78
78
  `workser task subtask add` (`workser help tasks`) — not `board create`,
79
79
  which makes a second, driftable "the plan" the task page never reads.
80
+ If a subtask's title, teammate, note, or scope is wrong after creation, fix
81
+ that same row with `workser task subtask update <id> --title … --role …
82
+ --note … --scope …`; never claim it is locked or create a duplicate.
80
83
  Write the narrative once as `doc create` (no `--work-item`, or it's hidden
81
84
  from the Docs panel), plus `decision create` for a real tradeoff. A plan
82
85
  in your reply alone is gone when the conversation scrolls. Details: