@nanocollective/roster 0.1.0-alpha.49 → 0.1.0-alpha.50

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
@@ -5727,12 +5727,17 @@ query($owner:String!, $name:String!) {
5727
5727
  ) { nodes { ${LIGHT_PR} } }
5728
5728
  }
5729
5729
  }`;
5730
+ var ROW_EXTRAS = `closedAt
5731
+ last: comments(last:1) { nodes { author { login } createdAt body } }
5732
+ closer: timelineItems(last:1, itemTypes:[CLOSED_EVENT]) {
5733
+ nodes { ... on ClosedEvent { actor { login } } }
5734
+ }`;
5730
5735
  var THREAD_QUERY = `
5731
5736
  query($owner:String!, $name:String!, $number:Int!) {
5732
5737
  repository(owner:$owner, name:$name) {
5733
5738
  issueOrPullRequest(number:$number) {
5734
5739
  ... on Issue {
5735
- number title body url state createdAt updatedAt
5740
+ number title body url state createdAt updatedAt ${ROW_EXTRAS}
5736
5741
  author { login }
5737
5742
  ${REACTIONS}
5738
5743
  labels(first:12) { nodes { name } }
@@ -5740,7 +5745,7 @@ query($owner:String!, $name:String!, $number:Int!) {
5740
5745
  timelineItems(last:100, itemTypes:${ISSUE_TYPES}) { nodes { ${TIMELINE_COMMON} } }
5741
5746
  }
5742
5747
  ... on PullRequest {
5743
- number title body url state createdAt updatedAt isDraft mergeable
5748
+ number title body url state createdAt updatedAt isDraft mergeable ${ROW_EXTRAS}
5744
5749
  author { login }
5745
5750
  ${REACTIONS}
5746
5751
  labels(first:12) { nodes { name } }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanocollective/roster",
3
- "version": "0.1.0-alpha.49",
3
+ "version": "0.1.0-alpha.50",
4
4
  "description": "An agent-run org, powered by GitHub. Scaffold AI staff members whose brain is a repo.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -27,7 +27,10 @@ const KIND_TONE = { decision: "hot", review: "warm", chore: "cool", ask: "", mer
27
27
  a reply just started shows up without a reload. Only while Home is on screen. */
28
28
  const FAST = 5_000;
29
29
  const SLOW = 30_000;
30
+ /** How old the issues on Home may get while it is open before they are read again. */
31
+ const ISSUES_STALE = 120_000;
30
32
  let timer = null;
33
+ let issuesAt = Date.now();
31
34
 
32
35
  export function viewHome(m) {
33
36
  m.append(el("h1", { textContent: "Home" }));
@@ -360,8 +363,16 @@ function poll() {
360
363
  .then((data) => {
361
364
  // Only a change repaints: a poll every few seconds must not move the page under you.
362
365
  const changed = JSON.stringify(data.staff) !== JSON.stringify(S.live?.staff);
366
+ /* A run that just ended has usually replied, closed or opened something, so that is when
367
+ the issues are read again. Otherwise every couple of minutes while Home is open. */
368
+ const ended = S.live && finishedCount(data) !== finishedCount(S.live);
363
369
  S.live = data;
364
- if (changed && S.view === "home" && !document.querySelector("dialog[open]")) repaintInPlace();
370
+ if (ended || Date.now() - issuesAt > ISSUES_STALE) {
371
+ issuesAt = Date.now();
372
+ refreshSoon(false);
373
+ } else if (changed && S.view === "home" && !document.querySelector("dialog[open]")) {
374
+ repaintInPlace();
375
+ }
365
376
  })
366
377
  .catch(() => {})
367
378
  .finally(() => {
@@ -517,10 +528,19 @@ function button(label, primary, onclick) {
517
528
  return b;
518
529
  }
519
530
 
520
- /** After a write: re-read the inbox, and look for the run it starts. */
521
- function refreshSoon() {
531
+ /** How many runs have finished across the staff, to notice one ending. */
532
+ function finishedCount(live) {
533
+ return (live?.staff ?? []).reduce((n, l) => n + (l.finished?.length ?? 0), 0);
534
+ }
535
+
536
+ /**
537
+ * Re-read the issues and repaint where you were. After a write it also looks for the run the
538
+ * write starts; from the poll it does not, since the poll is already running.
539
+ */
540
+ function refreshSoon(lookForRun = true) {
541
+ issuesAt = Date.now();
522
542
  ensureInbox(true)
523
543
  .then(() => S.view === "home" && !document.querySelector("dialog[open]") && repaintInPlace())
524
544
  .catch(() => {});
525
- later(poll, 3_000);
545
+ if (lookForRun) later(poll, 3_000);
526
546
  }
@@ -117,6 +117,14 @@ export const viewPrs = (m) => inboxScreen(m, { prs: true });
117
117
  * what they do on Trackers too.
118
118
  */
119
119
  export function threadInto(host, ref) {
120
+ /* Read fresh. Home can be minutes behind GitHub, and the reason to open something is usually
121
+ to read the reply that made its row change. Reading it again also brings the row up to
122
+ date, so Home is right when the sheet closes. */
123
+ const item = (S.inbox?.items ?? []).find((i) => i.repo === ref.repo && i.number === ref.number);
124
+ if (item) {
125
+ THREADS.delete(item.repo + "#" + item.number);
126
+ item.partial = true;
127
+ }
120
128
  host.append(inboxScreen(el("div"), { prs: ref.kind === "pr", only: ref }));
121
129
  }
122
130