@nanocollective/roster 0.1.0-alpha.11 → 0.1.0-alpha.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanocollective/roster",
3
- "version": "0.1.0-alpha.11",
3
+ "version": "0.1.0-alpha.12",
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": {
@@ -117,3 +117,7 @@
117
117
  .verdict{background:var(--accent-soft);border:1px solid transparent;border-radius:var(--r);
118
118
  padding:9px 12px;font-size:12.5px}
119
119
  .verdict p{margin:0}
120
+
121
+ .plansteps{margin:6px 0 12px;padding-left:20px;font-size:13.5px;line-height:1.7}
122
+ .planfiles{margin:0 0 12px}
123
+ .planfiles summary{cursor:pointer;color:var(--ink-dim);font-size:12.5px}
@@ -8,7 +8,7 @@ import { el } from "../dom.js";
8
8
 
9
9
  export function credentialPanel() {
10
10
  const box = el("div", { className: "manual" });
11
- box.append(el("b", { textContent: "Your agent's credential, once" }));
11
+ box.append(el("b", { textContent: "Agent credential" }));
12
12
  const body = el("div");
13
13
  box.append(body);
14
14
  body.append(el("p", { className: "sub", textContent: "Looking at where it would go…" }));
@@ -28,8 +28,7 @@ function draw(body, c) {
28
28
  el("p", {
29
29
  className: "sub",
30
30
  textContent:
31
- "Nothing reads it until somebody is hired, so this box opens once there is a staff " +
32
- "member. It is asked for once, not once per hire.",
31
+ "Available after your first hire. You only add it once.",
33
32
  }),
34
33
  );
35
34
  return;
@@ -40,8 +39,7 @@ function draw(body, c) {
40
39
  el("p", {
41
40
  className: "sub",
42
41
  textContent:
43
- c.name + " is already an org secret, shared with " + c.orgSecret.visibility + " repos. " +
44
- "Each hire adds its brain to it. Paste a new one only to replace it.",
42
+ c.name + " is already set. Paste a new one only to replace it.",
45
43
  }),
46
44
  );
47
45
  }
@@ -53,7 +51,7 @@ function draw(body, c) {
53
51
  (c.plan.mode === "org"
54
52
  ? "Stored as one org secret, " + c.name + ", shared with " + c.brains.join(", ") + ". "
55
53
  : "Stored as " + c.name + " on each of " + c.brains.join(", ") + ", because " + c.plan.reason + ". ") +
56
- "It goes to gh on standard input and is never written to disk.",
54
+ "It's never written to disk.",
57
55
  }),
58
56
  );
59
57
 
@@ -80,8 +78,8 @@ function draw(body, c) {
80
78
  el("p", {
81
79
  textContent:
82
80
  r.mode === "org"
83
- ? "Stored once for the org, shared with " + r.repos.length + " brains."
84
- : "Stored on " + r.repos.join(", ") + ".",
81
+ ? "Saved."
82
+ : "Saved on " + r.repos.join(", ") + ".",
85
83
  }),
86
84
  );
