@nanocollective/roster 0.1.0-alpha.5 → 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.
Files changed (102) hide show
  1. package/README.md +70 -84
  2. package/dist/cli.js +4833 -2752
  3. package/docs/README.md +9 -6
  4. package/docs/agents.md +24 -20
  5. package/docs/architecture.md +13 -5
  6. package/docs/charters/analyst.md +65 -0
  7. package/docs/charters/cmo.md +69 -0
  8. package/docs/charters/community.md +63 -0
  9. package/docs/charters/cto.md +71 -0
  10. package/docs/charters/designer.md +65 -0
  11. package/docs/charters/devops.md +65 -0
  12. package/docs/charters/pm.md +70 -0
  13. package/docs/charters/qa.md +65 -0
  14. package/docs/charters/support.md +60 -0
  15. package/docs/charters/writer.md +63 -0
  16. package/docs/commands.md +93 -7
  17. package/docs/concepts.md +61 -14
  18. package/docs/cost.md +36 -1
  19. package/docs/developing.md +16 -21
  20. package/docs/doctor-codes.md +10 -2
  21. package/docs/export.md +2 -0
  22. package/docs/extending.md +2 -2
  23. package/docs/getting-started.md +128 -78
  24. package/docs/images/brain.jpg +0 -0
  25. package/docs/images/org.jpg +0 -0
  26. package/docs/images/prompt.jpg +0 -0
  27. package/docs/images/setup-org.jpg +0 -0
  28. package/docs/images/setup-plan.jpg +0 -0
  29. package/docs/images/staff.jpg +0 -0
  30. package/docs/manual-steps.md +94 -123
  31. package/docs/memory.md +21 -3
  32. package/docs/org-yaml.md +40 -2
  33. package/docs/portal.md +165 -48
  34. package/docs/prompts.md +31 -4
  35. package/docs/security.md +37 -5
  36. package/docs/session-workflow.md +63 -17
  37. package/docs/staff-yaml.md +30 -3
  38. package/docs/troubleshooting.md +8 -8
  39. package/docs/upgrading.md +9 -3
  40. package/docs/writing-a-charter.md +28 -0
  41. package/package.json +18 -20
  42. package/templates/brain/.github/workflows/%%STAFF%%-daily.yaml +26 -1
  43. package/templates/brain/.github/workflows/%%STAFF%%-mention.yaml +41 -7
  44. package/templates/brain/CHARTER.md +3 -3
  45. package/templates/brain/README.md +1 -0
  46. package/templates/brain/log/decisions.md +3 -0
  47. package/templates/brain/staff.yaml +4 -1
  48. package/templates/brain/strategy/ideas.md +7 -0
  49. package/templates/briefs/priorities.md +46 -0
  50. package/templates/ops/.github/workflows/session.yaml +236 -15
  51. package/templates/ops/agents.mjs +7 -3
  52. package/templates/ops/compose.mjs +31 -3
  53. package/templates/ops/inflight.mjs +157 -0
  54. package/templates/ops/org/operating.md +43 -4
  55. package/templates/ops/org/voice.md +9 -0
  56. package/templates/ops/prompts/_inflight.md +14 -0
  57. package/templates/ops/prompts/_paths.md +2 -1
  58. package/templates/ops/prompts/daily.md +37 -9
  59. package/templates/ops/prompts/mention.md +21 -0
  60. package/templates/ops/run-record.mjs +146 -0
  61. package/templates/portal/css/base.css +167 -73
  62. package/templates/portal/css/brain.css +23 -20
  63. package/templates/portal/css/diff.css +10 -9
  64. package/templates/portal/css/graph.css +12 -7
  65. package/templates/portal/css/health.css +13 -11
  66. package/templates/portal/css/home.css +93 -0
  67. package/templates/portal/css/inbox.css +45 -25
  68. package/templates/portal/css/layout.css +90 -46
  69. package/templates/portal/css/markdown.css +36 -14
  70. package/templates/portal/css/runs.css +13 -0
  71. package/templates/portal/css/setup.css +116 -34
  72. package/templates/portal/index.html +21 -9
  73. package/templates/portal/js/api.js +44 -4
  74. package/templates/portal/js/app.js +94 -9
  75. package/templates/portal/js/dialog.js +83 -0
  76. package/templates/portal/js/homesort.js +174 -0
  77. package/templates/portal/js/icons.js +37 -0
  78. package/templates/portal/js/inflight.js +18 -0
  79. package/templates/portal/js/md.js +5 -2
  80. package/templates/portal/js/mdedit.js +84 -0
  81. package/templates/portal/js/readiness.js +70 -0
  82. package/templates/portal/js/refresh.js +10 -2
  83. package/templates/portal/js/state.js +11 -5
  84. package/templates/portal/js/views/app.js +24 -7
  85. package/templates/portal/js/views/brain.js +1 -1
  86. package/templates/portal/js/views/checklist.js +10 -4
  87. package/templates/portal/js/views/credential.js +84 -0
  88. package/templates/portal/js/views/graph.js +1 -1
  89. package/templates/portal/js/views/health.js +17 -4
  90. package/templates/portal/js/views/hire.js +593 -0
  91. package/templates/portal/js/views/home.js +546 -0
  92. package/templates/portal/js/views/inbox.js +226 -70
  93. package/templates/portal/js/views/org.js +46 -106
  94. package/templates/portal/js/views/orgedit.js +234 -0
  95. package/templates/portal/js/views/paste.js +87 -21
  96. package/templates/portal/js/views/prompt.js +11 -4
  97. package/templates/portal/js/views/repos.js +20 -15
  98. package/templates/portal/js/views/runonce.js +94 -0
  99. package/templates/portal/js/views/runs.js +170 -0
  100. package/templates/portal/js/views/setup.js +261 -75
  101. package/templates/portal/js/views/staff.js +170 -243
  102. package/templates/portal/js/views/todo.js +62 -0
