@loompad/cli 1.2.3 → 1.2.4

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/CHANGELOG.md CHANGED
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.2.4] — 2026-10-22
11
+
12
+ Team auto-orchestration, set up in one step and steadier on a teammate's machine.
13
+
14
+ ### Added
15
+
16
+ - **`loom team auto` — two machines, one goal, set up in one step.** `loom team auto` says whether team auto-orchestration is ready in this project, which teammates' agents a goal would get, and what's missing; `loom team auto on` shares the project, writes `loom.team.json` with `runners.shared` when the repo has none (commit and merge it), and turns on this machine's shared runner. The Team tab shows the same as a **Two machines, one goal** card with a **Turn on** button.
17
+
18
+ ### Fixed
19
+
20
+ - **A teammate's task could still fail to commit on their machine.** The clone's own Loom takes its end-of-turn checkpoint in the git index at the same moment the task commits, and could undo the task's staging ("nothing to commit"). The runner now builds the task's commit in a private index, so nothing else in the clone can disturb it.
21
+ - `loom crew status` in a project with several crews said "which crew?" instead of listing them; it lists every crew unless you name one.
22
+ - **A follow-up to a teammate's task re-ran the original prompt.** When the orchestrator sent a follow-up ("also fix the test"), the teammate's machine got the task from scratch. It now gets the follow-up, on top of the first attempt's work, with the original task for context.
23
+
10
24
  ## [1.2.3] — 2026-10-22
11
25
 
12
26
  Teams that work together on their own: one goal splits across teammates' machines. Plus Simple mode, hub hardening, and the fourth field round.
package/README.md CHANGED
@@ -1560,6 +1560,16 @@ loom team # who's doing what, right now
1560
1560
  - **Worker commits carry `Loom-Goal`, `Loom-Task`, `Loom-Agent` and `Loom-Member`
1561
1561
  trailers.** `git log` alone tells you which goal, task and agent wrote a line.
1562
1562
 
1563
+ **Two people, one goal — the agents split it themselves.** When teammates turn
1564
+ on team auto-orchestration (`loom team auto on`, or **Turn on** in the Team tab),
1565
+ a goal you start splits across both machines. Your orchestrator gets their agents
1566
+ as `team:codex`, `team:opencode`…; a task sent to one is claimed by their Loom on
1567
+ its own, run with **their** agent and subscription, and merged back into your
1568
+ goal's branch — still one PR. A teammate who goes offline doesn't stall you: an
1569
+ unclaimed task returns to your orchestrator after 10 minutes. `loom team auto`
1570
+ says what's missing; `loom orchestrate "…" --solo` keeps a goal on your machine.
1571
+ See [docs/teams.md](docs/teams.md#two-people-one-goal-team-auto-orchestration).
1572
+
1563
1573
  **Phase 2 (stop colliding) is built too:**
1564
1574
  - **Declaring touches.** On a team project, every orchestra task declares the files
1565
1575
  it will `touch`, and Loom takes a lease on them.
package/dist/cli/index.js CHANGED
@@ -1894,12 +1894,17 @@ program
1894
1894
  console.log(pc.dim(`no crews here yet — loom crew create [${templates.join("|")}] [name]`));
1895
1895
  return;
1896
1896
  }
1897
+ // status shows every crew unless one is named; everything else needs to know which
1898
+ if (a === "status" && !opts.crew) {
1899
+ for (const c of crews)
1900
+ printCrew(c);
1901
+ return;
1902
+ }
1897
1903
  const crew = opts.crew ? crews.find((c) => c.id === opts.crew || c.name === opts.crew) : crews.length === 1 ? crews[0] : undefined;
1898
1904
  if (!crew)
1899
1905
  throw new Error(`which crew? --crew ${crews.map((c) => c.id).join(" | ")}`);
1900
1906
  if (a === "status") {
1901
- for (const c of opts.crew ? [crew] : crews)
1902
- printCrew(c);
1907
+ printCrew(crew);
1903
1908
  return;
1904
1909
  }
1905
1910
  if (a === "diff") {
@@ -1955,7 +1960,7 @@ function printCrew(c) {
1955
1960
  }
1956
1961
  program
1957
1962
  .command("team [action] [args...]")
1958
- .description("Loom Teams: status | signin [hub] | create <name> | invite | join <link> | share | unshare | brain [inbox|promote|resolve|correct|trust|private] | landing | doctor [fix] | adopt <pr> | deploys | release-notes <since> | webhook [--repo r] [--install] | remove <github> | leave")
1963
+ .description("Loom Teams: status | auto [on] | signin [hub] | create <name> | invite | join <link> | share | unshare | brain [inbox|promote|resolve|correct|trust|private] | landing | doctor [fix] | adopt <pr> | deploys | release-notes <since> | webhook [--repo r] [--install] | remove <github> | leave")
1959
1964
  .option("--github <login>", "your GitHub login (defaults to the gh CLI's)")
1960
1965
  .option("--repo <owner/name>", "webhook: which repo (defaults to this project's)")
1961
1966
  .option("--install", "webhook: create it on the repo with gh (needs repo admin)")
@@ -1971,6 +1976,24 @@ program
1971
1976
  try {
1972
1977
  if (a === "status")
1973
1978
  return void printTeam(await client.team());
1979
+ if (a === "auto") {
1980
+ // team auto-orchestration: your goals split across teammates' machines, theirs across yours
1981
+ const project = await currentProject(client);
1982
+ const st = await client.teamAuto(project.id, arg === "on");
1983
+ if (st.wrotePolicy)
1984
+ console.log(`${pc.green("✓")} wrote loom.team.json (runners.shared) — commit and merge it; policy is reviewed like code`);
1985
+ const mark = (ok) => (ok ? pc.green("✓") : pc.dim("·"));
1986
+ console.log(`${mark(st.shared)} project shared with your team`);
1987
+ console.log(`${mark(st.policyShared)} repo policy lets teammates' runners take its work`);
1988
+ console.log(`${mark(st.myRunner.running && st.myRunner.shared)} your runner is on and shared (teammates' goals can use your agents)`);
1989
+ const on = st.teammates.filter((t) => t.online);
1990
+ console.log(`${mark(on.length > 0)} teammates' runners online: ${on.length ? on.map((t) => `${t.github} (${t.kinds.join(", ")})`).join(", ") : "none yet"}`);
1991
+ if (st.ready)
1992
+ console.log(`\n${pc.green("ready")} — goals you start get ${st.workers.join(", ")} as workers. ${pc.dim("loom orchestrate \"…\" (--solo to keep one local)")}`);
1993
+ else
1994
+ console.log(`\n${pc.yellow("not yet")} — ${st.missing.join("; ")}`);
1995
+ return;
1996
+ }
1974
1997
  if (a === "signin") {
1975
1998
  const { hostedHubUrl, hostedSupabaseUrl, publishableKeyFor } = await import("../core/hosted.js");
1976
1999
  const supabaseUrl = hostedSupabaseUrl(arg);