@mmerterden/multi-agent-pipeline 20.36.0 → 20.37.1
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 +37 -0
- package/docs/facts.json +2 -2
- package/docs/features.md +1 -1
- package/docs/recovery-guide.md +1 -1
- package/install/catalog-history.json +1 -1
- package/manifest.json +225 -148
- package/package.json +1 -1
- package/pipeline/commands/multi-agent/SKILL.md +33 -154
- package/pipeline/commands/multi-agent/analysis/SKILL.md +14 -68
- package/pipeline/commands/multi-agent/analysis-jira/SKILL.md +5 -8
- package/pipeline/commands/multi-agent/autopilot-on/SKILL.md +38 -109
- package/pipeline/commands/multi-agent/channels/SKILL.md +38 -167
- package/pipeline/commands/multi-agent/complaint-analysis/SKILL.md +37 -144
- package/pipeline/commands/multi-agent/design-check/SKILL.md +27 -131
- package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +22 -48
- package/pipeline/commands/multi-agent/ios-coding-standard/SKILL.md +37 -180
- package/pipeline/commands/multi-agent/jira/SKILL.md +16 -46
- package/pipeline/commands/multi-agent/manual-test/SKILL.md +12 -7
- package/pipeline/commands/multi-agent/refactor/SKILL.md +23 -184
- package/pipeline/commands/multi-agent/resume/SKILL.md +30 -136
- package/pipeline/commands/multi-agent/review/SKILL.md +24 -199
- package/pipeline/commands/multi-agent/setup/SKILL.md +25 -181
- package/pipeline/commands/multi-agent/stack/SKILL.md +9 -53
- package/pipeline/commands/multi-agent/status/SKILL.md +13 -2
- package/pipeline/commands/multi-agent/store-ready/SKILL.md +27 -226
- package/pipeline/commands/multi-agent/sync/SKILL.md +35 -164
- package/pipeline/commands/multi-agent/test-gen/SKILL.md +2 -4
- package/pipeline/commands/multi-agent/update/SKILL.md +18 -60
- package/pipeline/contract/CHANGELOG.md +9 -0
- package/pipeline/contract/fixtures/error-invalid-request.json +1 -1
- package/pipeline/contract/fixtures/error-unauthorized.json +1 -1
- package/pipeline/contract/fixtures/error-unsigned.json +1 -1
- package/pipeline/contract/fixtures/runs-awaiting-question.json +1 -1
- package/pipeline/contract/fixtures/runs-empty.json +1 -1
- package/pipeline/contract/fixtures/runs-failed.json +1 -1
- package/pipeline/contract/fixtures/runs-pr-opened-redacted.json +1 -1
- package/pipeline/contract/fixtures/runs-pr-opened.json +1 -1
- package/pipeline/contract/fixtures/runs-running.json +1 -1
- package/pipeline/contract/manifest.json +5 -5
- package/pipeline/contract/types/index.d.ts +3 -2
- package/pipeline/multi-agent-refs/audit-guide.md +20 -0
- package/pipeline/multi-agent-refs/autopilot-on/details.md +148 -0
- package/pipeline/multi-agent-refs/channels/generator.md +14 -0
- package/pipeline/multi-agent-refs/channels/preview.md +13 -0
- package/pipeline/multi-agent-refs/channels/reference.md +46 -0
- package/pipeline/multi-agent-refs/complaint-analysis/phases.md +159 -0
- package/pipeline/multi-agent-refs/design-check/export.md +1 -0
- package/pipeline/multi-agent-refs/design-check/init-inventory.md +1 -1
- package/pipeline/multi-agent-refs/design-check/scope-and-ledger.md +64 -0
- package/pipeline/multi-agent-refs/features/analysis-command-notes.md +53 -0
- package/pipeline/multi-agent-refs/features/commit-multi-repo.md +63 -0
- package/pipeline/multi-agent-refs/features/dev-multi-repo.md +51 -0
- package/pipeline/multi-agent-refs/features/test-gap.md +40 -0
- package/pipeline/multi-agent-refs/features/worktree-finalize.md +1 -1
- package/pipeline/multi-agent-refs/garbage-collect/phases.md +60 -0
- package/pipeline/multi-agent-refs/ios-coding-standard/plan.md +71 -0
- package/pipeline/multi-agent-refs/ios-coding-standard/resolve-and-scan.md +135 -0
- package/pipeline/multi-agent-refs/jira/picker-detail.md +71 -0
- package/pipeline/multi-agent-refs/orchestrator/copilot-pipeline.md +88 -0
- package/pipeline/multi-agent-refs/orchestrator/dispatcher.md +96 -1
- package/pipeline/multi-agent-refs/orchestrator/phase-3-user-test.md +12 -9
- package/pipeline/multi-agent-refs/phases/phase-1-plan.md +4 -4
- package/pipeline/multi-agent-refs/phases/phase-2-dev.md +8 -47
- package/pipeline/multi-agent-refs/phases/phase-3-review.md +21 -65
- package/pipeline/multi-agent-refs/phases/phase-4-commit.md +9 -59
- package/pipeline/multi-agent-refs/phases/phase-5-report.md +0 -31
- package/pipeline/multi-agent-refs/refactor/sweep.md +190 -0
- package/pipeline/multi-agent-refs/resume/details.md +115 -2
- package/pipeline/multi-agent-refs/review/inputs.md +33 -1
- package/pipeline/multi-agent-refs/review/module-guides.md +9 -1
- package/pipeline/multi-agent-refs/review/panel.md +75 -0
- package/pipeline/multi-agent-refs/review/valven.md +5 -1
- package/pipeline/multi-agent-refs/rules.md +1 -1
- package/pipeline/multi-agent-refs/setup/hooks-and-plugins.md +4 -0
- package/pipeline/multi-agent-refs/setup/token-save-flow.md +13 -0
- package/pipeline/multi-agent-refs/stack/background.md +72 -0
- package/pipeline/multi-agent-refs/store-ready/gates.md +139 -0
- package/pipeline/multi-agent-refs/store-ready/report.md +40 -2
- package/pipeline/multi-agent-refs/sync/office.md +10 -0
- package/pipeline/multi-agent-refs/sync/overview.md +61 -0
- package/pipeline/multi-agent-refs/sync/repo.md +91 -0
- package/pipeline/multi-agent-refs/update/details.md +83 -0
- package/pipeline/office/index.html +6 -3
- package/pipeline/office/toolkit.json +1 -1
- package/pipeline/rules/figma-pipeline.md +6 -3
- package/pipeline/schemas/prefs.schema.json +1 -1
- package/pipeline/schemas/runs-index.schema.json +2 -1
- package/pipeline/scripts/_memory-policy.mjs +27 -5
- package/pipeline/scripts/checkpoint-fold.sh +59 -0
- package/pipeline/scripts/contract-server.mjs +1 -1
- package/pipeline/scripts/gate-ledger.mjs +1 -1
- package/pipeline/scripts/office-control.mjs +41 -15
- package/pipeline/scripts/offload-ref.sh +1 -1
- package/pipeline/scripts/rework-rulings.mjs +5 -3
- package/pipeline/scripts/runs-index.mjs +34 -7
- package/pipeline/scripts/scope-check-gate.mjs +15 -2
- package/pipeline/scripts/status-overview.mjs +401 -0
- package/pipeline/scripts/user-test-handoff.sh +203 -0
- package/pipeline/scripts/validate-planning.mjs +5 -3
- package/pipeline/scripts/validate-triage.mjs +2 -1
- package/pipeline/scripts/write-state.mjs +13 -4
- package/pipeline/skills/.skill-manifest.json +64 -64
- package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +7 -70
- package/pipeline/skills/shared/core/apple-archive-compliance/references/examples.md +67 -0
- package/pipeline/skills/shared/core/apple-archive-compliance/references/version-history.md +8 -0
- package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +10 -72
- package/pipeline/skills/shared/core/google-play-compliance/references/examples.md +69 -0
- package/pipeline/skills/shared/core/google-play-compliance/references/notes.md +7 -0
- package/pipeline/skills/shared/core/google-play-compliance/references/version-history.md +5 -0
- package/pipeline/skills/shared/core/multi-agent/SKILL.md +39 -262
- package/pipeline/skills/shared/core/multi-agent-autopilot-on/SKILL.md +35 -73
- package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +37 -337
- package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +27 -122
- package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +8 -340
- package/pipeline/skills/shared/core/multi-agent-ios-coding-standard/SKILL.md +37 -180
- package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +12 -7
- package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +23 -184
- package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +14 -82
- package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +25 -277
- package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +13 -2
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +73 -217
- package/pipeline/skills/shared/external/alarmkit/SKILL.md +11 -162
- package/pipeline/skills/shared/external/alarmkit/references/alarmkit-code.md +257 -0
- package/pipeline/skills/shared/external/android-architecture/SKILL.md +7 -58
- package/pipeline/skills/shared/external/android-architecture/references/code-examples.md +68 -0
- package/pipeline/skills/shared/external/app-intents/SKILL.md +3 -45
- package/pipeline/skills/shared/external/app-intents/references/code-examples.md +54 -0
- package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +5 -81
- package/pipeline/skills/shared/external/app-store-optimization/references/engagement-and-localization.md +96 -0
- package/pipeline/skills/shared/external/app-store-review/SKILL.md +6 -112
- package/pipeline/skills/shared/external/app-store-review/references/monetization-and-submission.md +138 -0
- package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +10 -117
- package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models-code.md +186 -0
- package/pipeline/skills/shared/external/authentication/SKILL.md +3 -50
- package/pipeline/skills/shared/external/authentication/references/code-examples.md +59 -0
- package/pipeline/skills/shared/external/callkit-voip/SKILL.md +3 -84
- package/pipeline/skills/shared/external/callkit-voip/references/code-examples.md +93 -0
- package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +7 -263
- package/pipeline/skills/shared/external/ci-cd-pipelines/references/pipeline-examples.md +281 -0
- package/pipeline/skills/shared/external/clean-code/SKILL.md +8 -41
- package/pipeline/skills/shared/external/clean-code/references/code-examples.md +56 -0
- package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +8 -146
- package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-code.md +214 -0
- package/pipeline/skills/shared/external/compose-components/SKILL.md +6 -80
- package/pipeline/skills/shared/external/compose-components/references/code-examples.md +89 -0
- package/pipeline/skills/shared/external/compose-navigation/SKILL.md +5 -64
- package/pipeline/skills/shared/external/compose-navigation/references/code-examples.md +70 -0
- package/pipeline/skills/shared/external/core-data/SKILL.md +9 -157
- package/pipeline/skills/shared/external/core-data/references/core-data-code.md +221 -0
- package/pipeline/skills/shared/external/core-nfc/SKILL.md +3 -89
- package/pipeline/skills/shared/external/core-nfc/references/code-examples.md +98 -0
- package/pipeline/skills/shared/external/coreml/SKILL.md +17 -133
- package/pipeline/skills/shared/external/coreml/references/coreml-code.md +208 -0
- package/pipeline/skills/shared/external/css-modern/SKILL.md +8 -131
- package/pipeline/skills/shared/external/css-modern/references/code-examples.md +142 -0
- package/pipeline/skills/shared/external/database-patterns/SKILL.md +6 -103
- package/pipeline/skills/shared/external/database-patterns/references/orm-examples.md +112 -0
- package/pipeline/skills/shared/external/html-semantic/SKILL.md +7 -48
- package/pipeline/skills/shared/external/html-semantic/references/code-examples.md +54 -0
- package/pipeline/skills/shared/external/humanizer/SKILL.md +6 -19
- package/pipeline/skills/shared/external/humanizer/references/voice.md +24 -0
- package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +13 -170
- package/pipeline/skills/shared/external/ios-accessibility/references/assistive-tech-review.md +224 -0
- package/pipeline/skills/shared/external/ios-localization/SKILL.md +2 -24
- package/pipeline/skills/shared/external/ios-localization/references/code-examples.md +30 -0
- package/pipeline/skills/shared/external/ios-networking/SKILL.md +3 -58
- package/pipeline/skills/shared/external/ios-networking/references/code-examples.md +67 -0
- package/pipeline/skills/shared/external/ios-security/SKILL.md +4 -64
- package/pipeline/skills/shared/external/ios-security/references/code-examples.md +74 -0
- package/pipeline/skills/shared/external/live-activities/SKILL.md +4 -90
- package/pipeline/skills/shared/external/live-activities/references/code-examples.md +108 -0
- package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +9 -23
- package/pipeline/skills/shared/external/localization-reuse-map/references/project-settings.md +22 -0
- package/pipeline/skills/shared/external/mapkit-location/SKILL.md +5 -95
- package/pipeline/skills/shared/external/mapkit-location/references/code-examples.md +117 -0
- package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +7 -106
- package/pipeline/skills/shared/external/nextjs-app-router/references/app-router-examples.md +124 -0
- package/pipeline/skills/shared/external/permissionkit/SKILL.md +2 -31
- package/pipeline/skills/shared/external/permissionkit/references/code-examples.md +37 -0
- package/pipeline/skills/shared/external/play-store-review/SKILL.md +6 -74
- package/pipeline/skills/shared/external/play-store-review/references/signing-and-policies.md +83 -0
- package/pipeline/skills/shared/external/push-notifications/SKILL.md +8 -125
- package/pipeline/skills/shared/external/push-notifications/references/notification-code.md +176 -0
- package/pipeline/skills/shared/external/python-patterns/SKILL.md +7 -158
- package/pipeline/skills/shared/external/python-patterns/references/python-examples.md +176 -0
- package/pipeline/skills/shared/external/rest-api-design/SKILL.md +7 -157
- package/pipeline/skills/shared/external/rest-api-design/references/api-examples.md +175 -0
- package/pipeline/skills/shared/external/swift-architecture/SKILL.md +11 -230
- package/pipeline/skills/shared/external/swift-architecture/references/pattern-examples.md +295 -0
- package/pipeline/skills/shared/external/swift-codable/SKILL.md +17 -149
- package/pipeline/skills/shared/external/swift-codable/references/codable-recipes.md +207 -0
- package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +12 -99
- package/pipeline/skills/shared/external/swift-concurrency/references/code-examples.md +100 -0
- package/pipeline/skills/shared/external/swift-concurrency/references/swift-6-2-additions.md +18 -0
- package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +9 -78
- package/pipeline/skills/shared/external/swift-formatstyle/references/formatstyle-examples.md +113 -0
- package/pipeline/skills/shared/external/swift-language/SKILL.md +3 -56
- package/pipeline/skills/shared/external/swift-language/references/code-examples.md +65 -0
- package/pipeline/skills/shared/external/swift-testing-pro/SKILL.md +1 -0
- package/pipeline/skills/shared/external/swiftdata/SKILL.md +6 -122
- package/pipeline/skills/shared/external/swiftdata/references/code-examples.md +140 -0
- package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +12 -139
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/interop-code.md +198 -0
- package/pipeline/skills/shared/external/tailwind-css/SKILL.md +9 -81
- package/pipeline/skills/shared/external/tailwind-css/references/code-examples.md +91 -0
- package/pipeline/skills/shared/external/testing-backend/SKILL.md +7 -207
- package/pipeline/skills/shared/external/testing-backend/references/testing-examples.md +225 -0
- package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +8 -89
- package/pipeline/skills/shared/external/typescript-patterns/references/code-examples.md +100 -0
- package/pipeline/skills/shared/external/vision-framework/SKILL.md +2 -20
- package/pipeline/skills/shared/external/vision-framework/references/code-examples.md +26 -0
- package/pipeline/skills/shared/external/vue-composition/SKILL.md +7 -169
- package/pipeline/skills/shared/external/vue-composition/references/vue-examples.md +187 -0
- package/pipeline/skills/shared/external/web-accessibility/SKILL.md +7 -174
- package/pipeline/skills/shared/external/web-accessibility/references/a11y-examples.md +192 -0
- package/pipeline/skills/shared/external/web-performance/SKILL.md +8 -66
- package/pipeline/skills/shared/external/web-performance/references/code-examples.md +77 -0
- package/pipeline/skills/shared/external/web-testing/SKILL.md +11 -186
- package/pipeline/skills/shared/external/web-testing/references/testing-examples.md +213 -0
- /package/pipeline/skills/shared/external/localization-reuse-map/{reference → references}/format-and-output.md +0 -0
- /package/pipeline/skills/shared/external/localization-reuse-map/{reference → references}/publish-and-snapshot.md +0 -0
- /package/pipeline/skills/shared/external/localization-reuse-map/{reference → references}/sources-and-recipes.md +0 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# user-test-handoff.sh - hand a task branch from its worktree to the main
|
|
4
|
+
# repository for a manual test, and hand it back.
|
|
5
|
+
#
|
|
6
|
+
# A branch can be checked out in one place only, so testing in the main repo
|
|
7
|
+
# means removing the worktree first. That removal is where work gets lost: an
|
|
8
|
+
# uncommitted change, a submodule's local branches and stashes (its git dir
|
|
9
|
+
# lives inside the worktree's admin dir), and every ignored file (the run
|
|
10
|
+
# artefacts under `.pipeline/` and `.multi-agent/`, logs, `.env`, build
|
|
11
|
+
# output) live only in the worktree. This script refuses what it cannot carry
|
|
12
|
+
# and carries the rest.
|
|
13
|
+
#
|
|
14
|
+
# It never commits. The caller makes the WIP commit itself first, so the
|
|
15
|
+
# commit passes through the same approval and secret-scan hooks as any other.
|
|
16
|
+
#
|
|
17
|
+
# checkout check that the worktree and its submodules hold no uncommitted
|
|
18
|
+
# or unpushed work, move every ignored entry and the main repo's
|
|
19
|
+
# current branch into a hold under the git common dir, remove the
|
|
20
|
+
# worktree, check the branch out in the main repo.
|
|
21
|
+
# restore put the main repo back on the branch it was on, re-add the
|
|
22
|
+
# worktree on the task branch, move the held entries back. Safe to
|
|
23
|
+
# run again after an interrupted checkout or restore.
|
|
24
|
+
#
|
|
25
|
+
# The hold sits in the same repository as the worktree, so moving even a large
|
|
26
|
+
# ignored tree is a rename. Success is judged by where the branch ends up, not
|
|
27
|
+
# by git's exit code: a failing post-checkout hook (git LFS, core.hooksPath)
|
|
28
|
+
# makes `git checkout` and `git worktree add` exit non-zero after they did
|
|
29
|
+
# their work. The hold is deleted only once every entry is back.
|
|
30
|
+
#
|
|
31
|
+
# Usage:
|
|
32
|
+
# user-test-handoff.sh checkout|restore --task <id> --worktree <path>
|
|
33
|
+
# --root <main repo> --branch <task branch>
|
|
34
|
+
#
|
|
35
|
+
# Prints one JSON line on success. Exit codes:
|
|
36
|
+
# 0 done
|
|
37
|
+
# 1 usage error, or the worktree is not on the task branch
|
|
38
|
+
# 3 the main repo has uncommitted changes to tracked files; nothing moved
|
|
39
|
+
# 5 the worktree or a submodule has uncommitted, unpushed or stashed work;
|
|
40
|
+
# nothing moved
|
|
41
|
+
# 6 checkout: a handoff is already held (run restore), or git refused and
|
|
42
|
+
# everything was put back (restore then answers 7). restore: the main repo
|
|
43
|
+
# could not leave the branch, or the worktree could not be re-added; the
|
|
44
|
+
# hold is kept and the message names the cause
|
|
45
|
+
# 7 restore found nothing held for this task
|
|
46
|
+
set -uo pipefail
|
|
47
|
+
|
|
48
|
+
usage() {
|
|
49
|
+
echo "usage: user-test-handoff.sh checkout|restore --task <id> --worktree <path> --root <repo> --branch <name>" >&2
|
|
50
|
+
exit 1
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
MODE="${1:-}"
|
|
54
|
+
[ $# -gt 0 ] && shift
|
|
55
|
+
TASK="" WT="" ROOT="" BRANCH=""
|
|
56
|
+
while [ $# -gt 0 ]; do
|
|
57
|
+
[ $# -ge 2 ] || usage
|
|
58
|
+
case "$1" in
|
|
59
|
+
--task) TASK="$2" ;;
|
|
60
|
+
--worktree) WT="$2" ;;
|
|
61
|
+
--root) ROOT="$2" ;;
|
|
62
|
+
--branch) BRANCH="$2" ;;
|
|
63
|
+
*) echo "user-test-handoff: unknown argument $1" >&2; usage ;;
|
|
64
|
+
esac
|
|
65
|
+
shift 2
|
|
66
|
+
done
|
|
67
|
+
case "$MODE" in checkout | restore) ;; *) usage ;; esac
|
|
68
|
+
[ -n "$TASK" ] && [ -n "$WT" ] && [ -n "$ROOT" ] && [ -n "$BRANCH" ] || usage
|
|
69
|
+
case "$TASK" in */* | *..* | .* | *'"'* | *\\*) echo "user-test-handoff: task id must be a plain name" >&2; exit 1 ;; esac
|
|
70
|
+
|
|
71
|
+
ROOT="$(cd "$ROOT" 2>/dev/null && pwd)" || { echo "user-test-handoff: --root is not a directory" >&2; exit 1; }
|
|
72
|
+
case "$WT" in /*) ;; *) WT="$ROOT/$WT" ;; esac
|
|
73
|
+
COMMON="$(git -C "$ROOT" rev-parse --path-format=absolute --git-common-dir 2>/dev/null)" ||
|
|
74
|
+
{ echo "user-test-handoff: --root is not a git repository" >&2; exit 1; }
|
|
75
|
+
HOLD="$COMMON/multi-agent-user-test/$TASK"
|
|
76
|
+
|
|
77
|
+
esc() { printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'; }
|
|
78
|
+
json() { printf '{"status":"%s","task":"%s","branch":"%s","previous":"%s"}\n' "$1" "$(esc "$TASK")" "$(esc "$BRANCH")" "$(esc "$2")"; }
|
|
79
|
+
|
|
80
|
+
on_branch() { [ "$(git -C "$1" branch --show-current 2>/dev/null)" = "$2" ]; }
|
|
81
|
+
|
|
82
|
+
root_dirty() { [ -n "$(git -C "$ROOT" status --porcelain --untracked-files=no 2>/dev/null)" ]; }
|
|
83
|
+
|
|
84
|
+
# Every ignored entry of the worktree, directories collapsed, NUL-separated.
|
|
85
|
+
ignored_entries() { git -C "$WT" ls-files --others --ignored --exclude-standard --directory -z 2>/dev/null; }
|
|
86
|
+
|
|
87
|
+
# Move the listed entries (NUL-separated file $3) from tree $1 to tree $2.
|
|
88
|
+
move_entries() {
|
|
89
|
+
local from="$1" to="$2" list="$3" e rc=0
|
|
90
|
+
while IFS= read -r -d '' e; do
|
|
91
|
+
e="${e%/}"
|
|
92
|
+
[ -n "$e" ] && [ -e "$from/$e" ] || continue
|
|
93
|
+
mkdir -p "$to/$(dirname "$e")" && rm -rf "${to:?}/$e" && mv "$from/$e" "$to/$e" || rc=1
|
|
94
|
+
done <"$list"
|
|
95
|
+
return "$rc"
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return_entries() {
|
|
99
|
+
[ -f "$HOLD/entries" ] || : >"$HOLD/entries"
|
|
100
|
+
if move_entries "$HOLD/tree" "$WT" "$HOLD/entries"; then
|
|
101
|
+
rm -rf "$HOLD"
|
|
102
|
+
else
|
|
103
|
+
echo "user-test-handoff: some held entries are still under $HOLD/tree" >&2
|
|
104
|
+
fi
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
submodule_problems() {
|
|
108
|
+
# shellcheck disable=SC2016 # submodule foreach expands $displaypath itself
|
|
109
|
+
git -C "$WT" submodule foreach --quiet --recursive '
|
|
110
|
+
if [ -n "$(git status --porcelain)" ]; then echo "$displaypath (uncommitted changes)"
|
|
111
|
+
elif ! git branch -r --contains HEAD 2>/dev/null | grep -q .; then echo "$displaypath (HEAD on no remote branch; push it, or add a remote if there is none)"
|
|
112
|
+
elif [ -n "$(git rev-list -n1 --branches --not --remotes 2>/dev/null)" ]; then echo "$displaypath (a local branch has unpushed commits)"
|
|
113
|
+
elif [ -n "$(git stash list 2>/dev/null)" ]; then echo "$displaypath (has stashes)"
|
|
114
|
+
fi' 2>/dev/null
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
checkout() {
|
|
118
|
+
on_branch "$WT" "$BRANCH" || { echo "user-test-handoff: $WT is not a worktree on $BRANCH" >&2; exit 1; }
|
|
119
|
+
if [ -e "$HOLD" ]; then
|
|
120
|
+
echo "user-test-handoff: a handoff for $TASK is already held; run restore first" >&2
|
|
121
|
+
exit 6
|
|
122
|
+
fi
|
|
123
|
+
if root_dirty; then
|
|
124
|
+
echo "user-test-handoff: the main repo has uncommitted changes; commit or stash them, then retry" >&2
|
|
125
|
+
git -C "$ROOT" status --short --untracked-files=no >&2
|
|
126
|
+
exit 3
|
|
127
|
+
fi
|
|
128
|
+
local problems
|
|
129
|
+
problems="$(submodule_problems)"
|
|
130
|
+
if [ -n "$problems" ]; then
|
|
131
|
+
printf 'user-test-handoff: these submodules hold work the removal would lose:\n%s\n' "$problems" >&2
|
|
132
|
+
exit 5
|
|
133
|
+
fi
|
|
134
|
+
if [ -n "$(git -C "$WT" status --porcelain)" ]; then
|
|
135
|
+
echo "user-test-handoff: the worktree has uncommitted changes; make the WIP commit first" >&2
|
|
136
|
+
git -C "$WT" status --short >&2
|
|
137
|
+
exit 5
|
|
138
|
+
fi
|
|
139
|
+
local previous
|
|
140
|
+
previous="$(git -C "$ROOT" symbolic-ref --short -q HEAD || git -C "$ROOT" rev-parse HEAD)"
|
|
141
|
+
mkdir -p "$HOLD/tree" || exit 6
|
|
142
|
+
printf '%s\n' "$previous" >"$HOLD/previous" || exit 6
|
|
143
|
+
ignored_entries >"$HOLD/entries" || exit 6
|
|
144
|
+
if ! move_entries "$WT" "$HOLD/tree" "$HOLD/entries"; then
|
|
145
|
+
return_entries
|
|
146
|
+
exit 6
|
|
147
|
+
fi
|
|
148
|
+
if ! git -C "$ROOT" worktree remove --force "$WT"; then
|
|
149
|
+
return_entries
|
|
150
|
+
exit 6
|
|
151
|
+
fi
|
|
152
|
+
git -C "$ROOT" checkout -q "$BRANCH" || true
|
|
153
|
+
if ! on_branch "$ROOT" "$BRANCH"; then
|
|
154
|
+
git -C "$ROOT" worktree add -q "$WT" "$BRANCH" || true
|
|
155
|
+
on_branch "$WT" "$BRANCH" && return_entries
|
|
156
|
+
echo "user-test-handoff: the main repo could not check out $BRANCH" >&2
|
|
157
|
+
exit 6
|
|
158
|
+
fi
|
|
159
|
+
json checked-out "$previous"
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
restore() {
|
|
163
|
+
[ -f "$HOLD/previous" ] || { echo "user-test-handoff: nothing is held for $TASK" >&2; exit 7; }
|
|
164
|
+
local previous
|
|
165
|
+
previous="$(cat "$HOLD/previous")"
|
|
166
|
+
if on_branch "$ROOT" "$BRANCH"; then
|
|
167
|
+
if root_dirty; then
|
|
168
|
+
echo "user-test-handoff: the main repo has uncommitted changes on $BRANCH; stash them (git stash), restore, then git stash pop in the worktree" >&2
|
|
169
|
+
git -C "$ROOT" status --short --untracked-files=no >&2
|
|
170
|
+
exit 3
|
|
171
|
+
fi
|
|
172
|
+
if [ -n "$previous" ] && [ "$previous" != "$BRANCH" ]; then
|
|
173
|
+
git -C "$ROOT" checkout -q "$previous" || true
|
|
174
|
+
else
|
|
175
|
+
git -C "$ROOT" checkout -q --detach || true
|
|
176
|
+
fi
|
|
177
|
+
if on_branch "$ROOT" "$BRANCH"; then
|
|
178
|
+
echo "user-test-handoff: the main repo could not leave $BRANCH for $previous (an untracked file in the way?); move it and run restore again" >&2
|
|
179
|
+
exit 6
|
|
180
|
+
fi
|
|
181
|
+
fi
|
|
182
|
+
if ! on_branch "$WT" "$BRANCH"; then
|
|
183
|
+
git -C "$ROOT" worktree unlock "$WT" 2>/dev/null || true
|
|
184
|
+
git -C "$ROOT" worktree prune
|
|
185
|
+
if [ -e "$WT" ]; then
|
|
186
|
+
if ! { mkdir -p "$HOLD/leftover" && mv "$WT" "$HOLD/leftover/$(date +%s)"; }; then
|
|
187
|
+
echo "user-test-handoff: $WT exists and is not a worktree; move it and run restore again" >&2
|
|
188
|
+
exit 6
|
|
189
|
+
fi
|
|
190
|
+
fi
|
|
191
|
+
git -C "$ROOT" worktree add -q "$WT" "$BRANCH" || true
|
|
192
|
+
on_branch "$WT" "$BRANCH" || { echo "user-test-handoff: the worktree could not be re-added on $BRANCH" >&2; exit 6; }
|
|
193
|
+
fi
|
|
194
|
+
if [ -d "$HOLD/leftover" ]; then
|
|
195
|
+
mkdir -p "$COMMON/multi-agent-user-test-leftover" &&
|
|
196
|
+
mv "$HOLD/leftover" "$COMMON/multi-agent-user-test-leftover/$TASK-$(date +%s)" &&
|
|
197
|
+
echo "user-test-handoff: files found at the worktree path were kept under $COMMON/multi-agent-user-test-leftover" >&2
|
|
198
|
+
fi
|
|
199
|
+
return_entries
|
|
200
|
+
json restored "$previous"
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
"$MODE"
|
|
@@ -12,8 +12,10 @@
|
|
|
12
12
|
// cat plan.json | node validate-planning.mjs - [--spec <path>]
|
|
13
13
|
//
|
|
14
14
|
// --spec names the analysis document or task text the plan was written from.
|
|
15
|
-
// A
|
|
16
|
-
//
|
|
15
|
+
// A named spec that cannot be read is an error, because the design checks
|
|
16
|
+
// below would otherwise be skipped without a trace. A plan more than
|
|
17
|
+
// SPEC_RATIO times its length gets a warning: a plan should record decisions,
|
|
18
|
+
// and one far longer than its spec is usually a transcript.
|
|
17
19
|
//
|
|
18
20
|
// Exit codes:
|
|
19
21
|
// 0 - valid
|
|
@@ -326,7 +328,7 @@ async function main() {
|
|
|
326
328
|
specText = readFileSync(spec, "utf-8");
|
|
327
329
|
specChars = specText.length;
|
|
328
330
|
} catch {
|
|
329
|
-
|
|
331
|
+
errors.push(`spec not readable: ${spec}`);
|
|
330
332
|
}
|
|
331
333
|
// With a design behind the plan, values come from its tokens, never from a
|
|
332
334
|
// number someone read off a screenshot.
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
// 0 - valid, safe to act on
|
|
28
28
|
// 1 - invalid structure or required-field violation - caller MUST retry or fallback
|
|
29
29
|
// 2 - over-rejection guard tripped - caller MUST pause for human (or log+accept in autopilot)
|
|
30
|
+
// (takes precedence over 3; `corrected` is still set when a contradiction was fixed)
|
|
30
31
|
// 3 - contradiction auto-corrected - caller MAY proceed with corrected output
|
|
31
32
|
//
|
|
32
33
|
// Output: JSON result to stdout with shape:
|
|
@@ -427,7 +428,7 @@ function validate(raw) {
|
|
|
427
428
|
warnings.push(
|
|
428
429
|
`over-rejection guard: ${parsed.rejected.length}/${total} rejected (${(ratio * 100).toFixed(0)}%) - caller must pause for human confirm (triage=high-rejection-rate); autopilot may accept and log`,
|
|
429
430
|
);
|
|
430
|
-
triageCode =
|
|
431
|
+
triageCode = 2;
|
|
431
432
|
}
|
|
432
433
|
}
|
|
433
434
|
|
|
@@ -390,7 +390,8 @@ export function completionRefusal(next, payload, replace, diskStatus) {
|
|
|
390
390
|
* background launches approve nothing by design, and in analysis mode
|
|
391
391
|
* Phase 1 is not a plan, so neither is asked.
|
|
392
392
|
* - A `sessionId` already set is the run's identity for resume; a write that
|
|
393
|
-
* changes it detaches the run from the session that started it.
|
|
393
|
+
* changes it detaches the run from the session that started it. A replace
|
|
394
|
+
* document is the whole record, so leaving the field out also changes it.
|
|
394
395
|
* - Phase 2 to a later phase in an attended run with a tracked issue (jiraId
|
|
395
396
|
* or githubIssue) needs `phases["2"].trackerStatus` verified, declined or
|
|
396
397
|
* not-tracked: the issue moves to In Progress before any code, and a failed
|
|
@@ -399,15 +400,16 @@ export function completionRefusal(next, payload, replace, diskStatus) {
|
|
|
399
400
|
* @param {object} next the document as it would be written
|
|
400
401
|
* @param {unknown} payload the patch as sent
|
|
401
402
|
* @param {object} current the document on disk
|
|
403
|
+
* @param {{replace?: boolean}} [opts]
|
|
402
404
|
* @returns {string|null}
|
|
403
405
|
*/
|
|
404
|
-
export function transitionRefusal(next, payload, current) {
|
|
406
|
+
export function transitionRefusal(next, payload, current, { replace = false } = {}) {
|
|
405
407
|
const patch = payload && typeof payload === "object" ? payload : {};
|
|
406
408
|
const was = current && typeof current === "object" ? current : {};
|
|
407
409
|
if (
|
|
408
410
|
typeof was.sessionId === "string" &&
|
|
409
411
|
was.sessionId &&
|
|
410
|
-
Object.hasOwn(patch, "sessionId") &&
|
|
412
|
+
(replace || Object.hasOwn(patch, "sessionId")) &&
|
|
411
413
|
next.sessionId !== was.sessionId
|
|
412
414
|
) {
|
|
413
415
|
return `write-state: refusing to change sessionId from "${was.sessionId}". It identifies the run for resume; nothing was written.`;
|
|
@@ -531,6 +533,13 @@ async function main() {
|
|
|
531
533
|
let current = {};
|
|
532
534
|
if (replace) {
|
|
533
535
|
next = payload;
|
|
536
|
+
if (existsSync(path)) {
|
|
537
|
+
try {
|
|
538
|
+
current = JSON.parse(readFileSync(path, "utf-8"));
|
|
539
|
+
} catch {
|
|
540
|
+
current = {};
|
|
541
|
+
}
|
|
542
|
+
}
|
|
534
543
|
} else {
|
|
535
544
|
if (existsSync(path)) {
|
|
536
545
|
try {
|
|
@@ -597,7 +606,7 @@ async function main() {
|
|
|
597
606
|
|
|
598
607
|
const refusal =
|
|
599
608
|
completionRefusal(next, payload, replace, diskStatus) ||
|
|
600
|
-
transitionRefusal(next, payload, current);
|
|
609
|
+
transitionRefusal(next, payload, current, { replace });
|
|
601
610
|
if (refusal) {
|
|
602
611
|
console.error(refusal);
|
|
603
612
|
releaseLock(path);
|