@@ -0,0 +1,84 @@
1
+ /* The agent's credential, stored once for the org.
2
+ *
3
+ * The value goes from this box to the local server in a POST, and from there to gh on its
4
+ * standard input. It is not kept in the page after it is sent, and nothing echoes it back. */
5
+
6
+ import { getCredential, storeCredential } from "../api.js";
7
+ import { el } from "../dom.js";
8
+
9
+ /** @param opts.bare drawn inside a step that already has a title. `onStatus(done)` hears whether one is stored. */
10
+ export function credentialPanel(opts = {}) {
11
+ const box = el("div", { className: opts.bare ? "" : "manual" });
12
+ if (!opts.bare) box.append(el("b", { textContent: "Agent credential" }));
13
+ const body = el("div");
14
+ box.append(body);
15
+ body.append(el("p", { className: "sub", textContent: "Checking…" }));
16
+
17
+ getCredential()
18
+ .then((c) => {
19
+ opts.onStatus?.(Boolean(c.stored ?? c.orgSecret));
20
+ draw(body, c, opts);
21
+ })
22
+ .catch((err) => body.replaceChildren(el("p", { className: "err", textContent: String(err.message || err) })));
23
+ return box;
24
+ }
25
+
26
+ function draw(body, c, opts = {}) {
27
+ body.replaceChildren();
28
+
29
+ if (!(c.brains ?? []).length) {
30
+ // Inside a step, the step's own hint already says when this opens.
31
+ if (!opts.bare) body.append(el("p", { className: "sub", textContent: "Available after your first hire. You only add it once." }));
32
+ return;
33
+ }
34
+
35
+ const form = el("div", { className: "credform" });
36
+ const input = el("input", { type: "password", placeholder: "Paste it here", autocomplete: "off", className: "textfield" });
37
+ const go = el("button", { className: "btn primary", textContent: "Save" });
38
+ const out = el("div");
39
+ form.append(
40
+ ...(c.howTo ? [el("p", { className: "sub", textContent: "To get one, " + c.howTo })] : []),
41
+ input,
42
+ el("div", { className: "row" }, [go]),
43
+ out,
44
+ );
45
+
46
+ // Stored already, on the org or on every brain repo: say so, and keep replacing it one click away.
47
+ if (c.stored ?? c.orgSecret) {
48
+ const replace = el("button", { className: "ghbtn", textContent: "Replace it" });
49
+ replace.onclick = () => {
50
+ replace.remove();
51
+ form.hidden = false;
52
+ input.focus?.();
53
+ };
54
+ form.hidden = true;
55
+ body.append(el("p", { className: "okline", textContent: "✓ Stored as " + c.name + "." }), replace, form);
56
+ } else {
57
+ body.append(form);
58
+ }
59
+
60
+ go.onclick = async () => {
61
+ const value = String(input.value ?? "").trim();
62
+ if (!value) {
63
+ input.focus?.();
64
+ return;
65
+ }
66
+ go.disabled = true;
67
+ go.textContent = "Saving…";
68
+ try {
69
+ const r = await storeCredential(value, false);
70
+ input.value = "";
71
+ if (!r.ok) throw new Error(r.error);
72
+ opts.onStatus?.(true);
73
+ out.replaceChildren(
74
+ ...(r.fellBack ? [el("p", { className: "sub", textContent: "Saved on each repo instead: " + r.fellBack })] : []),
75
+ el("p", { className: "okline", textContent: "✓ Saved." }),
76
+ );
77
+ } catch (err) {
78
+ out.replaceChildren(el("p", { className: "err", textContent: String(err.message || err) }));
79
+ } finally {
80
+ go.disabled = false;
81
+ go.textContent = "Save";
82
+ }
83
+ };
84
+ }
@@ -53,7 +53,7 @@ function drawGraph(canvas, wrap, s) {
53
53
  }
