muse-crew 0.7.20 → 0.8.0

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.
@@ -6,13 +6,18 @@
6
6
  # worktree strategy lives — workflows and agents never run raw git worktree
7
7
  # commands; they call these lifecycle commands instead.
8
8
  #
9
- # The crew's registry ($REPO/.worktrees/.registry/<task_id>) is the source
10
- # of truth for task→branch/path. Never reconstruct the mapping from git
11
- # state alone.
9
+ # The crew's registry ($REPO/.worktrees/.registry/<task_id>) is the first
10
+ # source of truth for task→branch/path. When the registry is empty (a
11
+ # Build agent created the branch with raw git from an abbreviated id,
12
+ # bypassing prepare — task 4e1a1bba, 2026-09-17), resolve_branch() falls
13
+ # back to enumerating refs: the canonical task/<full-id> ref wins, then a
14
+ # task/<id-prefix> ref is tolerated (matched by strict prefix, never
15
+ # created). Canonical stays task/<full-id>; ambiguous prefixes fail closed.
12
16
  #
13
17
  # Commands:
14
18
  # validate <task_id> — check task ID is safe for branches/paths
15
19
  # prepare <task_id> — create worktree + branch, register ownership
20
+ # resolve-branch <task_id> — print the resolved task branch name
16
21
  # inspect <task_id> — diff against main for review
17
22
  # integrate <task_id> <commit_msg> — merge lock → merge into main → report commit
18
23
  # verify-merge <task_id> — confirm the task branch tip is an ancestor of main (post-step merge check)
@@ -63,15 +68,47 @@ MERGE_RECORDS_DIR="$CREW_HOME/.merge-records"
63
68
 
64
69
  # --- helpers ---
65
70
 
66
- # Task branch name: task/<id>. The registry wins when the task was
67
- # prepared before.
71
+ # Task branch name. Resolution order (task 4e1a1bba, 2026-09-17):
72
+ # 1. the registry — prepare writes the branch it created;
73
+ # 2. the canonical task/<full-id> ref, when it exists;
74
+ # 3. a task/<id-prefix> ref, matched by strict literal prefix over
75
+ # refs/heads/task/ — tolerated, never created. Build and Integrate
76
+ # therefore agree on the branch name even when Build bypassed
77
+ # prepare with an abbreviated id.
78
+ # When nothing matches, the canonical name is returned anyway so callers
79
+ # keep their "branch X does not exist" failure (and verify-merge's merge-
80
+ # record fallback) instead of failing on an empty name. Ambiguous prefixes
81
+ # fail closed (exit 1).
68
82
  resolve_branch() {
69
83
  local task_id="$1" b
70
84
  if [ -f "$REGISTRY_DIR/$task_id" ]; then
71
85
  b=$(grep '^branch=' "$REGISTRY_DIR/$task_id" | cut -d= -f2-)
72
86
  if [ -n "$b" ]; then printf '%s' "$b"; return 0; fi
73
87
  fi
74
- printf 'task/%s' "$task_id"
88
+ local canonical="task/$task_id"
89
+ if git -C "$REPO" rev-parse --verify "$canonical" >/dev/null 2>&1; then
90
+ printf '%s' "$canonical"; return 0
91
+ fi
92
+ local matches=() ref stripped
93
+ while IFS= read -r ref; do
94
+ [ -n "$ref" ] || continue
95
+ [ "$ref" = "$canonical" ] && continue
96
+ # Strict literal prefix: ref must be a proper prefix of the canonical
97
+ # name. The quoted expansion keeps the pattern literal (task ids are
98
+ # [a-zA-Z0-9_-], but literal is literal).
99
+ stripped="${canonical#"$ref"}"
100
+ if [ "$stripped" != "$canonical" ]; then
101
+ matches+=("$ref")
102
+ fi
103
+ done < <(git -C "$REPO" for-each-ref --format='%(refname:short)' 'refs/heads/task/')
104
+ if [ "${#matches[@]}" -eq 1 ]; then
105
+ printf '%s' "${matches[0]}"; return 0
106
+ fi
107
+ if [ "${#matches[@]}" -gt 1 ]; then
108
+ echo "ERROR: task id '$task_id' matches multiple task branches: ${matches[*]} — ambiguous, refusing to guess" >&2
109
+ return 1
110
+ fi
111
+ printf '%s' "$canonical"
75
112
  }
76
113
 
77
114
  # Worktree path: $REPO/.worktrees/<id>. The registry wins when the task
@@ -168,6 +205,17 @@ cmd_prepare() {
168
205
  echo "BASE: $base_commit"
169
206
  }
170
207
 
208
+ # Agent-side one-liner: $(worktree-lifecycle.sh resolve-branch <id>) prints
209
+ # the branch Build and Integrate must agree on. Mechanical — no agent call
210
+ # per phase needed (task 4e1a1bba). Exits 1 on an ambiguous prefix.
211
+ cmd_resolve_branch() {
212
+ local task_id="$1"
213
+ validate_task_id "$task_id"
214
+ local branch
215
+ branch=$(resolve_branch "$task_id")
216
+ echo "$branch"
217
+ }
218
+
171
219
  cmd_inspect() {
172
220
  local task_id="$1"
173
221
  validate_task_id "$task_id"
@@ -373,7 +421,12 @@ cmd_post_deploy() {
373
421
  final_commit=$(git rev-parse HEAD)
374
422
 
375
423
  # Cleanup worktree + branch — report honestly: a failed removal must
376
- # never print success (a lying "removed" hid real leftovers).
424
+ # never print success (a lying "removed" hid real leftovers). The branch
425
+ # is resolved, never reconstructed: a Build agent may have created it
426
+ # from an abbreviated id (task 4e1a1bba) and deleting "task/<full-id>"
427
+ # would leave the real branch behind.
428
+ local branch
429
+ branch=$(resolve_branch "$task_id")
377
430
  if [ -d "$WORKTREE_DIR/$task_id" ]; then
378
431
  if git worktree remove "$WORKTREE_DIR/$task_id" 2>/dev/null; then
379
432
  echo "WORKTREE: removed"
@@ -382,7 +435,7 @@ cmd_post_deploy() {
382
435
  fi
383
436
  fi
384
437
  git worktree prune 2>/dev/null
385
- git branch -d "task/$task_id" 2>/dev/null && echo "BRANCH: deleted" || true
438
+ git branch -d "$branch" 2>/dev/null && echo "BRANCH: deleted" || true
386
439
  unregister "$task_id"
387
440
 
388
441
  # Release merge lock
@@ -480,7 +533,11 @@ cmd_cleanup() {
480
533
  echo "WORKTREE: not found (already clean)"
481
534
  fi
482
535
  git worktree prune 2>/dev/null
483
- git branch -D "task/$task_id" 2>/dev/null && echo "BRANCH: deleted" || true
536
+ # Resolve, never reconstruct: the branch may live under an abbreviated
537
+ # id (task 4e1a1bba).
538
+ local branch
539
+ branch=$(resolve_branch "$task_id")
540
+ git branch -D "$branch" 2>/dev/null && echo "BRANCH: deleted" || true
484
541
  unregister "$task_id"
485
542
  echo "CLEANUP: done"
486
543
  }
@@ -569,6 +626,7 @@ shift || true
569
626
  case "$cmd" in
570
627
  validate) cmd_validate "${1:?task_id required}" ;;
571
628
  prepare) cmd_prepare "${1:?task_id required}" ;;
629
+ resolve-branch) cmd_resolve_branch "${1:?task_id required}" ;;
572
630
  inspect) cmd_inspect "${1:?task_id required}" ;;
573
631
  integrate) cmd_integrate "${1:?task_id required}" "${2:-}" ;;
574
632
  verify-merge) cmd_verify_merge "${1:?task_id required}" ;;
@@ -581,7 +639,7 @@ case "$cmd" in
581
639
  merge-record) cmd_merge_record "${1:?task_id required}" ;;
582
640
  *)
583
641
  echo "Usage: worktree-lifecycle.sh <command> [args]"
584
- echo "Commands: validate, prepare, inspect, integrate, verify-merge, post-deploy, terminal-cleanup, cleanup, status, refresh-lock, lock-status, merge-record"
642
+ echo "Commands: validate, prepare, resolve-branch, inspect, integrate, verify-merge, post-deploy, terminal-cleanup, cleanup, status, refresh-lock, lock-status, merge-record"
585
643
  exit 1
586
644
  ;;
587
645
  esac
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "muse-crew",
3
- "version": "0.7.20",
3
+ "version": "0.8.0",
4
4
  "description": "Opinionated orchestration for Muse — workflows, identities, and tooling for autonomous software development.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
package/seed/AGENTS.md CHANGED
@@ -4,6 +4,7 @@ Init source data. Everything `crew-init.js` reads when setting up a new crew ins
4
4
 
5
5
  - `crons.json` — the declarative cron manifest; crew-init creates/updates each entry idempotently; `enabled` is a creation-time default only
6
6
  - `cron-body-template.md` — template for creating the dispatch cron job
7
+ - `cron-body-update-watch.md` — template for the daily `crew-update-watch` cron job: runs `lib/update-watch.js --crew-home {crewHome}` verbatim and reports stdout
7
8
  - `posture.md` — PM posture that shapes the user's assistant for crew interaction
8
9
  - `feedback/` — feedback feature placeholder
9
10
  - `workflows/` — human-readable workflow definitions, copied to `$CREW_HOME/.orchestration/workflows/` during init
@@ -0,0 +1,13 @@
1
+ ## Muse Crew update watch
2
+
3
+ You are the update watcher. Run the deterministic check and report its output.
4
+
5
+ ### Steps
6
+
7
+ 1. Run verbatim:
8
+ node {crewHome}/current/lib/update-watch.js --crew-home {crewHome}
9
+ The script exits 0 on every path. Check failures are logged to
10
+ {crewHome}/update-watch.log and reported on stdout — never thrown.
11
+ 2. Report the script's stdout verbatim. Do not summarize, do not judge, do
12
+ not file tasks yourself — the watcher files through the Crew API when
13
+ policy and idempotency allow.
package/seed/crons.json CHANGED
@@ -5,13 +5,26 @@
5
5
  "enabled": true,
6
6
  "id": "crew-poll",
7
7
  "mode": "task",
8
- "owner": "space:{dashboardSlug}",
8
+ "owner": "cli:{instanceId}",
9
9
  "schedule": {
10
10
  "every": "15m",
11
11
  "kind": "interval"
12
12
  },
13
13
  "timeout_secs": 5400,
14
14
  "title": "Muse Crew polling loop"
15
+ },
16
+ {
17
+ "body_template": "cron-body-update-watch.md",
18
+ "enabled": true,
19
+ "id": "crew-update-watch",
20
+ "mode": "task",
21
+ "owner": "cli:{instanceId}",
22
+ "schedule": {
23
+ "every": "24h",
24
+ "kind": "interval"
25
+ },
26
+ "timeout_secs": 600,
27
+ "title": "Muse Crew automatic update watcher"
15
28
  }
16
29
  ],
17
30
  "version": 1
