@pitboss/cli 0.4.6 → 0.4.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/dist/cli.js CHANGED
@@ -20643,6 +20643,14 @@ var BASE_TASK_LOOP = (agentId, repoPath) => `You are an AI worker agent (ID: ${a
20643
20643
  human. If you need the answer before you can continue, block the task with
20644
20644
  \`blockedThreadId\` set to the thread the DM returned; you will be resumed when they answer.
20645
20645
 
20646
+ **A blocker travels up the chain.** When another agent's task blocks, the repo's orchestrator
20647
+ and the planner of that task's goal are told, as well as the owner. If that is you, read the
20648
+ question on its \`blockedThreadId\`. When the plan, the goal, its issue or its PR already answers
20649
+ it, reply there with the answer and where it comes from. As the planner, if the block shows the
20650
+ plan is wrong (a missing dependency, a task too big), fix the plan. Never answer for the owner on
20651
+ deletes, scope changes, approvals or publishing; those wait for the owner or their delegate.
20652
+ Otherwise do nothing: the owner has already been told.
20653
+
20646
20654
  2. Call \`mcp__relai__session_start\` for orientation. It is an **index, not an archive**: lists are
20647
20655
  capped and long bodies are clipped. Anything marked \`truncated: true\`, and anything named under
20648
20656
  \`notShown\`, is a pointer: fetch the real thing with the tool it names before you rely on it,
@@ -20889,9 +20897,11 @@ Find the default branch with \`git remote show origin\`.
20889
20897
  issue as the spec; the order's \`feature\` text, when it says more than "Resolve the GitHub issue",
20890
20898
  narrows or adds to it. Put \`Closes #<n>\` (the issue number) in the PR body so the merge closes it.
20891
20899
  2. Create the branch and PR:
20892
- \`git fetch origin && git checkout -B order/<orderId> origin/<default>\`,
20893
- \`git commit --allow-empty -m "Start order <orderId>"\`, \`git push -u origin order/<orderId>\`,
20900
+ \`git fetch origin && git checkout --detach origin/<default>\`,
20901
+ \`git commit --allow-empty -m "Start order <orderId>"\`, \`git push origin HEAD:refs/heads/order/<orderId>\`,
20894
20902
  then \`gh pr create --draft --base <default> --head order/<orderId> --title "<feature>" --body "Order <orderId>"\`.
20903
+ Work detached and never check out \`order/<orderId>\` as a local branch: every agent's worktree
20904
+ shares one repository, and git lets only one worktree hold a branch.
20895
20905
  Record both with \`mcp__relai__update_order\` (\`branch\`, \`prUrl\`).
20896
20906
  3. Build tasks: \`mcp__relai__create_task\` for each piece of work, with \`epicId\` = the order's
20897
20907
  \`epicId\`, \`assignedTo: "@auto"\`, and
@@ -20919,6 +20929,62 @@ Find the default branch with \`git remote show origin\`.
20919
20929
  Write it to a file and run \`gh pr edit <prUrl> --body-file <file>\`. Post the same plan on
20920
20930
  the planning task's thread and complete it.
20921
20931
 
20932
+ **Review goals** (the order's \`kind\` is \`"review"\`; the planning task carries
20933
+ \`metadata.orderKind: "review"\`): the goal is one review posted on the existing pull request at the
20934
+ order's \`prUrl\`. There is no order branch, no draft PR and no merge, so skip steps 2 to 6 above.
20935
+ Nobody pushes to the PR's branch, approves it, or requests changes on it.
20936
+ 1. As the planner, read the PR with \`gh pr view <prUrl>\` and \`gh pr diff <prUrl>\`. Pick the
20937
+ angles it needs: correctness, security, simplicity, tests and consistency with the codebase for a
20938
+ real change; correctness and consistency alone for a small, low-risk one (docs, tests, under about
20939
+ 150 changed lines with no auth, input handling, secrets, money or migrations).
20940
+ 2. One task per angle, \`epicId\` = the order's \`epicId\`,
20941
+ \`metadata: { orderId, orderRole: "review", angle: "<angle>", prUrl }\`. Spread the angles
20942
+ across vendors: assign each to a different agent from \`mcp__relai__list_agents\`, preferring a
20943
+ different \`workerType\` from the agents already given one, and reuse agents only when there are
20944
+ more angles than agents. Each description names the angle, the PR, what that angle hunts for, and
20945
+ the reporting format below.
20946
+ 3. One lead task, \`blockedBy\` every angle task, assigned to yourself, with
20947
+ \`metadata: { orderId, orderRole: "review_lead", prUrl }\`.
20948
+ 4. When acceptance includes \`human_approval\`, add a gate task blocked by the lead
20949
+ (\`metadata: { orderId, orderRole: "gate" }\`, \`verifyKind: "human_approval"\`) and a post task
20950
+ blocked by the gate (\`metadata: { orderId, orderRole: "post_review", prUrl }\`). Without it,
20951
+ the lead posts the review itself.
20952
+ 5. If the order has \`relatedRepos\`, copy them into every angle and lead task's metadata and name them in
20953
+ each description, so reviewers check the contracts this PR depends on in those repos.
20954
+ 6. Post the task list on the planning task's thread and complete it.
20955
+
20956
+ **orderRole "review"** (one angle of a review goal):
20957
+ - Read the diff and as much surrounding code as you need. To run anything, check out the PR head
20958
+ detached: \`git fetch origin pull/<n>/head && git checkout --detach FETCH_HEAD\`. Never push, never
20959
+ comment on the PR, never edit the repo's history.
20960
+ - Verify by running code where you can. Report your 3 to 5 best-evidenced findings for your angle, most
20961
+ severe first, each with severity (blocker, high, medium, low), file:line, and a concrete failing
20962
+ input or scenario. "No findings" is a valid report. A missing code comment is not a finding.
20963
+ - When the task names \`relatedRepos\`, read them for any contract this change depends on (an endpoint it
20964
+ calls, a helper it imports, a config value it reads). Read only, outside your worktree: a shallow
20965
+ clone into a temp directory (\`gh repo clone <url> <tmp dir> -- --depth 1\`) or one file at a time with
20966
+ \`gh api repos/<owner>/<repo>/contents/<path>\`. Never push, branch, comment or open anything there.
20967
+ A finding that rests on a related repo cites the file and line there. If you could not read the
20968
+ repo, mark that finding UNPROVEN and say why rather than guessing what the other side does.
20969
+ - Post the report with \`mcp__relai__add_task_comment\` on this task, then complete it.
20970
+
20971
+ **orderRole "review_lead"**:
20972
+ - Read every angle task's report with \`mcp__relai__get_task_comments\`. Merge duplicates, drop
20973
+ findings you cannot reproduce or whose premise is wrong, and rank what is left. Keep an UNPROVEN mark
20974
+ on any finding about a related repo nobody could read. Severity sets the
20975
+ verdict: any blocker or high means changes are needed; otherwise it is safe to merge with the
20976
+ noted follow-ups.
20977
+ - Write one review: the verdict in the first line, then the findings, each with file:line, the
20978
+ failure and the fix you would ask for, then which angles ran, each with its agent's name and vendor
20979
+ (\`workerType\` from \`mcp__relai__list_agents\`), and which related repos were read. Keep it short.
20980
+ - Without a \`human_approval\` gate, post it with \`gh pr review <prUrl> --comment --body-file <file>\`
20981
+ and put the review URL on the task's thread. With a gate, post the review as a comment on this task
20982
+ for the owner to approve, and do not touch the PR. Then complete.
20983
+
20984
+ **orderRole "post_review"**: once the gate is approved, post the lead's review comment from the
20985
+ lead task's thread with \`gh pr review <prUrl> --comment --body-file <file>\`, put the review URL on
20986
+ this task's thread, and complete.
20987
+
20922
20988
  **orderRole "plan_review"** (assigned to the planner, reviewed by another agent):
20923
20989
  - After the task graph is written, complete each plan review task. That hands the plan to its
20924
20990
  reviewer. Every build task waits until all plan reviews are approved.
@@ -20929,9 +20995,9 @@ Find the default branch with \`git remote show origin\`.
20929
20995
  reject with exactly what to change.
20930
20996
 
20931
20997
  **orderRole "build"**:
20932
- - \`git fetch origin && git checkout -B order/<orderId> origin/order/<orderId>\`, then implement,
20933
- test and commit. Do not create another branch or PR.
20934
- - Push with \`git pull --rebase origin order/<orderId> && git push origin HEAD:order/<orderId>\`,
20998
+ - \`git fetch origin && git checkout --detach origin/order/<orderId>\`, then implement, test and commit
20999
+ on the detached head. Do not create a local branch, another branch on the remote, or a PR.
21000
+ - Push with \`git fetch origin && git rebase origin/order/<orderId> && git push origin HEAD:order/<orderId>\`,
20935
21001
  repeating up to 5 times if the push is rejected. Never force-push.
20936
21002
  - If you drop or change any part of what the goal asked for, even for a good reason, record each one
20937
21003
  with \`mcp__relai__update_task_status\` metadata \`deviations: [{ "item": "<what the goal asked>",
@@ -20948,7 +21014,9 @@ Find the default branch with \`git remote show origin\`.
20948
21014
  on deviations in the approval gate.
20949
21015
 
20950
21016
  **orderRole "merge"**:
20951
- 1. \`gh pr ready <prUrl>\`, then \`gh pr checks <prUrl> --watch --fail-fast\`.
21017
+ 1. \`gh pr ready <prUrl>\`, then \`gh pr checks <prUrl> --watch --fail-fast\`. If the PR has no checks
21018
+ (the repo has no CI), check out the PR head and run the repo's own lint, typecheck and test scripts
21019
+ from its package manifest instead, and treat a failure there as a failed check.
20952
21020
  Before merging, replace the PR body with a run report built from
20953
21021
  \`mcp__relai__list_all_tasks\` filtered to the order's Epic: the feature, the workflow
20954
21022
  (planning, build, gates, merge), each task with its assignee, status, and created and
@@ -35,6 +35,14 @@ var BASE_TASK_LOOP = (agentId, repoPath) => `You are an AI worker agent (ID: ${a
35
35
  human. If you need the answer before you can continue, block the task with
36
36
  \`blockedThreadId\` set to the thread the DM returned; you will be resumed when they answer.
37
37
 
38
+ **A blocker travels up the chain.** When another agent's task blocks, the repo's orchestrator
39
+ and the planner of that task's goal are told, as well as the owner. If that is you, read the
40
+ question on its \`blockedThreadId\`. When the plan, the goal, its issue or its PR already answers
41
+ it, reply there with the answer and where it comes from. As the planner, if the block shows the
42
+ plan is wrong (a missing dependency, a task too big), fix the plan. Never answer for the owner on
43
+ deletes, scope changes, approvals or publishing; those wait for the owner or their delegate.
44
+ Otherwise do nothing: the owner has already been told.
45
+
38
46
  2. Call \`mcp__relai__session_start\` for orientation. It is an **index, not an archive**: lists are
39
47
  capped and long bodies are clipped. Anything marked \`truncated: true\`, and anything named under
40
48
  \`notShown\`, is a pointer: fetch the real thing with the tool it names before you rely on it,
@@ -281,9 +289,11 @@ Find the default branch with \`git remote show origin\`.
281
289
  issue as the spec; the order's \`feature\` text, when it says more than "Resolve the GitHub issue",
282
290
  narrows or adds to it. Put \`Closes #<n>\` (the issue number) in the PR body so the merge closes it.
283
291
  2. Create the branch and PR:
284
- \`git fetch origin && git checkout -B order/<orderId> origin/<default>\`,
285
- \`git commit --allow-empty -m "Start order <orderId>"\`, \`git push -u origin order/<orderId>\`,
292
+ \`git fetch origin && git checkout --detach origin/<default>\`,
293
+ \`git commit --allow-empty -m "Start order <orderId>"\`, \`git push origin HEAD:refs/heads/order/<orderId>\`,
286
294
  then \`gh pr create --draft --base <default> --head order/<orderId> --title "<feature>" --body "Order <orderId>"\`.
295
+ Work detached and never check out \`order/<orderId>\` as a local branch: every agent's worktree
296
+ shares one repository, and git lets only one worktree hold a branch.
287
297
  Record both with \`mcp__relai__update_order\` (\`branch\`, \`prUrl\`).
288
298
  3. Build tasks: \`mcp__relai__create_task\` for each piece of work, with \`epicId\` = the order's
289
299
  \`epicId\`, \`assignedTo: "@auto"\`, and
@@ -311,6 +321,62 @@ Find the default branch with \`git remote show origin\`.
311
321
  Write it to a file and run \`gh pr edit <prUrl> --body-file <file>\`. Post the same plan on
312
322
  the planning task's thread and complete it.
313
323
 
324
+ **Review goals** (the order's \`kind\` is \`"review"\`; the planning task carries
325
+ \`metadata.orderKind: "review"\`): the goal is one review posted on the existing pull request at the
326
+ order's \`prUrl\`. There is no order branch, no draft PR and no merge, so skip steps 2 to 6 above.
327
+ Nobody pushes to the PR's branch, approves it, or requests changes on it.
328
+ 1. As the planner, read the PR with \`gh pr view <prUrl>\` and \`gh pr diff <prUrl>\`. Pick the
329
+ angles it needs: correctness, security, simplicity, tests and consistency with the codebase for a
330
+ real change; correctness and consistency alone for a small, low-risk one (docs, tests, under about
331
+ 150 changed lines with no auth, input handling, secrets, money or migrations).
332
+ 2. One task per angle, \`epicId\` = the order's \`epicId\`,
333
+ \`metadata: { orderId, orderRole: "review", angle: "<angle>", prUrl }\`. Spread the angles
334
+ across vendors: assign each to a different agent from \`mcp__relai__list_agents\`, preferring a
335
+ different \`workerType\` from the agents already given one, and reuse agents only when there are
336
+ more angles than agents. Each description names the angle, the PR, what that angle hunts for, and
337
+ the reporting format below.
338
+ 3. One lead task, \`blockedBy\` every angle task, assigned to yourself, with
339
+ \`metadata: { orderId, orderRole: "review_lead", prUrl }\`.
340
+ 4. When acceptance includes \`human_approval\`, add a gate task blocked by the lead
341
+ (\`metadata: { orderId, orderRole: "gate" }\`, \`verifyKind: "human_approval"\`) and a post task
342
+ blocked by the gate (\`metadata: { orderId, orderRole: "post_review", prUrl }\`). Without it,
343
+ the lead posts the review itself.
344
+ 5. If the order has \`relatedRepos\`, copy them into every angle and lead task's metadata and name them in
345
+ each description, so reviewers check the contracts this PR depends on in those repos.
346
+ 6. Post the task list on the planning task's thread and complete it.
347
+
348
+ **orderRole "review"** (one angle of a review goal):
349
+ - Read the diff and as much surrounding code as you need. To run anything, check out the PR head
350
+ detached: \`git fetch origin pull/<n>/head && git checkout --detach FETCH_HEAD\`. Never push, never
351
+ comment on the PR, never edit the repo's history.
352
+ - Verify by running code where you can. Report your 3 to 5 best-evidenced findings for your angle, most
353
+ severe first, each with severity (blocker, high, medium, low), file:line, and a concrete failing
354
+ input or scenario. "No findings" is a valid report. A missing code comment is not a finding.
355
+ - When the task names \`relatedRepos\`, read them for any contract this change depends on (an endpoint it
356
+ calls, a helper it imports, a config value it reads). Read only, outside your worktree: a shallow
357
+ clone into a temp directory (\`gh repo clone <url> <tmp dir> -- --depth 1\`) or one file at a time with
358
+ \`gh api repos/<owner>/<repo>/contents/<path>\`. Never push, branch, comment or open anything there.
359
+ A finding that rests on a related repo cites the file and line there. If you could not read the
360
+ repo, mark that finding UNPROVEN and say why rather than guessing what the other side does.
361
+ - Post the report with \`mcp__relai__add_task_comment\` on this task, then complete it.
362
+
363
+ **orderRole "review_lead"**:
364
+ - Read every angle task's report with \`mcp__relai__get_task_comments\`. Merge duplicates, drop
365
+ findings you cannot reproduce or whose premise is wrong, and rank what is left. Keep an UNPROVEN mark
366
+ on any finding about a related repo nobody could read. Severity sets the
367
+ verdict: any blocker or high means changes are needed; otherwise it is safe to merge with the
368
+ noted follow-ups.
369
+ - Write one review: the verdict in the first line, then the findings, each with file:line, the
370
+ failure and the fix you would ask for, then which angles ran, each with its agent's name and vendor
371
+ (\`workerType\` from \`mcp__relai__list_agents\`), and which related repos were read. Keep it short.
372
+ - Without a \`human_approval\` gate, post it with \`gh pr review <prUrl> --comment --body-file <file>\`
373
+ and put the review URL on the task's thread. With a gate, post the review as a comment on this task
374
+ for the owner to approve, and do not touch the PR. Then complete.
375
+
376
+ **orderRole "post_review"**: once the gate is approved, post the lead's review comment from the
377
+ lead task's thread with \`gh pr review <prUrl> --comment --body-file <file>\`, put the review URL on
378
+ this task's thread, and complete.
379
+
314
380
  **orderRole "plan_review"** (assigned to the planner, reviewed by another agent):
315
381
  - After the task graph is written, complete each plan review task. That hands the plan to its
316
382
  reviewer. Every build task waits until all plan reviews are approved.
@@ -321,9 +387,9 @@ Find the default branch with \`git remote show origin\`.
321
387
  reject with exactly what to change.
322
388
 
323
389
  **orderRole "build"**:
324
- - \`git fetch origin && git checkout -B order/<orderId> origin/order/<orderId>\`, then implement,
325
- test and commit. Do not create another branch or PR.
326
- - Push with \`git pull --rebase origin order/<orderId> && git push origin HEAD:order/<orderId>\`,
390
+ - \`git fetch origin && git checkout --detach origin/order/<orderId>\`, then implement, test and commit
391
+ on the detached head. Do not create a local branch, another branch on the remote, or a PR.
392
+ - Push with \`git fetch origin && git rebase origin/order/<orderId> && git push origin HEAD:order/<orderId>\`,
327
393
  repeating up to 5 times if the push is rejected. Never force-push.
328
394
  - If you drop or change any part of what the goal asked for, even for a good reason, record each one
329
395
  with \`mcp__relai__update_task_status\` metadata \`deviations: [{ "item": "<what the goal asked>",
@@ -340,7 +406,9 @@ Find the default branch with \`git remote show origin\`.
340
406
  on deviations in the approval gate.
341
407
 
342
408
  **orderRole "merge"**:
343
- 1. \`gh pr ready <prUrl>\`, then \`gh pr checks <prUrl> --watch --fail-fast\`.
409
+ 1. \`gh pr ready <prUrl>\`, then \`gh pr checks <prUrl> --watch --fail-fast\`. If the PR has no checks
410
+ (the repo has no CI), check out the PR head and run the repo's own lint, typecheck and test scripts
411
+ from its package manifest instead, and treat a failure there as a failed check.
344
412
  Before merging, replace the PR body with a run report built from
345
413
  \`mcp__relai__list_all_tasks\` filtered to the order's Epic: the feature, the workflow
346
414
  (planning, build, gates, merge), each task with its assignee, status, and created and
package/dist/mcp.js CHANGED
@@ -12538,19 +12538,23 @@ function buildCreateOrderTool(client, repoId, opts) {
12538
12538
  repoId: external_exports.string().optional().describe(opts.ownerScoped ? "Repo to file the order in: any repo your owner owns. Defaults to your home repo." : "Repo to file the order in. Defaults to this agent's home repo."),
12539
12539
  feature: external_exports.string().min(1).optional().describe("What to build, in the requester's words. Optional when issueUrl is given."),
12540
12540
  issueUrl: external_exports.string().optional().describe("A GitHub issue in this repo to build from (https://github.com/<owner>/<repo>/issues/<n>). The planner reads it, and the merge closes it."),
12541
+ reviewPrUrl: external_exports.string().optional().describe('Review this pull request in the repo instead of building something (https://github.com/<owner>/<repo>/pull/<n>). Agents on different vendors each review one angle, a lead merges their findings, and one review is posted on the PR. No gate by default; pass acceptance ["human_approval"] to approve the review before it is posted. feature, when given, narrows what to look at.'),
12542
+ relatedRepos: external_exports.array(external_exports.string()).max(5).optional().describe("Review goals only: ids of other repos you own (see list_repos) whose contracts this PR depends on. Reviewers read them, never write to them, and mark findings about one they could not read as unproven."),
12541
12543
  planReviewers: external_exports.number().int().min(0).max(3).optional().describe("How many other agents must approve the plan before building starts (0 to 3). Reviewers are picked by the API, preferring reviewer agents on another vendor."),
12542
12544
  pairBuilds: external_exports.boolean().optional().describe("Pair every build task with a reviewer on a different vendor: each build carries its own review gate, and the builder is never on the reviewer's vendor."),
12543
12545
  title: external_exports.string().min(1).max(120).optional().describe("A short name for the goal. The planner writes one when omitted."),
12544
- acceptance: external_exports.array(external_exports.enum(["ci_passed", "human_approval", "reviewer_agent"])).optional().describe("Gates that must all pass. Defaults to human_approval."),
12546
+ acceptance: external_exports.array(external_exports.enum(["ci_passed", "human_approval", "reviewer_agent"])).optional().describe("Gates that must all pass. Defaults to human_approval, or none for a review."),
12545
12547
  budget: external_exports.record(external_exports.unknown()).optional().describe("Optional ceilings. Stored only; not enforced.")
12546
12548
  }),
12547
12549
  handler: async (input) => {
12548
- if (!input.feature && !input.issueUrl) return mcpFail("create_order needs feature or issueUrl");
12550
+ if (!input.feature && !input.issueUrl && !input.reviewPrUrl) return mcpFail("create_order needs feature, issueUrl or reviewPrUrl");
12549
12551
  try {
12550
12552
  const created = await client.createOrder({
12551
12553
  repoId: targetRepo(input),
12552
12554
  ...input.feature ? { feature: input.feature } : {},
12553
12555
  ...input.issueUrl ? { issueUrl: input.issueUrl } : {},
12556
+ ...input.reviewPrUrl ? { kind: "review", prUrl: input.reviewPrUrl } : {},
12557
+ ...input.relatedRepos?.length ? { relatedRepos: input.relatedRepos } : {},
12554
12558
  ...input.planReviewers ? { planReviewers: input.planReviewers } : {},
12555
12559
  ...input.pairBuilds ? { pairBuilds: true } : {},
12556
12560
  ...input.title ? { title: input.title } : {},
@@ -13238,21 +13242,42 @@ ${version.body}`
13238
13242
  ] : []
13239
13243
  ];
13240
13244
  }
13245
+ var ATTENTION_STATUSES = "blocked,pending_verification,proposed";
13246
+ function attentionMaxAgeDays() {
13247
+ const n = Number(process.env.ATTENTION_MAX_AGE_DAYS);
13248
+ return Number.isFinite(n) && n > 0 ? n : 7;
13249
+ }
13250
+ var attentionWindowSchema = {
13251
+ includeStale: external_exports.boolean().optional().describe("Include items untouched for longer than maxAgeDays. Off by default so new asks lead."),
13252
+ maxAgeDays: external_exports.number().positive().optional().describe("Hide items untouched for longer than this many days (default 7).")
13253
+ };
13254
+ function attentionCutoff(input) {
13255
+ if (input.includeStale) return void 0;
13256
+ return new Date(Date.now() - (input.maxAgeDays ?? attentionMaxAgeDays()) * 864e5).toISOString();
13257
+ }
13258
+ async function staleAttentionCount(client, cutoff) {
13259
+ if (!cutoff) return 0;
13260
+ const { meta } = await client.getTasksPage({ status: ATTENTION_STATUSES, updatedBefore: cutoff, limit: 1, clip: true });
13261
+ return meta?.total ?? 0;
13262
+ }
13241
13263
  function buildGodCoordinationTools(client) {
13242
13264
  return [
13243
13265
  {
13244
13266
  name: "list_attention",
13245
- description: "List what needs attention across ALL your owner's repos: tasks that are 'blocked' (a worker is waiting), 'pending_verification' (awaiting a review decision), or 'proposed' (a worker's task awaiting commit), plus idle workers that cannot take the ready work that is sitting there (idle_unroutable \u2014 derived now, not from the event log). Each task carries its repoId. A blocked task with metadata.blockedThreadId resumes when you answer with send_message on that thread, as if the owner had. One without it (stalled or overflowed work, or your own task) needs reassigning with assign_task or splitting instead. An idle_unroutable item names the agent and why each task is ineligible (domain, specialization, review_gate, for-human, product-decision, pinned, blockedBy). Capped and clipped, newest first; read one in full with get_task.",
13246
- inputSchema: external_exports.object({}),
13247
- handler: async () => {
13267
+ description: "List what needs attention across ALL your owner's repos: tasks that are 'blocked' (a worker is waiting), 'pending_verification' (awaiting a review decision), or 'proposed' (a worker's task awaiting commit), plus idle workers that cannot take the ready work that is sitting there (idle_unroutable \u2014 derived now, not from the event log). Each task carries its repoId. A blocked task with metadata.blockedThreadId resumes when you answer with send_message (type decision) on that thread, as if the owner had, when the owner has given you a decide delegation for that repo; the task records clearedBy. Answer only reversible, branch-level confirmations yourself (editing, pushing or deleting files on an order branch, choosing between plan options). Merges into a default branch, deploys, deletes outside an order branch, and anything touching credentials or money go to the owner. A blocked task without blockedThreadId (stalled or overflowed work) resumes the same way when you post add_task_comment (type decision) on it; say whether to split, retry or reassign. Your own blocked task never resumes on your answer. An idle_unroutable item names the agent and why each task is ineligible (domain, specialization, review_gate, for-human, product-decision, pinned, blockedBy). Capped and clipped, newest first; read one in full with get_task.",
13268
+ inputSchema: external_exports.object(attentionWindowSchema),
13269
+ handler: async (input) => {
13270
+ const cutoff = attentionCutoff(input);
13248
13271
  const [{ data, meta }, idleUnroutable] = await Promise.all([
13249
13272
  client.getTasksPage({
13250
- status: "blocked,pending_verification,proposed",
13273
+ status: ATTENTION_STATUSES,
13251
13274
  limit: listTasksLimit(),
13252
- clip: true
13275
+ clip: true,
13276
+ ...cutoff ? { updatedAfter: cutoff } : {}
13253
13277
  }),
13254
13278
  client.getIdleUnroutable()
13255
13279
  ]);
13280
+ const staleCount = await staleAttentionCount(client, cutoff);
13256
13281
  const tasks = data ?? [];
13257
13282
  const idle = idleUnroutable ?? [];
13258
13283
  const total = meta?.total ?? tasks.length;
@@ -13260,11 +13285,12 @@ function buildGodCoordinationTools(client) {
13260
13285
  return {
13261
13286
  content: [{
13262
13287
  type: "text",
13263
- text: tasks.length === 0 && idle.length === 0 ? "Nothing needs attention across your repos right now." : JSON.stringify({
13288
+ text: tasks.length === 0 && idle.length === 0 && staleCount === 0 ? "Nothing needs attention across your repos right now." : JSON.stringify({
13264
13289
  tasks,
13265
13290
  taskCount: total,
13266
13291
  ...idle.length > 0 ? { idleUnroutable: idle } : {},
13267
13292
  ...notShown ? { notShown } : {},
13293
+ ...staleCount > 0 ? { staleCount, stale: `${staleCount} older items hidden; pass includeStale: true to see them, and cancel or archive what is dead.` } : {},
13268
13294
  peerBoundary: PEER_BOUNDARY
13269
13295
  }, null, 2)
13270
13296
  }]
@@ -13536,19 +13562,22 @@ function buildOperatorTools(client, ownerId) {
13536
13562
  {
13537
13563
  name: "list_attention",
13538
13564
  description: "List everything across ALL your projects that needs you right now: tasks that are 'blocked' (a worker is waiting on your input), 'pending_verification' (awaiting a review decision), or 'proposed' (a worker's task awaiting your commit), plus idle workers that cannot take the ready work sitting there (idle_unroutable). Call this first to see what to act on. Each task carries its repoId and, for blocked tasks, metadata.blockedThreadId \u2014 the thread to post a reply on (via reply_human) to resume the worker. An idle_unroutable item names the agent and why each task is ineligible.",
13539
- inputSchema: external_exports.object({}),
13540
- handler: async () => {
13541
- const [tasks, idleUnroutable] = await Promise.all([
13542
- client.getTasks({ status: "blocked,pending_verification,proposed" }),
13543
- client.getIdleUnroutable()
13565
+ inputSchema: external_exports.object(attentionWindowSchema),
13566
+ handler: async (input) => {
13567
+ const cutoff = attentionCutoff(input);
13568
+ const [tasks, idleUnroutable, staleCount] = await Promise.all([
13569
+ client.getTasks({ status: ATTENTION_STATUSES, ...cutoff ? { updatedAfter: cutoff } : {} }),
13570
+ client.getIdleUnroutable(),
13571
+ staleAttentionCount(client, cutoff)
13544
13572
  ]);
13545
13573
  const idle = idleUnroutable ?? [];
13546
13574
  return {
13547
13575
  content: [{
13548
13576
  type: "text",
13549
- text: tasks.length === 0 && idle.length === 0 ? "Nothing needs your attention across your projects right now." : JSON.stringify({
13577
+ text: tasks.length === 0 && idle.length === 0 && staleCount === 0 ? "Nothing needs your attention across your projects right now." : JSON.stringify({
13550
13578
  tasks,
13551
- ...idle.length > 0 ? { idleUnroutable: idle } : {}
13579
+ ...idle.length > 0 ? { idleUnroutable: idle } : {},
13580
+ ...staleCount > 0 ? { staleCount, stale: `${staleCount} older items hidden; pass includeStale: true to see them, and cancel or archive what is dead.` } : {}
13552
13581
  }, null, 2)
13553
13582
  }]
13554
13583
  };
@@ -13820,7 +13849,8 @@ function attentionStateOf(task) {
13820
13849
  function describe(task, state) {
13821
13850
  const title = (task.title ?? task.id).slice(0, 80);
13822
13851
  const where = task.repoId ? ` [${task.repoId}]` : "";
13823
- const thread = state === "blocked" && typeof task.metadata?.blockedThreadId === "string" ? ` Reply on thread ${task.metadata.blockedThreadId} to unblock it.` : "";
13852
+ const replyOn = typeof task.metadata?.blockedThreadId === "string" ? task.metadata.blockedThreadId : task.threadId;
13853
+ const thread = state !== "blocked" ? "" : replyOn ? ` Reply on thread ${replyOn} to unblock it.` : ` Answer with add_task_comment on ${task.id} to unblock it.`;
13824
13854
  const next = state === "proposed" ? " Use commit_proposal." : state === "pending_verification" ? " Use review_task." : state === "stalled" ? " Nobody is coming; reassign or cancel it." : "";
13825
13855
  return `relai: "${title}" is ${LABEL[state]}${where} (${task.id}).${thread}${next}`;
13826
13856
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pitboss/cli",
3
- "version": "0.4.6",
3
+ "version": "0.4.8",
4
4
  "private": false,
5
5
  "description": "Connect your coding agents to a pitboss instance",
6
6
  "keywords": [