87
85
  } catch (err) {
@@ -18,9 +18,7 @@ export function repoPicker(opts) {
18
18
  el("b", { textContent: "Which repos the staff work in" }),
19
19
  el("p", {
20
20
  textContent:
21
- "Repos marked as products are the ones staff contribute to without owning. A new hire " +
22
- "picks them up automatically; somebody already hired keeps the works_in list in their " +
23
- "own staff.yaml.",
21
+ "Add the repos your staff should work on. New hires get access to them automatically.",
24
22
  }),
25
23
  );
26
24
 
@@ -66,8 +66,7 @@ export async function viewGettingStarted(main) {
66
66
  next.append(
67
67
  el("p", {
68
68
  textContent:
69
- "Nothing runs until somebody is hired. Hiring creates their repo, their workflows and " +
70
- "their pinned issue; the GitHub App and the charter follow on their card.",
69
+ "Nothing runs until you hire someone. You'll set up their GitHub App and charter from their card.",
71
70
  }),
72
71
  el("div", { className: "row" }, [hire]),
73
72
  );
@@ -120,9 +119,7 @@ function render(main) {
120
119
  el("p", {
121
120
  className: "sub",
122
121
  textContent:
123
- "Sign in with gh, choose the organisation and the agent, then what is left: a setting " +
124
- "roster tries for you, the agent's credential, the repos your staff work in, and the two " +
125
- "files only you can write. Nothing is created until you have read the plan.",
122
+ "Choose an organisation and a coding agent. Nothing is created until you press Create it.",
126
123
  }),
127
124
  );
128
125
 
@@ -148,8 +145,7 @@ function stepGh() {
148
145
  el("p", {
149
146
  className: "sub",
150
147
  textContent:
151
- "roster does everything through your own gh, so it holds no token of its own. Run this " +
152
- "in a terminal, then reload:",
148
+ "Run this in a terminal, then reload:",
153
149
  }),
154
150
  el("pre", { className: "cmd", textContent: "gh auth login" }),
155
151
  );
@@ -206,8 +202,7 @@ function stepOrg(main) {
206
202
  orgWrap.append(
207
203
  el("small", {
208
204
  textContent:
209
- "Repos are created here. GitHub has no API for creating an organisation, so make one on " +
210
- "github.com first if you need to.",
205
+ "Don't have one? Create it on github.com first.",
211
206
  }),
212
207
  );
213
208
  form.append(orgWrap);
@@ -250,8 +245,8 @@ function stepOrg(main) {
250
245
  });
251
246
  other.input.addEventListener("change", look);
252
247
 
253
- const name = field("name", "What the business is called", "", "Shown to the agents. Defaults to the org.");
254
- const human = field("human", "Your GitHub login", S.gh.login ?? "", "The person the agents answer to.");
248
+ const name = field("name", "What the business is called", "", "Defaults to the organisation name.");
249
+ const human = field("human", "Your GitHub login", S.gh.login ?? "", "The person the staff report to.");
255
250
 
256
251
  card.append(form);
257
252
  const agentHead = el("h3", { textContent: "Which coding agent runs a session" });
@@ -272,8 +267,7 @@ function stepOrg(main) {
272
267
  const agentNote = el("p", {
273
268
  className: "sub",
274
269
  textContent:
275
- "Anything else works too: a runner is an install command, a run command and the name of " +
276
- "the secret holding its credential. Write those three into org.yaml afterwards.",
270
+ "Using a different agent? Pick any of these, then set it in org.yaml afterwards.",
277
271
  });
278
272
  card.append(agentNote);
279
273
 
@@ -349,26 +343,20 @@ function stepOrg(main) {
349
343
  out.replaceChildren(el("p", { className: "sub", textContent: "Working…" }));
350
344
  try {
351
345
  const result = await planTenant(p);
352
- out.replaceChildren();
353
- out.append(
354
- el("p", {
355
- textContent:
356
- `${result.files.length} files in ${result.dir}, and one private repo, ${p.org}/roster-ops, ` +
357
- "with its Actions access set so every repo in the org can call its workflow. If GitHub " +
358
- "refuses that, you get the reason and the page to click.",
359
- }),
360
- );
361
- const list = el("div", { className: "filelist" });
362
- for (const f of result.files) list.append(el("code", { textContent: "+ " + f }));
363
- out.append(list);
364
- out.append(
365
- el("p", {
366
- className: "sub",
367
- textContent:
368
- "org/business.md arrives as questions, not prose. Answering it is the next step and " +
369
- "it is the one that decides whether any of this is worth running.",
370
- }),
371
- );
346
+ const steps = el("ol", { className: "plansteps" }, [
347
+ el("li", { textContent: `Create a private repo, ${p.org}/roster-ops, to hold the org's shared settings.` }),
348
+ el("li", { textContent: `Put a copy of it in ${result.dir}.` }),
349
+ el("li", { textContent: `Let the other repos in ${p.org} run its workflow.` }),
350
+ ]);
351
+ const files = el("details", { className: "planfiles" }, [
352
+ el("summary", { textContent: `The ${result.files.length} files it writes` }),
353
+ el("div", { className: "filelist" }, result.files.map((f) => el("code", { textContent: f }))),
354
+ ]);
355
+ const next = el("p", {
356
+ className: "sub",
357
+ textContent: "After that: describe the business, set this month's priorities, and hire your first staff member.",
358
+ });
359
+ out.replaceChildren(el("p", { textContent: "Create it will:" }), steps, files, next);
372
360
  go.hidden = false;
373
361
  } catch (err) {
374
362
  out.replaceChildren(el("p", { className: "err", textContent: String(err.message || err) }));
@@ -401,13 +389,6 @@ function stepOrg(main) {
401
389
  function afterCreate(n) {
402
390
  fileSteps.clear();
403
391
  const card = step(n, "What is left", false);
404
- card.append(
405
- el("p", {
406
- textContent:
407
- "The first is a setting roster tries for you. The last two are the files that decide " +
408
- "whether any of this is worth running, and only you can write them.",
409
- }),
410
- );
411
392
  card.append(accessStep());
412
393
  card.append(credentialPanel());
413
394
 
@@ -417,9 +398,8 @@ function afterCreate(n) {
417
398
 
418
399
  const business = fileStep(
419
400
  "business",
420
- "Answer org/business.md",
421
- "It ships as questions. It is composed into the top of every prompt, every run, and an " +
422
- "agent that cannot answer them writes work that is plausible and generic.",
401
+ "Describe the business",
402
+ "Answer the questions in org/business.md. Every staff member reads it before they start work.",
423
403
  );
424
404
  // The copy-a-prompt loop, which is the whole answer to "how do I write this file".
425
405
  business.append(paste({ kind: "discover", title: "Write it with your own AI", onSaved: recheck }));
@@ -427,9 +407,8 @@ function afterCreate(n) {
427
407
 
428
408
  const priorities = fileStep(
429
409
  "priorities",
430
- "Rank org/priorities.md",
431
- "What matters this month, at most three things in order, and what is out of scope. Every " +
432
- "daily run reads it; without it each staff member picks its own direction from its charter.",
410
+ "Set this month's priorities",
411
+ "Up to three things, in order, plus what's out of scope. Saved as org/priorities.md.",
433
412
  );
434
413
  priorities.append(prioritiesEditor());
435
414
  card.append(priorities);
@@ -500,7 +479,7 @@ function prioritiesEditor() {
500
479
  el("p", {
501
480
  className: r.pushed ? "sub" : "err",
502
481
  textContent: r.pushed
503
- ? "Committed and pushed. Every daily run reads it from the next one."
482
+ ? "Saved and pushed."
504
483
  : "Committed, but the push failed: " + (r.note ?? ""),
505
484
  }),
506
485
  );
@@ -529,7 +508,7 @@ function opsName() {
529
508
  */
530
509
  function accessStep() {
531
510
  const box = el("div", { className: "manual" });
532
- box.append(el("b", { textContent: "Let every repo in the org call the ops repo's workflow" }));
511
+ box.append(el("b", { textContent: "Let staff repos run the shared workflow" }));
533
512
  const out = el("div");
534
513
  box.append(out);
535
514
  const say = (text, cls) => el("p", { className: cls ?? "sub", textContent: text });
@@ -539,8 +518,7 @@ function accessStep() {
539
518
  out.replaceChildren(
540
519
  say(
541
520
  (why ? why + " " : "") +
542
- "Settings → Actions → General → Access on roster-ops. Skip it and every workflow fails " +
543
- "with “workflow not found”.",
521
+ "Needed so staff repos can run the shared workflow.",
544
522
  ),
545
523
  el("div", { className: "row" }, [go]),
546
524
  );
@@ -549,7 +527,7 @@ function accessStep() {
549
527
  try {
550
528
  const r = await setAccess();
551
529
  if (r.ok) {
552
- out.replaceChildren(say("Set. Every repo in the org can call roster-ops."));
530
+ out.replaceChildren(say("Done."));
553
531
  return;
554
532
  }
555
533
  out.replaceChildren(
@@ -567,7 +545,7 @@ function accessStep() {
567
545
  out.replaceChildren(say("Checking…"));
568
546
  getAccess()
569
547
  .then((r) => {
570
- if (r.ok) out.replaceChildren(say("Done. Every repo in the org can call roster-ops."));
548
+ if (r.ok) out.replaceChildren(say("Done."));
571
549
  else offer(r.level ? "It is set to “" + r.level + "”." : "");
572
550
  })
573
551
  .catch(() => offer(""));