54
54
  const groups = [...members.keys()].sort((a, b) => members.get(b).length - members.get(a).length);
55
55
 
56
- const PALETTE = ["#7cc7a4","#7aa2f7","#c99bd6","#d8a657","#6fc3c9","#e07b7b","#b3c46b","#e0a1c0","#9d9ff5","#8fb0d9"];
56
+ const PALETTE = ["#30d158","#0a84ff","#bf5af2","#ff9f0a","#64d2ff","#ff453a","#ffcc00","#ff375f","#5e5ce6","#ac8e68"];
57
57
  const colour = new Map(groups.map((g, i) => [g, PALETTE[i % PALETTE.length]]));
58
58
 
59
59
  // The ring grows with the number of groups so they never crowd, and each group keeps its
@@ -1,12 +1,14 @@
1
1
  /* Is the scaffolding still there, has the agent been running, and what does lint say. */
2
2
 
3
3
  import { post } from "../api.js";
4
+ import { askYes } from "../dialog.js";
4
5
  import { ago, el, esc, kb } from "../dom.js";
5
6
  import { inline } from "../md.js";
6
7
  import { render } from "../router.js";
7
8
  import { S, staff } from "../state.js";
8
9
  import { checklist } from "./checklist.js";
9
10
  import { copyAmendBrief } from "./prompt.js";
11
+ import { runOnce } from "./runonce.js";
10
12
 
11
13
  const DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
12
14
 
@@ -81,7 +83,18 @@ export function viewHealth(m) {
81
83
  doctor, bordered boxes for the prompt audit, cards with two buttons each for lint. Same
82
84
  question in all three, so one shape: a heading that carries its own count, a line saying
83
85
  what the section is, the findings as rows, and the section's actions at the end. */
84
- const doctor = section(m, "The org, from roster doctor", "doctor");
86
+ /* A workflow that has never run is unproven, and the way to prove it is to run it. Here
87
+ because Health is where "unproven" is read; a success re-runs the checks below. */
88
+ let doctor = null;
89
+ m.append(
90
+ runOnce({
91
+ staff: s.handle,
92
+ name: s.name,
93
+ onDone: (ok) => ok && doctor && checklist(doctor.body, { shell: doctor }),
94
+ }),
95
+ );
96
+
97
+ doctor = section(m, "The org, from roster doctor", "doctor");
85
98
  checklist(doctor.body, { shell: doctor });
86
99
 
87
100
  /* What is wrong with what this agent is sent. It used to sit in the tree on the Prompt
@@ -132,7 +145,7 @@ function memoryProblems({ body, actions, say }, s) {
132
145
  const { row, body: text } = finding(
133
146
  p.level === "error" ? "error" : "warning",
134
147
  { html: inline(p.message) },
135
- [p.rule, p.line ? "INDEX.md:" + p.line : ""],
148
+ [p.rule, p.line ? "INDEX.md:" + p.line : (p.file ?? "")],
136
149
  );
137
150
  const status = el("span", { className: "meta" });
138
151
  const btn = el("button", { className: "ghbtn", textContent: "Ask " + s.handle.toUpperCase() + " to fix" });
@@ -263,13 +276,13 @@ export async function askToFix(s, problems, btn, status) {
263
276
  "",
264
277
  "| rule | where | what |",
265
278
  "|---|---|---|",
266
- ...problems.map((p) => "| `" + p.rule + "` | " + (p.line ? "INDEX.md:" + p.line : "—") + " | " +
279
+ ...problems.map((p) => "| `" + p.rule + "` | " + (p.line ? "INDEX.md:" + p.line : (p.file ?? "—")) + " | " +
267
280
  String(p.message).replace(/\|/g, "\\|") + " |"),
268
281
  "",
269
282
  "Fix in your next session and close this.",
270
283
  ].join("\n");
271
284
 
272
- if (!confirm("Open an issue in " + s.brain + "?")) return;
285
+ if (!(await askYes({ title: "Open an issue in " + s.brain + "?", confirm: "Open it" }))) return;
273
286
  btn.disabled = true;
274
287
  status.textContent = "opening…";
275
288
  status.className = "meta";