forge-orkes 0.72.2 → 0.74.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.
- package/bin/create-forge.js +6 -4
- package/experimental/m10/source/mcp-server/README.md +2 -2
- package/experimental/m10/source/mcp-server/index.js +2 -2
- package/experimental/m10/source/skills/orchestrating/SKILL.md +7 -3
- package/package.json +1 -1
- package/template/.claude/hooks/forge-reserve.sh +367 -166
- package/template/.claude/hooks/tests/forge-reserve.test.sh +169 -0
- package/template/.claude/skills/chief-of-staff/SKILL.md +1 -0
- package/template/.claude/skills/forge/SKILL.md +8 -6
- package/template/.claude/skills/jarvis/SKILL.md +39 -4
- package/template/.forge/FORGE.md +4 -4
- package/template/.forge/checks/forge-check-lint.sh +12 -3
- package/template/.forge/checks/forge-hold-check.sh +2 -0
- package/template/.forge/checks/forge-jarvis-awareness.sh +62 -11
- package/template/.forge/checks/forge-jarvis-dispatch.sh +25 -1
- package/template/.forge/checks/forge-jarvis-prwatch.sh +8 -5
- package/template/.forge/checks/forge-jarvis-relay.sh +15 -6
- package/template/.forge/checks/tests/forge-jarvis-awareness.test.sh +53 -0
- package/template/.forge/checks/tests/forge-jarvis-dispatch.test.sh +50 -0
- package/template/.forge/checks/tests/forge-jarvis-relay.test.sh +30 -0
- package/template/.forge/templates/project.yml +6 -0
- package/template/.forge/templates/state/desire-path.yml +15 -45
|
@@ -114,5 +114,58 @@ else
|
|
|
114
114
|
bad 'unknown flag refused loudly (exit 2)' "rc=$RC out=$OUT"
|
|
115
115
|
fi
|
|
116
116
|
|
|
117
|
+
# --- 9-12. BARE BRANCH LOOSENING (issue #25): a worktree glob against REAL git worktrees on
|
|
118
|
+
# bare m-<id>-slug / m<digits>-slug branches (no forge/ prefix) — FORGE_JARVIS_REPO_ROOT
|
|
119
|
+
# points the git-worktree glob at a throwaway fixture repo instead of --worktree-root's
|
|
120
|
+
# root-scan (which bypasses branch matching entirely). ------------------------------------
|
|
121
|
+
GITROOT="$ROOT/git-fixture"; mkdir -p "$GITROOT/main"
|
|
122
|
+
(
|
|
123
|
+
cd "$GITROOT/main" || exit 1
|
|
124
|
+
git init -q .
|
|
125
|
+
git config user.email t@t.com; git config user.name test
|
|
126
|
+
mkdir -p .forge/state
|
|
127
|
+
printf 'id: 176\n' > .forge/state/milestone-176.yml
|
|
128
|
+
printf 'id: 167\n' > .forge/state/milestone-167.yml
|
|
129
|
+
printf 'id: R61-002\n' > .forge/state/milestone-R61-002.yml
|
|
130
|
+
git add .forge >/dev/null 2>&1 || : > .gitkeep
|
|
131
|
+
git add -A; git commit -q -m init
|
|
132
|
+
git worktree add -q -b m-176-marcy-mcp "$GITROOT/bare-1" >/dev/null 2>&1
|
|
133
|
+
git worktree add -q -b m167-close-sync "$GITROOT/bare-2" >/dev/null 2>&1
|
|
134
|
+
git worktree add -q -b m-R61-002-cleanup "$GITROOT/bare-3" >/dev/null 2>&1
|
|
135
|
+
git worktree add -q -b fix-issue-2 "$GITROOT/guard-1" >/dev/null 2>&1
|
|
136
|
+
) >/dev/null 2>&1
|
|
137
|
+
|
|
138
|
+
OUT="$(FORGE_JARVIS_REPO_ROOT="$GITROOT/main" FORGE_JARVIS_FOLD="$FOLDSTUB" FORGE_JARVIS_BOARD="$BOARDSTUB" \
|
|
139
|
+
sh "$AWARE" --dry-run 2>&1)"
|
|
140
|
+
|
|
141
|
+
# 9. bare branch m-176-marcy-mcp discovered with milestone id m-176 (previously silently absent)
|
|
142
|
+
if printf '%s' "$OUT" | grep -qE 'm-176[[:space:]]+m-176-marcy-mcp'; then
|
|
143
|
+
ok 'bare branch m-176-marcy-mcp is discovered as milestone id m-176'
|
|
144
|
+
else
|
|
145
|
+
bad 'bare branch m-176-marcy-mcp is discovered as milestone id m-176' "$OUT"
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
# 10. bare branch m167-close-sync (no hyphen after m) discovered with milestone id m-167
|
|
149
|
+
if printf '%s' "$OUT" | grep -qE 'm-167[[:space:]]+m167-close-sync'; then
|
|
150
|
+
ok 'bare branch m167-close-sync is discovered as milestone id m-167'
|
|
151
|
+
else
|
|
152
|
+
bad 'bare branch m167-close-sync is discovered as milestone id m-167' "$OUT"
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
# 11. hyphenated id: m-R61-002-cleanup resolves via the longest-matching state-file prefix,
|
|
156
|
+
# not the naive first-hyphen-segment (which would wrongly stop at m-R61)
|
|
157
|
+
if printf '%s' "$OUT" | grep -qE 'm-R61-002[[:space:]]+m-R61-002-cleanup'; then
|
|
158
|
+
ok 'hyphenated milestone id: m-R61-002-cleanup resolves to m-R61-002 (longest state-file prefix)'
|
|
159
|
+
else
|
|
160
|
+
bad 'hyphenated milestone id: m-R61-002-cleanup resolves to m-R61-002 (longest state-file prefix)' "$OUT"
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
# 12. GUARD: a bare-number branch (fix-issue-2, no m- token) is NEVER discovered
|
|
164
|
+
if ! printf '%s' "$OUT" | grep -q 'fix-issue-2'; then
|
|
165
|
+
ok 'guard: bare-number branch fix-issue-2 (no m- token) is not discovered'
|
|
166
|
+
else
|
|
167
|
+
bad 'guard: bare-number branch fix-issue-2 (no m- token) is not discovered' "$OUT"
|
|
168
|
+
fi
|
|
169
|
+
|
|
117
170
|
printf '\nforge-jarvis-awareness.test.sh: %s passed, %s failed\n' "$PASSED" "$FAILED"
|
|
118
171
|
[ "$FAILED" -eq 0 ]
|
|
@@ -403,6 +403,56 @@ if [ "$rc" = 0 ] && printf '%s' "$err24" | grep -q 'using it as-is'; then
|
|
|
403
403
|
else
|
|
404
404
|
bad "legacy materialized order" "rc=$rc err=$err24"
|
|
405
405
|
fi
|
|
406
|
+
|
|
407
|
+
# --- 25-27. BARE BRANCH LOOSENING (issue #25): the branch-derived milestone-dir pick also
|
|
408
|
+
# matches a bare m-<id>-slug / m<digits>-slug branch (no forge/ prefix) — same match family
|
|
409
|
+
# as awareness/relay. A bare slug can carry several descriptive words, so the pick walks
|
|
410
|
+
# truncations of the last hyphen-segment until an existing milestone dir is found.
|
|
411
|
+
|
|
412
|
+
# 25. bare branch m-176-marcy-mcp (hyphenated id + 2-word slug) picks milestone-176 among
|
|
413
|
+
# several dirs
|
|
414
|
+
BSLICE="$ROOT/bare-wt"
|
|
415
|
+
mkdir -p "$BSLICE/.forge/phases/milestone-176/1-num" "$BSLICE/.forge/phases/milestone-5/1-decoy"
|
|
416
|
+
printf 'bare plan\n' > "$BSLICE/.forge/phases/milestone-176/1-num/plan-01.md"
|
|
417
|
+
printf 'decoy\n' > "$BSLICE/.forge/phases/milestone-5/1-decoy/plan-01.md"
|
|
418
|
+
mkbranch "$BSLICE" m-176-marcy-mcp
|
|
419
|
+
err25="$(sh "$DISPATCH" --slice "$BSLICE" --materialize-only 2>&1)"; rc=$?
|
|
420
|
+
if [ "$rc" = 0 ] && grep -q '^ - 1-num$' "$BSLICE/slice.yml" 2>/dev/null \
|
|
421
|
+
&& grep -q 'bare plan' "$BSLICE/phases/1-num/plan.md" 2>/dev/null && [ ! -d "$BSLICE/phases/1-decoy" ]; then
|
|
422
|
+
ok "bare branch m-176-marcy-mcp: branch picks milestone-176 among several dirs (no forge/ prefix)"
|
|
423
|
+
else
|
|
424
|
+
bad "bare-branch pick (hyphenated id)" "rc=$rc err=$err25"
|
|
425
|
+
fi
|
|
426
|
+
|
|
427
|
+
# 26. bare branch m167-close-sync (no hyphen after m, 2-word slug) picks milestone-167
|
|
428
|
+
CSLICE="$ROOT/bare-wt2"
|
|
429
|
+
mkdir -p "$CSLICE/.forge/phases/milestone-167/1-num" "$CSLICE/.forge/phases/milestone-9/1-decoy"
|
|
430
|
+
printf 'bare plan\n' > "$CSLICE/.forge/phases/milestone-167/1-num/plan-01.md"
|
|
431
|
+
printf 'decoy\n' > "$CSLICE/.forge/phases/milestone-9/1-decoy/plan-01.md"
|
|
432
|
+
mkbranch "$CSLICE" m167-close-sync
|
|
433
|
+
err26="$(sh "$DISPATCH" --slice "$CSLICE" --materialize-only 2>&1)"; rc=$?
|
|
434
|
+
if [ "$rc" = 0 ] && grep -q '^ - 1-num$' "$CSLICE/slice.yml" 2>/dev/null \
|
|
435
|
+
&& grep -q 'bare plan' "$CSLICE/phases/1-num/plan.md" 2>/dev/null && [ ! -d "$CSLICE/phases/1-decoy" ]; then
|
|
436
|
+
ok "bare branch m167-close-sync: branch picks milestone-167 among several dirs (m immediately followed by digits)"
|
|
437
|
+
else
|
|
438
|
+
bad "bare-branch pick (numeric, no hyphen)" "rc=$rc err=$err26"
|
|
439
|
+
fi
|
|
440
|
+
|
|
441
|
+
# 27. GUARD: a bare-number branch (fix-issue-2, no m- token) does NOT resolve — several
|
|
442
|
+
# milestone dirs with no branch-derived pick still refuses as ambiguous
|
|
443
|
+
NSLICE="$ROOT/guard-wt"
|
|
444
|
+
mkdir -p "$NSLICE/.forge/phases/milestone-1/1-a" "$NSLICE/.forge/phases/milestone-2/1-b"
|
|
445
|
+
printf 'a\n' > "$NSLICE/.forge/phases/milestone-1/1-a/plan-01.md"
|
|
446
|
+
printf 'b\n' > "$NSLICE/.forge/phases/milestone-2/1-b/plan-01.md"
|
|
447
|
+
mkbranch "$NSLICE" fix-issue-2
|
|
448
|
+
err27="$(sh "$DISPATCH" --slice "$NSLICE" --materialize-only 2>&1)"; rc=$?
|
|
449
|
+
if [ "$rc" != 0 ] && [ ! -f "$NSLICE/slice.yml" ] && printf '%s' "$err27" | grep -q 'REFUSED' \
|
|
450
|
+
&& printf '%s' "$err27" | grep -q 'no forge/m-\* or bare m-<id> branch'; then
|
|
451
|
+
ok "guard: bare-number branch fix-issue-2 (no m- token) refuses ambiguous pick, names both accepted forms"
|
|
452
|
+
else
|
|
453
|
+
bad "guard: bare-number branch fix-issue-2" "rc=$rc err=$err27"
|
|
454
|
+
fi
|
|
455
|
+
|
|
406
456
|
# --- summary -----------------------------------------------------------------
|
|
407
457
|
printf '\n%s: %d passed, %d failed\n' "$(basename "$0")" "$PASSED" "$FAILED"
|
|
408
458
|
[ "$FAILED" = 0 ]
|
|
@@ -130,6 +130,36 @@ case "$out" in
|
|
|
130
130
|
*) bad "catchup summary" "no while-you-were-away line: $out" ;;
|
|
131
131
|
esac
|
|
132
132
|
|
|
133
|
+
# --- 14-15. BARE BRANCH LOOSENING (issue #25): --list-logs glob against REAL git worktrees on
|
|
134
|
+
# bare m-<id>-slug branches (no forge/ prefix) — --list-logs only needs the notify-log
|
|
135
|
+
# PATH, no id derivation, so this pins the match extension alone (FORGE_JARVIS_REPO_ROOT
|
|
136
|
+
# points the glob at a throwaway fixture repo). --------------------------------------------
|
|
137
|
+
GITROOT="$ROOT/git-fixture"; mkdir -p "$GITROOT/main"
|
|
138
|
+
(
|
|
139
|
+
cd "$GITROOT/main" || exit 1
|
|
140
|
+
git init -q .
|
|
141
|
+
git config user.email t@t.com; git config user.name test
|
|
142
|
+
: > .gitkeep; git add .gitkeep; git commit -q -m init
|
|
143
|
+
git worktree add -q -b m-176-marcy-mcp "$GITROOT/bare-1" >/dev/null 2>&1
|
|
144
|
+
git worktree add -q -b fix-issue-2 "$GITROOT/guard-1" >/dev/null 2>&1
|
|
145
|
+
) >/dev/null 2>&1
|
|
146
|
+
|
|
147
|
+
out="$(FORGE_JARVIS_REPO_ROOT="$GITROOT/main" sh "$RELAY" --list-logs 2>/dev/null)"
|
|
148
|
+
|
|
149
|
+
# 14. bare branch m-176-marcy-mcp emits its notify-log path (pings reach the phone)
|
|
150
|
+
if printf '%s' "$out" | grep -q "$GITROOT/bare-1/.forge/runner-work/notify.log"; then
|
|
151
|
+
ok "bare branch m-176-marcy-mcp: --list-logs emits its notify-log path"
|
|
152
|
+
else
|
|
153
|
+
bad "bare branch --list-logs path" "$out"
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
# 15. GUARD: a bare-number branch (fix-issue-2, no m- token) emits NO log path
|
|
157
|
+
if ! printf '%s' "$out" | grep -q 'guard-1'; then
|
|
158
|
+
ok "guard: bare-number branch fix-issue-2 (no m- token) emits no log path"
|
|
159
|
+
else
|
|
160
|
+
bad "guard: bare-number branch fix-issue-2 (no m- token) emits no log path" "$out"
|
|
161
|
+
fi
|
|
162
|
+
|
|
133
163
|
# --- summary -----------------------------------------------------------------
|
|
134
164
|
printf '\n%s: %d passed, %d failed\n' "$(basename "$0")" "$PASSED" "$FAILED"
|
|
135
165
|
[ "$FAILED" = 0 ]
|
|
@@ -154,6 +154,12 @@ models:
|
|
|
154
154
|
# # no flag (platform default). TRUST WARNING: bypassPermissions means
|
|
155
155
|
# # phone-spawned sessions act without prompts — opt in only where the
|
|
156
156
|
# # phone lane carries the same trust as an attended terminal.
|
|
157
|
+
# dev_lane_cmd: "" # OPTIONAL. Shell command Jarvis runs (in the slice worktree) to spin up
|
|
158
|
+
# # the LOCAL dev server for the operator's UAT after a `done` ping — the
|
|
159
|
+
# # UAT-gated dispatch seam (m-48). Stack-specific: Forge owns no dev-server
|
|
160
|
+
# # concept, so the project supplies the "how" (e.g. its `dev:all` lane).
|
|
161
|
+
# # Absent → Jarvis tells the operator to start the lane manually (no failure).
|
|
162
|
+
# # The PR opens only AFTER the operator's explicit in-session UAT — never here.
|
|
157
163
|
|
|
158
164
|
# attribution: # OPT-IN Driven-by attribution (hold-waiver patch) — default OFF.
|
|
159
165
|
# driven_by: true # When true, the merge-floor check-quality lint
|
|
@@ -1,46 +1,16 @@
|
|
|
1
|
-
# Forge Desire-Path Observation —
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
# that is what used to make state/index.yml conflict across worktrees.
|
|
6
|
-
#
|
|
7
|
-
# Filename: state/desire-paths/{YYYY-MM-DD}-{type}-{milestone}-{slug}.yml
|
|
8
|
-
# e.g. state/desire-paths/2026-06-10-recurring_friction-m7-uncommitted-state.yml
|
|
9
|
-
# The date+type+milestone+slug make the name unique, so concurrent agents in
|
|
10
|
-
# different worktrees only ever ADD files — git never has to merge content.
|
|
11
|
-
#
|
|
12
|
-
# Occurrence counts are DERIVED: the `forge` skill globs this directory and
|
|
13
|
-
# groups by (type + normalized note). A pattern appearing in 3+ files is a
|
|
14
|
-
# candidate for framework evolution, surfaced at `forge` boot — the single
|
|
15
|
-
# review owner (see ADR-012).
|
|
16
|
-
#
|
|
17
|
-
# SCOPE decides where a 3+ pattern's fix lands:
|
|
18
|
-
# project = fix targets user-owned files (constitution.md, design-system.md,
|
|
19
|
-
# context.md). Stays in-project.
|
|
20
|
-
# framework = fix targets Forge's own skills/templates. Eligible for UPSTREAM
|
|
21
|
-
# transport — forge review writes a portable block to
|
|
22
|
-
# state/desire-paths/upstream/ and (when gh + forge.upstream_repo
|
|
23
|
-
# are available) offers a GH issue against the Forge repo.
|
|
24
|
-
# Lazy migration: a file with no `scope` is read as `project`.
|
|
1
|
+
# Forge Desire-Path Observation — one file per observation
|
|
2
|
+
# Copy to .forge/state/desire-paths/{YYYY-MM-DD}-{type}-{milestone}-{slug}.yml
|
|
3
|
+
# Append-only: never edit an existing observation file; recurrence is derived
|
|
4
|
+
# by globbing (type + normalized note), not a counter. See FORGE.md § state/desire-paths/.
|
|
25
5
|
|
|
26
|
-
type: ""
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
note: "" # one-line description — the grouping key for occurrence counts
|
|
38
|
-
|
|
39
|
-
# Optional type-specific detail (fill what applies to `type`):
|
|
40
|
-
detail:
|
|
41
|
-
detected: "" # tier_override: what Forge detected
|
|
42
|
-
overridden_to: "" # tier_override: what the user chose
|
|
43
|
-
rule: null # deviation_pattern: 1 | 2 | 3
|
|
44
|
-
correction: "" # user_correction: the repeated correction
|
|
45
|
-
failure_pattern: "" # agent_struggle: how the task fails
|
|
46
|
-
step: "" # skipped_step: the step skipped
|
|
6
|
+
type: "" # recurring_friction | agent_struggle | user_correction (etc. — free-form, grouped by exact string)
|
|
7
|
+
date: "" # ISO 8601 date the observation was made, e.g. "2026-07-23"
|
|
8
|
+
milestone: "" # milestone id, or a short label for non-milestone work (e.g. "quick-task (...)")
|
|
9
|
+
scope: project # project | framework — absent ⇒ project (this repo only; framework ⇒ upstream-eligible per ADR-012)
|
|
10
|
+
suggestion_target: "" # the file/skill this observation would change if acted on
|
|
11
|
+
note: >
|
|
12
|
+
What was observed — concrete enough that a future review can judge recurrence
|
|
13
|
+
(same type + normalized note) without re-reading the original session.
|
|
14
|
+
suggestion: >
|
|
15
|
+
What to do about it, if a fix is proposed. Omit this key when the observation
|
|
16
|
+
has no concrete suggestion yet.
|