@@ -0,0 +1,21 @@
1
+ # Upgrade
2
+
3
+ Upgrade the crew itself through its own dispatch loop. The task description carries a `source:` line naming the upgrade source — `repo` (default, the task project's repo HEAD) or `npm@<x.y.z>` (the published npm package). The stable `crew-release.sh` deploys, the workflow verifies mechanically, and handover to the new release is automatic on the next tick.
4
+
5
+ ## Steps
6
+
7
+ ### Triage
8
+ **Identity:** Sage
9
+ Validate the `source:` line (exactly `repo`, or `npm@<x.y.z>` — anything else parks fail-closed), verify the repo checkout and resolve `git rev-parse HEAD` for repo source, read the live release via `crew-release.sh current`, and compute the target. If the crew is already on the target, record the idempotent no-op and skip Deploy.
10
+
11
+ ### Deploy
12
+ **Identity:** Wren
13
+ Run the stable `$CREW_HOME/crew-release.sh deploy` — against the repo HEAD for repo source, or against a staging dir under `$CREW_HOME/.upgrade-staging/<version>` (public npm install only) for npm source. Single command, no merge lock. Any non-zero exit parks fail-closed with the exact output; no retry, no auto-rollback — `crew-release.sh rollback` is the human recovery path.
14
+
15
+ ### Verify
16
+ **Identity:** Wren
17
+ Mechanical, no LLM judgment: (1) `crew-release.sh current` equals the target; (2) `<crewHome>/workflows/registry.json` parses as JSON — and for repo source carries the `upgrade` key (npm releases predating the upgrade workflow are still valid upgrades); (3) `crew-api get-state` works via the pinned old-release CLI. Handover is automatic: the next poll tick launches the dispatcher through the `current` symlink, i.e. the new release. In-flight runs finish on the old release via per-task lib pinning.
18
+
19
+ ## Safety
20
+
21
+ Never mutate the crew repo — repo source always means the repo's current HEAD. Never publish to npm — the npm source only installs the published package. Never touch the scheduler. Fail closed everywhere.
@@ -5,7 +5,7 @@ Executable Muse workflow scripts (JavaScript). These are what the workflow runti
5
5
  - `crew-dispatch.js` — reads the board, recommends eligible tasks, returns structured launch records (the launched workflow self-claims; the dispatcher never writes claims). Skips tasks on quiesced projects and on projects with no repo_path configured.
6
6
 
7
7
  All four workflow scripts share byte-identical transport helpers (`workRetryKey`, `buildTransportRetryTrailer`, `describeWorkAgentFailure`, `workerMissingArtifactTools` — pinned by `tests/closeout.test.js`). The transport-retry loop treats a worker report naming the missing artifact tool namespace (bug 3472bf36, a per-launch platform flake) as a retryable attempt with a fresh launch rather than accepting a useless report.
8
- - `crew-init.js` — sets up a new crew instance: Gate 0 validates crewHome is workspace-contained and a valid git repo, and (in dashboard mode) validates dashboardRepoPath is workspace-contained and an existing git repo (never auto-created); bootstraps the release system; scaffolds orchestration folders; registers the first project with repo_path set to the validated dashboard repo — skipped in CLI-only mode (no dashboardSlug/dashboardRepoPath), where projects are created later via crew-api.js; creates/converges cron jobs from the declarative manifest (owner `space:<slug>` in dashboard mode, `cli:<crew-home-basename>` in CLI-only mode). Idempotent. The crew owns its state via the Crew API (lib/crew-api.js); the dashboard is an optional client and is never a dependency.
8
+ - `crew-init.js` — sets up a new crew instance: Gate 0 validates crewHome is workspace-contained and a valid git repo, and (in dashboard mode) validates dashboardRepoPath is workspace-contained and an existing git repo (never auto-created); bootstraps the release system; scaffolds orchestration folders; registers the first project with repo_path set to the validated dashboard repo — skipped in CLI-only mode (no dashboardSlug/dashboardRepoPath), where projects are created later via crew-api.js; creates/converges cron jobs from the declarative manifest (scheduler identity is dashboard-independent: first init uses the crew-home basename, re-runs keep the instanceId recorded in `.cron-registry.json`; owner `cli:<instanceId>` — deleting a dashboard artifact never stops the crew). Idempotent. The crew owns its state via the Crew API (lib/crew-api.js); the dashboard is an optional client and is never a dependency.
9
9
  - `standard.js` — default task workflow: Triage → Capture → Map → Build → Review → Integrate → Publish → QA
10
10
  - `bugfix.js` — adds Capture after Triage, then Reproduce
11
11
  - `chore.js` — adds Capture after Triage, drops QA (low-risk)