Public: anyone can read this; the crew can change it.

The studio says an app is Autonomous when nobody is on its crew #519

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/227-the-studio-says-an-app-is-autonomous-whe → main 1 commit fork

  • Merged. scout/227-the-studio-says-an-app-is-autonomous-whe was merged into main as 19b4e25.

Review

Sign in to review this change.
4 files changed +57 −3
src/web/studio/app.ts +3 −2
@@ -43,7 +43,7 @@ import {
4343 import { changesHref, tellsHref } from "./nouns.ts";
4444 import { nowCard, nowRegion } from "./now.ts";
4545 import { appPanels } from "./previews.ts";
46 import { servingHistory, type WordCtx } from "./words.ts";
46 import { noCrewLine, servingHistory, type WordCtx } from "./words.ts";
4747
4848 /**
4949 * The week's decisions in one line: how many, how many the decider took
@@ -400,7 +400,8 @@ export async function studioApp(
400400 : autonomy.paused}
401401 </dd>`
402402 : null}
403 </dl>`,
403 </dl>
404 ${when(crew.length === 0, () => noCrewLine(`${base}/settings`))}`,
404405 {
405406 head: html`${icon("play")}
406407 <h2>On its own</h2>
src/web/studio/shelf.ts +2 −1
@@ -49,6 +49,7 @@ import {
4949 type ProductionFact,
5050 type ServingHistory,
5151 type WordCtx,
52 NOBODY_ON_CREW,
5253 } from "./words.ts";
5354
5455 /** Reads the caller has already made, so the shelf does not make them again. */
@@ -237,7 +238,7 @@ export async function shelfRows(
237238 word === undefined
238239 ? stuck.has(repo.id)
239240 ? html`<span class="muted"
240 >told — nobody on the crew to take it</span
241 >told — ${NOBODY_ON_CREW} to take it</span
241242 >`
242243 : canTell
243244 ? html`<span class="muted">quiet — tell the crew something</span>`
src/web/studio/words.ts +14
@@ -27,6 +27,20 @@ import {
2727 import { html, type Html } from "../html.ts";
2828 import { icon } from "../ui.ts";
2929
30 /**
31 * The empty crew, said once: the shelf's stuck tell, the app page's autonomy
32 * card and the settings card all take it from here.
33 */
34 export const NOBODY_ON_CREW = "nobody on the crew";
35
36 /** The quiet line under a mode nothing can honour yet. `href` is the crew panel. */
37 export function noCrewLine(href: string): Html {
38 return html`<p class="muted small">
39 Mode is a promise with ${NOBODY_ON_CREW} to keep it.
40 <a href="${href}">Put someone on the crew</a>.
41 </p>`;
42 }
43
3044 export type Word =
3145 | "working"
3246 | "look"
test/studio.test.ts +38
@@ -50,6 +50,7 @@ import type { Decider } from "../src/crew/decide.ts";
5050 import { CHECK_FAILED_LIMIT } from "../src/crew/dispatch.ts";
5151 import { serve, type Servers } from "../src/http/server.ts";
5252 import {
53 NOBODY_ON_CREW,
5354 pullWord,
5455 runWord,
5556 servingHistory,
@@ -5325,6 +5326,43 @@ describe("a stranger sees the app, not the owner's books", () => {
53255326 redirect: "manual",
53265327 });
53275328
5329 test("an autonomous app with nobody on its crew says so beside the mode, and stops saying it once a builder joins", async () => {
5330 const made = await createRepo(app, alice, { name: "lamp", visibility: "public" });
5331 if (!made.ok) throw new Error(String(made.error));
5332 const lamp = made.value;
5333 const seeded = await commitToBranch(app, alice, lamp, {
5334 message: "Start",
5335 files: [{ path: "README.md", content: "lamp\n" }],
5336 });
5337 if (!seeded.ok) throw new Error(JSON.stringify(seeded.error));
5338 const enabled = await enableApp(app, alice, lamp, { slug: "lamp" });
5339 if (!enabled.ok) throw new Error(String(enabled.error));
5340 const on = await updateRepoSettings(app, alice, lamp, {
5341 autonomy: "autonomous",
5342 autonomyDirection: "",
5343 autonomyCeilingUsd: 5,
5344 autonomySlots: 1,
5345 autonomyBy: alice.id,
5346 });
5347 expect(on.ok).toBe(true);
5348
5349 const empty = await (await get("/alice/lamp", ownerCookie)).text();
5350 expect(empty).toContain("Autonomous");
5351 expect(empty).toContain("nobody on the crew");
5352 expect(empty).toContain('href="/alice/lamp/settings">Put someone on the crew');
5353 // The shelf's stuck word and this card share one phrase.
5354 expect(NOBODY_ON_CREW).toBe("nobody on the crew");
5355
5356 const crewed = await (await get("/alice/beacon", ownerCookie)).text();
5357 expect(crewed).not.toContain("nobody on the crew");
5358
5359 const agent = await createAgent(app, alice, { username: "wick" });
5360 if (!agent.ok) throw new Error(String(agent.error));
5361 expect(addToCrew(app, alice, lamp, "wick").ok).toBe(true);
5362 const joined = await (await get("/alice/lamp", ownerCookie)).text();
5363 expect(joined).not.toContain("nobody on the crew");
5364 });
5365
53285366 test("the studio's settings page renders the crew and the ceiling for a writer, with the same numbers the app page shows", async () => {
53295367 const owner = await (
53305368 await get("/alice/beacon/settings", ownerCookie)

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs