@nanocollective/roster 0.1.0-alpha.12 → 0.1.0-alpha.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanocollective/roster",
3
- "version": "0.1.0-alpha.12",
3
+ "version": "0.1.0-alpha.13",
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": {
@@ -10,6 +10,8 @@ import { el, toClipboard } from "../dom.js";
10
10
  const LEVEL_ORDER = { fail: 0, warn: 1, ok: 2 };
11
11
 
12
12
  /**
13
+ * @param opts.skip finding ids the caller already shows as a step of its own, so they are not
14
+ * reported twice. With `opts.hideWhenClean`, a list left empty draws nothing at all.
13
15
  * @param opts.shell when Health draws this, the section it lives in: `{actions, say}`. The
14
16
  * setup screen passes nothing and gets the layout it has always had. Its own screen is a
15
17
  * wizard, where a chunky button and a paragraph under it are right; on Health it is one
@@ -32,9 +34,14 @@ export async function checklist(host, opts = {}) {
32
34
  const findings = (report.findings ?? []).slice().sort(
33
35
  (a, b) => (LEVEL_ORDER[a.level] ?? 3) - (LEVEL_ORDER[b.level] ?? 3),
34
36
  );
35
- const bad = findings.filter((f) => f.level !== "ok");
37
+ const skip = new Set(opts.skip ?? []);
38
+ const bad = findings.filter((f) => f.level !== "ok" && !skip.has(f.id));
36
39
 
37
40
  host.replaceChildren();
41
+ if (!bad.length && opts.hideWhenClean) {
42
+ opts.onEmpty?.();
43
+ return;
44
+ }
38
45
  opts.shell?.say(bad.length ? String(bad.length) : "clean");
39
46
  host.append(
40
47
  el("p", {
@@ -83,7 +90,7 @@ export async function checklist(host, opts = {}) {
83
90
  const again = el("button", { className: btnClass, textContent: "Check again" });
84
91
  again.onclick = () => checklist(host, opts);
85
92
 
86
- const feet = opts.shell?.actions ?? host;
93
+ const feet = opts.shell?.actions ?? host.appendChild(el("div", { className: "row" }));
87
94
  if (opts.shell) feet.replaceChildren();
88
95
  feet.append(copy, again, note);
89
96
  if (bad.length) {
@@ -92,8 +99,7 @@ export async function checklist(host, opts = {}) {
92
99
  className: noteClass,
93
100
  style: "flex-basis:100%",
94
101
  textContent:
95
- "Paste it into Cursor, Claude Code or anything else that can edit files here, then " +
96
- "check again. The ids above should be gone.",
102
+ "Paste them into your coding agent, then check again.",
97
103
  }),
98
104
  );
99
105
  }
@@ -30,6 +30,12 @@ let S = null; // /api/setup/status, refreshed after anything that changes the wo
30
30
  /* Where the doctor checklist is drawn on this screen, so a save can re-run it. Left stale, it
31
31
  went on saying business.stub after business.md had been saved, until "Check again". */
32
32
  let healthHost = null;
33
+ let healthStep = null;
34
+
35
+ /* What the "What is left" cards already ask for. Doctor reporting them as well, right after a
36
+ successful create, read as the create having failed. */
37
+ const COVERED = ["business", "business.stub", "priorities", "priorities.stub", "actions-access", "secrets", "agent"];
38
+ const HEALTH = { skip: COVERED, hideWhenClean: true };
33
39
 
34
40
  /* Each "what is left" step that is a file, by id, so a save can mark it done in place rather
35
41
  than repainting the page and throwing away the diff somebody is still reading. */
@@ -75,11 +81,12 @@ export async function viewGettingStarted(main) {
75
81
 
76
82
  main.append(afterCreate(App.data?.staff?.length ? 1 : 2));
77
83
 
78
- const health = step(App.data?.staff?.length ? 2 : 3, "What doctor still says", false);
84
+ const health = step(App.data?.staff?.length ? 2 : 3, "Other problems", false);
79
85
  healthHost = el("div", { style: "margin-top:12px" });
80
86
  health.append(healthHost);
81
87
  main.append(health);
82
- checklist(healthHost, {});
88
+ healthStep = health;
89
+ checklist(healthHost, { ...HEALTH, onEmpty: () => health.remove() });
83
90
  }
84
91
 
85
92
  /** Whether the sidebar offers Getting started: while anything is left, or while it is open. */
@@ -93,7 +100,7 @@ export function paintSetupNav() {
93
100
  again rather than updated by hand. The sidebar's list comes from /api/org, which is the one
94
101
  the portal already reads. */
95
102
  async function recheck() {
96
- if (healthHost) checklist(healthHost, {});
103
+ if (healthHost) checklist(healthHost, { ...HEALTH, onEmpty: () => healthStep?.remove() });
97
104
  try {
98
105
  S = await getSetup();
99
106
  for (const [id, mark] of fileSteps) mark(!(S.tenant.left ?? []).includes(id));
@@ -166,13 +173,9 @@ function stepOrg(main) {
166
173
  el("p", {
167
174
  className: "sub",
168
175
  textContent:
169
- "Reload the page to open the portal. Anything below that is still undone stays under " +
170
- "Getting started in the sidebar until it is.",
176
+ "Finish the steps below. They stay under Getting started in the sidebar until they're done.",
171
177
  }),
172
178
  );
173
- healthHost = el("div", { style: "margin-top:12px" });
174
- card.append(healthHost);
175
- checklist(healthHost, {});
176
179
  return card;
177
180
  }
178
181