llm-wb 0.1.0-beta.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/.agentic/00.chat/README.md +78 -0
- package/.agentic/00.chat/checklists/before-commit.md +195 -0
- package/.agentic/00.chat/checklists/llm-workbench-public-beta.md +94 -0
- package/.agentic/00.chat/commands/README.md +108 -0
- package/.agentic/00.chat/migration-plan.md +132 -0
- package/.agentic/00.chat/skills/session-summary.md +48 -0
- package/.agentic/00.chat/standards/llm-workbench-public-beta-contract.md +216 -0
- package/.agentic/00.chat/standards/main-refresh-conflict-types.md +358 -0
- package/.agentic/00.chat/workflows/README.md +40 -0
- package/.agentic/00.chat/workflows/bootstrap-chat-workbench-repo.md +212 -0
- package/.agentic/00.chat/workflows/chat-cleanup.md +102 -0
- package/.agentic/00.chat/workflows/chat-commit.md +56 -0
- package/.agentic/00.chat/workflows/chat-promote-to-main.md +169 -0
- package/.agentic/00.chat/workflows/chat-refresh-from-main.md +242 -0
- package/.agentic/00.chat/workflows/chat-reporting.md +69 -0
- package/.agentic/00.chat/workflows/chat-start.md +173 -0
- package/.agentic/00.chat/workflows/chat-upstream-reusable-lesson.md +123 -0
- package/.agentic/shared/standards/README.md +32 -0
- package/.agentic/shared/standards/upstream-repo-bootstrap.md +131 -0
- package/.agentic/shared/workflows/README.md +35 -0
- package/.agentic/shared/workflows/capability-resolution-workflow.md +189 -0
- package/.agentic/shared/workflows/change-shared-process.md +92 -0
- package/.cursor/rules/llm-workbench.mdc +17 -0
- package/.github/copilot-instructions.md +16 -0
- package/AGENTS.md +63 -0
- package/CLAUDE.md +16 -0
- package/CONTRIBUTING.md +57 -0
- package/LICENSE +21 -0
- package/LLM_WORKBENCH.md +17 -0
- package/README.md +98 -0
- package/SECURITY.md +44 -0
- package/bin/llm-workbench.js +672 -0
- package/docs/00.chat/README.md +47 -0
- package/docs/00.chat/llm-workbench-acceptance-matrix.md +55 -0
- package/docs/00.chat/script-layout.md +107 -0
- package/docs/adapting-to-your-repo.md +29 -0
- package/docs/concepts.md +38 -0
- package/docs/install.md +114 -0
- package/docs/public-beta-contract.md +45 -0
- package/docs/workflows.md +103 -0
- package/examples/minimal-repo/README.md +13 -0
- package/package.json +93 -0
- package/scripts/00.chat/README.md +46 -0
- package/scripts/00.chat/bootstrap/README.md +35 -0
- package/scripts/00.chat/bootstrap/audit-chat-bootstrap-file-set/README.md +39 -0
- package/scripts/00.chat/bootstrap/audit-chat-bootstrap-file-set/script.sh +213 -0
- package/scripts/00.chat/closeout/README.md +30 -0
- package/scripts/00.chat/closeout/build-closeout-prompt/README.md +35 -0
- package/scripts/00.chat/closeout/build-closeout-prompt/script.sh +124 -0
- package/scripts/00.chat/command/README.md +31 -0
- package/scripts/00.chat/command/close/README.md +30 -0
- package/scripts/00.chat/command/close/script.sh +25 -0
- package/scripts/00.chat/command/dispatcher/README.md +46 -0
- package/scripts/00.chat/command/dispatcher/script.sh +91 -0
- package/scripts/00.chat/command/dispatcher/smoke-test.sh +168 -0
- package/scripts/00.chat/command/new/README.md +32 -0
- package/scripts/00.chat/command/new/script.sh +28 -0
- package/scripts/00.chat/command/open-window/README.md +38 -0
- package/scripts/00.chat/command/open-window/script.sh +25 -0
- package/scripts/00.chat/command/package-scripts/README.md +34 -0
- package/scripts/00.chat/command/package-scripts/smoke-test.sh +113 -0
- package/scripts/00.chat/git/README.md +30 -0
- package/scripts/00.chat/git/cleanup-empty-chat-branches/README.md +36 -0
- package/scripts/00.chat/git/cleanup-empty-chat-branches/script.sh +243 -0
- package/scripts/00.chat/git/cleanup-empty-chat-branches/smoke-test.sh +136 -0
- package/scripts/00.chat/local-merge/README.md +30 -0
- package/scripts/00.chat/local-merge/list-active-chat-branches/README.md +29 -0
- package/scripts/00.chat/local-merge/list-active-chat-branches/script.sh +109 -0
- package/scripts/00.chat/local-merge/report-chat-branch-overlaps/README.md +29 -0
- package/scripts/00.chat/local-merge/report-chat-branch-overlaps/script.sh +142 -0
- package/scripts/00.chat/local-merge/verify-chat-ready-to-merge-local-main/README.md +33 -0
- package/scripts/00.chat/local-merge/verify-chat-ready-to-merge-local-main/script.sh +345 -0
- package/scripts/00.chat/local-merge/verify-chat-ready-to-merge-local-main/smoke-test.sh +244 -0
- package/scripts/00.chat/main-refresh/README.md +39 -0
- package/scripts/00.chat/main-refresh/apply-rehearsed-refresh/README.md +32 -0
- package/scripts/00.chat/main-refresh/apply-rehearsed-refresh/script.sh +198 -0
- package/scripts/00.chat/main-refresh/check-chat-is-current-with-main/README.md +30 -0
- package/scripts/00.chat/main-refresh/check-chat-is-current-with-main/script.sh +121 -0
- package/scripts/00.chat/main-refresh/classify-conflict/README.md +39 -0
- package/scripts/00.chat/main-refresh/classify-conflict/script.sh +169 -0
- package/scripts/00.chat/main-refresh/classify-conflict/smoke-test.sh +137 -0
- package/scripts/00.chat/main-refresh/classify-refresh-readiness/README.md +35 -0
- package/scripts/00.chat/main-refresh/classify-refresh-readiness/script.sh +171 -0
- package/scripts/00.chat/main-refresh/classify-refresh-readiness/smoke-test.sh +132 -0
- package/scripts/00.chat/main-refresh/rehearse-refresh-from-main/README.md +34 -0
- package/scripts/00.chat/main-refresh/rehearse-refresh-from-main/script.sh +124 -0
- package/scripts/00.chat/main-refresh/rehearse-refresh-from-main/smoke-test.sh +257 -0
- package/scripts/00.chat/main-refresh/show-main-update-status/README.md +31 -0
- package/scripts/00.chat/main-refresh/show-main-update-status/script.sh +73 -0
- package/scripts/00.chat/main-refresh/verify-conflict-audit/README.md +37 -0
- package/scripts/00.chat/main-refresh/verify-conflict-audit/script.sh +154 -0
- package/scripts/00.chat/main-refresh/verify-conflict-audit/smoke-test.sh +99 -0
- package/scripts/00.chat/metrics/README.md +35 -0
- package/scripts/00.chat/metrics/data/chat-pricing.json +107 -0
- package/scripts/00.chat/metrics/data/chat-pricing.schema.json +63 -0
- package/scripts/00.chat/metrics/estimate-chat-cost/README.md +40 -0
- package/scripts/00.chat/metrics/estimate-chat-cost/script.js +130 -0
- package/scripts/00.chat/migration/README.md +30 -0
- package/scripts/00.chat/migration/audit-chat-layer-migration/README.md +33 -0
- package/scripts/00.chat/migration/audit-chat-layer-migration/script.sh +127 -0
- package/scripts/00.chat/recovery/README.md +30 -0
- package/scripts/00.chat/recovery/import-active-paths-to-chat-worktree/README.md +76 -0
- package/scripts/00.chat/recovery/import-active-paths-to-chat-worktree/script.sh +212 -0
- package/scripts/00.chat/recovery/import-active-paths-to-chat-worktree/smoke-test.sh +162 -0
- package/scripts/00.chat/reporting/README.md +30 -0
- package/scripts/00.chat/reporting/generate-commit-log-summary/README.md +35 -0
- package/scripts/00.chat/reporting/generate-commit-log-summary/script.sh +299 -0
- package/scripts/00.chat/reporting/generate-commit-log-summary/smoke-test.sh +93 -0
- package/scripts/00.chat/reporting/report-chat-workspaces/README.md +32 -0
- package/scripts/00.chat/reporting/report-chat-workspaces/script.sh +82 -0
- package/scripts/00.chat/session-log/README.md +33 -0
- package/scripts/00.chat/session-log/check-commit-prerequisites/README.md +89 -0
- package/scripts/00.chat/session-log/check-commit-prerequisites/script.sh +121 -0
- package/scripts/00.chat/session-log/check-commit-prerequisites/smoke-test.sh +119 -0
- package/scripts/00.chat/session-log/check-commitlog-deletions/README.md +90 -0
- package/scripts/00.chat/session-log/check-commitlog-deletions/script.sh +131 -0
- package/scripts/00.chat/session-log/check-commitlog-deletions/smoke-test.sh +123 -0
- package/scripts/00.chat/session-log/checkpoint-chat-session-log/README.md +98 -0
- package/scripts/00.chat/session-log/checkpoint-chat-session-log/script.sh +126 -0
- package/scripts/00.chat/session-log/paths/README.md +38 -0
- package/scripts/00.chat/session-log/paths/lib.sh +133 -0
- package/scripts/00.chat/session-log/prepare-chat-session-before-commit/README.md +90 -0
- package/scripts/00.chat/session-log/prepare-chat-session-before-commit/script.sh +145 -0
- package/scripts/00.chat/session-log/read-current-chat-log/README.md +44 -0
- package/scripts/00.chat/session-log/read-current-chat-log/script.sh +92 -0
- package/scripts/00.chat/session-log/read-current-chat-log/smoke-test.sh +127 -0
- package/scripts/00.chat/session-log/record-chat-commit/README.md +133 -0
- package/scripts/00.chat/session-log/record-chat-commit/script.sh +394 -0
- package/scripts/00.chat/session-log/record-chat-commit/smoke-test.sh +227 -0
- package/scripts/00.chat/session-log/record-main-refresh-conflict/README.md +34 -0
- package/scripts/00.chat/session-log/record-main-refresh-conflict/script.sh +239 -0
- package/scripts/00.chat/session-log/rename-current-chat-log-folder/README.md +32 -0
- package/scripts/00.chat/session-log/rename-current-chat-log-folder/script.sh +112 -0
- package/scripts/00.chat/session-log/update-chat-log/README.md +32 -0
- package/scripts/00.chat/session-log/update-chat-log/script.sh +294 -0
- package/scripts/00.chat/startup/README.md +37 -0
- package/scripts/00.chat/startup/auto-start-missing-session/README.md +113 -0
- package/scripts/00.chat/startup/auto-start-missing-session/script.sh +54 -0
- package/scripts/00.chat/startup/resolve-current-chat-session/README.md +57 -0
- package/scripts/00.chat/startup/resolve-current-chat-session/script.sh +47 -0
- package/scripts/00.chat/startup/resolve-current-chat-session/smoke-test.sh +130 -0
- package/scripts/00.chat/startup/start-chat-session/README.md +197 -0
- package/scripts/00.chat/startup/start-chat-session/script.sh +330 -0
- package/scripts/00.chat/startup/start-chat-session/smoke-test.sh +182 -0
- package/scripts/00.chat/startup/start-new-chat/README.md +31 -0
- package/scripts/00.chat/startup/start-new-chat/script.sh +29 -0
- package/scripts/00.chat/transcript/README.md +36 -0
- package/scripts/00.chat/transcript/discover-codex-session-log/README.md +32 -0
- package/scripts/00.chat/transcript/discover-codex-session-log/script.sh +106 -0
- package/scripts/00.chat/transcript/register-codex-session-log/README.md +32 -0
- package/scripts/00.chat/transcript/register-codex-session-log/script.sh +115 -0
- package/scripts/00.chat/worktree/README.md +32 -0
- package/scripts/00.chat/worktree/check-write-location/README.md +87 -0
- package/scripts/00.chat/worktree/check-write-location/script.sh +95 -0
- package/scripts/00.chat/worktree/dirty-worktree-check/README.md +77 -0
- package/scripts/00.chat/worktree/dirty-worktree-check/script.sh +93 -0
- package/scripts/00.chat/worktree/ensure-chat-worktree/README.md +33 -0
- package/scripts/00.chat/worktree/ensure-chat-worktree/script.sh +132 -0
- package/scripts/00.chat/worktree/open-window/README.md +34 -0
- package/scripts/00.chat/worktree/open-window/script.sh +131 -0
- package/scripts/00.chat/worktree/paths/README.md +32 -0
- package/scripts/00.chat/worktree/paths/lib.sh +71 -0
- package/scripts/01.harness/artifact-metadata/check-headers/script.sh +522 -0
- package/scripts/01.harness/artifact-metadata/check-headers/smoke-test.sh +48 -0
- package/scripts/01.harness/check-deterministic-process-drift.sh +416 -0
- package/scripts/01.harness/check-governed-script-command-drift.sh +184 -0
- package/scripts/01.harness/run-governed-script.sh +178 -0
- package/scripts/install.sh +503 -0
- package/scripts/uninstall.sh +199 -0
- package/tests/smoke-test-install.sh +70 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# agentic-artifact:
|
|
5
|
+
# schema: agentic-artifact/v2
|
|
6
|
+
# id: chat.script.local-merge.report-chat-branch-overlaps
|
|
7
|
+
# version: 1
|
|
8
|
+
# status: active
|
|
9
|
+
# layer: 00.chat
|
|
10
|
+
# domain: local-merge
|
|
11
|
+
# disciplines:
|
|
12
|
+
# - agentic
|
|
13
|
+
# kind: script
|
|
14
|
+
# purpose: Report changed-path overlap between active worktree changes and chat branches.
|
|
15
|
+
# portability:
|
|
16
|
+
# class: required
|
|
17
|
+
# targets:
|
|
18
|
+
# - llm-workbench
|
|
19
|
+
# used_by:
|
|
20
|
+
# - id: chat.workflows.chat-refresh-from-main
|
|
21
|
+
# path: .agentic/00.chat/workflows/chat-refresh-from-main.md
|
|
22
|
+
# - id: harness.script.run-governed-script
|
|
23
|
+
# path: scripts/01.harness/run-governed-script.sh
|
|
24
|
+
# effects:
|
|
25
|
+
# - read-only
|
|
26
|
+
|
|
27
|
+
BASE_BRANCH="${1:-main}"
|
|
28
|
+
|
|
29
|
+
if ! git show-ref --verify --quiet "refs/heads/${BASE_BRANCH}"; then
|
|
30
|
+
echo "ERROR: base branch does not exist: ${BASE_BRANCH}" >&2
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
tmp_dir="$(mktemp -d)"
|
|
35
|
+
|
|
36
|
+
cleanup() {
|
|
37
|
+
rm -rf "$tmp_dir"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
trap cleanup EXIT
|
|
41
|
+
|
|
42
|
+
labels_file="${tmp_dir}/labels"
|
|
43
|
+
current_branch="$(git branch --show-current)"
|
|
44
|
+
|
|
45
|
+
if [ -z "$current_branch" ]; then
|
|
46
|
+
echo "ERROR: current HEAD is detached." >&2
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
safe_name() {
|
|
51
|
+
printf '%s\n' "$1" | tr -c 'A-Za-z0-9._-' '_'
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
write_branch_paths() {
|
|
55
|
+
local label="$1"
|
|
56
|
+
local branch="$2"
|
|
57
|
+
local path_file="${tmp_dir}/$(safe_name "$label").paths"
|
|
58
|
+
|
|
59
|
+
git diff --name-only "${BASE_BRANCH}...${branch}" | sort -u > "$path_file"
|
|
60
|
+
|
|
61
|
+
if [ -s "$path_file" ]; then
|
|
62
|
+
printf '%s\t%s\n' "$label" "$path_file" >> "$labels_file"
|
|
63
|
+
fi
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
write_worktree_paths() {
|
|
67
|
+
local label="worktree:${current_branch}"
|
|
68
|
+
local path_file="${tmp_dir}/$(safe_name "$label").paths"
|
|
69
|
+
|
|
70
|
+
{
|
|
71
|
+
git diff --name-only
|
|
72
|
+
git diff --cached --name-only
|
|
73
|
+
git ls-files --others --exclude-standard
|
|
74
|
+
} | sort -u > "$path_file"
|
|
75
|
+
|
|
76
|
+
if [ -s "$path_file" ]; then
|
|
77
|
+
printf '%s\t%s\n' "$label" "$path_file" >> "$labels_file"
|
|
78
|
+
fi
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
: > "$labels_file"
|
|
82
|
+
|
|
83
|
+
git branch --format='%(refname:short)' | while IFS= read -r branch; do
|
|
84
|
+
case "$branch" in
|
|
85
|
+
chat/*)
|
|
86
|
+
write_branch_paths "$branch" "$branch"
|
|
87
|
+
;;
|
|
88
|
+
esac
|
|
89
|
+
done
|
|
90
|
+
|
|
91
|
+
write_worktree_paths
|
|
92
|
+
|
|
93
|
+
if [ ! -s "$labels_file" ]; then
|
|
94
|
+
echo "No branch-only or worktree path changes found relative to ${BASE_BRANCH}."
|
|
95
|
+
exit 0
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
echo "Base branch: ${BASE_BRANCH}"
|
|
99
|
+
echo "Current branch: ${current_branch}"
|
|
100
|
+
echo
|
|
101
|
+
echo "Changed path sets:"
|
|
102
|
+
while IFS="$(printf '\t')" read -r label path_file; do
|
|
103
|
+
count="$(wc -l < "$path_file" | tr -d ' ')"
|
|
104
|
+
printf '%5s %s\n' "$count" "$label"
|
|
105
|
+
done < "$labels_file"
|
|
106
|
+
|
|
107
|
+
echo
|
|
108
|
+
echo "Overlaps:"
|
|
109
|
+
|
|
110
|
+
overlap_count=0
|
|
111
|
+
line_count="$(wc -l < "$labels_file" | tr -d ' ')"
|
|
112
|
+
|
|
113
|
+
for left_index in $(seq 1 "$line_count"); do
|
|
114
|
+
left_line="$(sed -n "${left_index}p" "$labels_file")"
|
|
115
|
+
left_label="${left_line%% *}"
|
|
116
|
+
left_file="${left_line#* }"
|
|
117
|
+
|
|
118
|
+
right_start=$((left_index + 1))
|
|
119
|
+
if [ "$right_start" -gt "$line_count" ]; then
|
|
120
|
+
continue
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
for right_index in $(seq "$right_start" "$line_count"); do
|
|
124
|
+
right_line="$(sed -n "${right_index}p" "$labels_file")"
|
|
125
|
+
right_label="${right_line%% *}"
|
|
126
|
+
right_file="${right_line#* }"
|
|
127
|
+
overlap_file="${tmp_dir}/overlap-${left_index}-${right_index}"
|
|
128
|
+
|
|
129
|
+
comm -12 "$left_file" "$right_file" > "$overlap_file"
|
|
130
|
+
|
|
131
|
+
if [ -s "$overlap_file" ]; then
|
|
132
|
+
overlap_count=$((overlap_count + 1))
|
|
133
|
+
overlap_paths="$(wc -l < "$overlap_file" | tr -d ' ')"
|
|
134
|
+
printf '\n%s <-> %s (%s paths)\n' "$left_label" "$right_label" "$overlap_paths"
|
|
135
|
+
sed 's/^/ /' "$overlap_file"
|
|
136
|
+
fi
|
|
137
|
+
done
|
|
138
|
+
done
|
|
139
|
+
|
|
140
|
+
if [ "$overlap_count" -eq 0 ]; then
|
|
141
|
+
echo "No overlapping changed paths found."
|
|
142
|
+
fi
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<!-- agentic-artifact:
|
|
2
|
+
schema: agentic-artifact/v2
|
|
3
|
+
id: chat.script.local-merge.verify-chat-ready-to-merge-local-main.readme
|
|
4
|
+
version: 1
|
|
5
|
+
status: active
|
|
6
|
+
layer: 00.chat
|
|
7
|
+
domain: local-merge
|
|
8
|
+
disciplines:
|
|
9
|
+
- agentic
|
|
10
|
+
kind: guide
|
|
11
|
+
purpose: Explain the read-only gate that checks whether a chat branch can merge into
|
|
12
|
+
local main.
|
|
13
|
+
portability:
|
|
14
|
+
class: required
|
|
15
|
+
targets:
|
|
16
|
+
- llm-workbench
|
|
17
|
+
used_by:
|
|
18
|
+
- id: chat.script.local-merge.verify-chat-ready-to-merge-local-main
|
|
19
|
+
path: scripts/00.chat/local-merge/verify-chat-ready-to-merge-local-main/script.sh
|
|
20
|
+
- id: chat.script.local-merge.verify-chat-ready-to-merge-local-main.smoke-test
|
|
21
|
+
path: scripts/00.chat/local-merge/verify-chat-ready-to-merge-local-main/smoke-test.sh
|
|
22
|
+
-->
|
|
23
|
+
# Verify Chat Ready To Merge Local Main
|
|
24
|
+
|
|
25
|
+
This capability answers: can this completed chat branch be merged into local
|
|
26
|
+
`main` right now?
|
|
27
|
+
|
|
28
|
+
It is read-only. It checks the root integration worktree, the chat-owned
|
|
29
|
+
worktree, session-log metadata, branch freshness, dirty state, and recorded
|
|
30
|
+
commit evidence. If any requirement is missing, it prints a deterministic
|
|
31
|
+
blocked state and the recovery action to take before retrying.
|
|
32
|
+
|
|
33
|
+
Use this before an explicit local merge from a chat branch into `main`.
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# agentic-artifact:
|
|
5
|
+
# schema: agentic-artifact/v2
|
|
6
|
+
# id: chat.script.local-merge.verify-chat-ready-to-merge-local-main
|
|
7
|
+
# version: 1
|
|
8
|
+
# status: active
|
|
9
|
+
# layer: 00.chat
|
|
10
|
+
# domain: local-merge
|
|
11
|
+
# disciplines:
|
|
12
|
+
# - agentic
|
|
13
|
+
# kind: script
|
|
14
|
+
# purpose: Verify whether a completed chat branch is ready to merge into local main.
|
|
15
|
+
# portability:
|
|
16
|
+
# class: required
|
|
17
|
+
# targets:
|
|
18
|
+
# - llm-workbench
|
|
19
|
+
# used_by:
|
|
20
|
+
# - id: chat.workflows.chat-promote-to-main
|
|
21
|
+
# path: .agentic/00.chat/workflows/chat-promote-to-main.md
|
|
22
|
+
# - id: harness.architecture.adr.0011-use-chat-owned-worktrees-for-local-convergence
|
|
23
|
+
# effects:
|
|
24
|
+
# - read-only
|
|
25
|
+
|
|
26
|
+
usage() {
|
|
27
|
+
cat <<'EOF'
|
|
28
|
+
Usage:
|
|
29
|
+
script.sh [--base <branch>] <chat-branch>
|
|
30
|
+
|
|
31
|
+
Read-only gate for merging a completed chat branch into local main.
|
|
32
|
+
Classifies deterministic blocked states and exits non-zero unless the branch is
|
|
33
|
+
eligible for explicit, user-approved local merge.
|
|
34
|
+
EOF
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
BASE_BRANCH="main"
|
|
38
|
+
TARGET_BRANCH=""
|
|
39
|
+
|
|
40
|
+
while [ $# -gt 0 ]; do
|
|
41
|
+
case "$1" in
|
|
42
|
+
--base)
|
|
43
|
+
if [ $# -lt 2 ]; then
|
|
44
|
+
usage >&2
|
|
45
|
+
exit 2
|
|
46
|
+
fi
|
|
47
|
+
BASE_BRANCH="$2"
|
|
48
|
+
shift 2
|
|
49
|
+
;;
|
|
50
|
+
-h|--help)
|
|
51
|
+
usage
|
|
52
|
+
exit 0
|
|
53
|
+
;;
|
|
54
|
+
*)
|
|
55
|
+
if [ -n "$TARGET_BRANCH" ]; then
|
|
56
|
+
usage >&2
|
|
57
|
+
exit 2
|
|
58
|
+
fi
|
|
59
|
+
TARGET_BRANCH="$1"
|
|
60
|
+
shift
|
|
61
|
+
;;
|
|
62
|
+
esac
|
|
63
|
+
done
|
|
64
|
+
|
|
65
|
+
if [ -z "$TARGET_BRANCH" ]; then
|
|
66
|
+
usage >&2
|
|
67
|
+
exit 2
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
|
71
|
+
REPO_ROOT="$(cd "$REPO_ROOT" && pwd -P)"
|
|
72
|
+
|
|
73
|
+
# shellcheck source=../../worktree/paths/lib.sh
|
|
74
|
+
source "$REPO_ROOT/scripts/00.chat/worktree/paths/lib.sh"
|
|
75
|
+
# shellcheck source=../../session-log/paths/lib.sh
|
|
76
|
+
source "$REPO_ROOT/scripts/00.chat/session-log/paths/lib.sh"
|
|
77
|
+
|
|
78
|
+
tmp_dir="$(mktemp -d)"
|
|
79
|
+
|
|
80
|
+
cleanup() {
|
|
81
|
+
rm -rf "$tmp_dir"
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
trap cleanup EXIT
|
|
85
|
+
|
|
86
|
+
block() {
|
|
87
|
+
local state="$1"
|
|
88
|
+
local condition="$2"
|
|
89
|
+
local action="$3"
|
|
90
|
+
|
|
91
|
+
echo "State: $state"
|
|
92
|
+
echo "Branch: $TARGET_BRANCH"
|
|
93
|
+
echo "Blocking condition: $condition"
|
|
94
|
+
echo "Required action: $action"
|
|
95
|
+
exit 1
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
info() {
|
|
99
|
+
printf '%s: %s\n' "$1" "$2"
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
find_worktree_log_by_metadata() {
|
|
103
|
+
local grouped_parent="$1"
|
|
104
|
+
local candidate
|
|
105
|
+
|
|
106
|
+
if [ ! -d "$REPO_ROOT/$grouped_parent" ]; then
|
|
107
|
+
return 1
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
while IFS= read -r candidate; do
|
|
111
|
+
if [ "$(chat_log_metadata_value "$REPO_ROOT/$candidate" "id")" = "$SESSION_ID" ] \
|
|
112
|
+
|| [ "$(chat_log_metadata_value "$REPO_ROOT/$candidate" "branch")" = "$TARGET_BRANCH" ]; then
|
|
113
|
+
printf '%s\n' "$candidate"
|
|
114
|
+
return 0
|
|
115
|
+
fi
|
|
116
|
+
done < <(find "$REPO_ROOT/$grouped_parent" -mindepth 2 -maxdepth 2 -type f -name README.md \
|
|
117
|
+
| sed "s#^$REPO_ROOT/##" \
|
|
118
|
+
| sort)
|
|
119
|
+
|
|
120
|
+
return 1
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
find_branch_log_by_metadata() {
|
|
124
|
+
local grouped_parent="$1"
|
|
125
|
+
local candidate tmp_log
|
|
126
|
+
|
|
127
|
+
while IFS= read -r candidate; do
|
|
128
|
+
tmp_log="${tmp_dir}/candidate-log.md"
|
|
129
|
+
git -C "$REPO_ROOT" show "${TARGET_BRANCH}:${candidate}" > "$tmp_log"
|
|
130
|
+
if [ "$(chat_log_metadata_value "$tmp_log" "id")" = "$SESSION_ID" ] \
|
|
131
|
+
|| [ "$(chat_log_metadata_value "$tmp_log" "branch")" = "$TARGET_BRANCH" ]; then
|
|
132
|
+
printf '%s\n' "$candidate"
|
|
133
|
+
return 0
|
|
134
|
+
fi
|
|
135
|
+
done < <(git -C "$REPO_ROOT" ls-tree -r --name-only "$TARGET_BRANCH" -- "$grouped_parent" \
|
|
136
|
+
| awk '/\/README\.md$/ { print }' \
|
|
137
|
+
| sort)
|
|
138
|
+
|
|
139
|
+
return 1
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
case "$TARGET_BRANCH" in
|
|
143
|
+
chat/*) ;;
|
|
144
|
+
*)
|
|
145
|
+
block "blocked-invalid-branch" \
|
|
146
|
+
"target is not a chat branch" \
|
|
147
|
+
"Choose a local chat/* branch."
|
|
148
|
+
;;
|
|
149
|
+
esac
|
|
150
|
+
|
|
151
|
+
if ! git -C "$REPO_ROOT" show-ref --verify --quiet "refs/heads/${BASE_BRANCH}"; then
|
|
152
|
+
block "blocked-missing-base" \
|
|
153
|
+
"base branch does not exist: $BASE_BRANCH" \
|
|
154
|
+
"Create or select the local base branch before convergence."
|
|
155
|
+
fi
|
|
156
|
+
|
|
157
|
+
if ! git -C "$REPO_ROOT" show-ref --verify --quiet "refs/heads/${TARGET_BRANCH}"; then
|
|
158
|
+
block "blocked-missing-branch" \
|
|
159
|
+
"target branch does not exist locally" \
|
|
160
|
+
"Create or fetch the chat branch before convergence."
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
PRIMARY_PATH="$(chat_worktree_primary_path)"
|
|
164
|
+
PRIMARY_PATH="$(cd "$PRIMARY_PATH" && pwd -P)"
|
|
165
|
+
|
|
166
|
+
if [ "$REPO_ROOT" != "$PRIMARY_PATH" ]; then
|
|
167
|
+
block "blocked-not-root-integration-worktree" \
|
|
168
|
+
"verification is not running from the root integration worktree" \
|
|
169
|
+
"Run local merge verification from the root integration worktree."
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
current_branch="$(git -C "$REPO_ROOT" branch --show-current)"
|
|
173
|
+
if [ "$current_branch" != "$BASE_BRANCH" ]; then
|
|
174
|
+
block "blocked-root-not-main" \
|
|
175
|
+
"root integration worktree is on '$current_branch', expected '$BASE_BRANCH'" \
|
|
176
|
+
"Switch the root integration worktree to $BASE_BRANCH before convergence."
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
if [ -n "$(git -C "$REPO_ROOT" status --porcelain)" ]; then
|
|
180
|
+
block "blocked-dirty-root" \
|
|
181
|
+
"root integration worktree is dirty" \
|
|
182
|
+
"Clean or explicitly resolve root worktree changes before convergence."
|
|
183
|
+
fi
|
|
184
|
+
|
|
185
|
+
SESSION_ID="${TARGET_BRANCH#chat/}"
|
|
186
|
+
GROUPED_DIR="$(chat_log_grouped_dir_for_session "$SESSION_ID")"
|
|
187
|
+
GROUPED_PARENT="${GROUPED_DIR%/*}"
|
|
188
|
+
GROUPED_LOG="${GROUPED_DIR}/README.md"
|
|
189
|
+
FLAT_LOG="commitLogs/${SESSION_ID}/README.md"
|
|
190
|
+
LOG_FILE="${tmp_dir}/session-log.md"
|
|
191
|
+
LOG_SOURCE=""
|
|
192
|
+
LOG_PATH=""
|
|
193
|
+
metadata_log_path=""
|
|
194
|
+
|
|
195
|
+
if git -C "$REPO_ROOT" cat-file -e "${TARGET_BRANCH}:${GROUPED_LOG}" 2>/dev/null; then
|
|
196
|
+
git -C "$REPO_ROOT" show "${TARGET_BRANCH}:${GROUPED_LOG}" > "$LOG_FILE"
|
|
197
|
+
LOG_SOURCE="branch"
|
|
198
|
+
LOG_PATH="$GROUPED_LOG"
|
|
199
|
+
elif git -C "$REPO_ROOT" cat-file -e "${TARGET_BRANCH}:${FLAT_LOG}" 2>/dev/null; then
|
|
200
|
+
git -C "$REPO_ROOT" show "${TARGET_BRANCH}:${FLAT_LOG}" > "$LOG_FILE"
|
|
201
|
+
LOG_SOURCE="branch"
|
|
202
|
+
LOG_PATH="$FLAT_LOG"
|
|
203
|
+
elif metadata_log_path="$(find_branch_log_by_metadata "$GROUPED_PARENT")"; then
|
|
204
|
+
git -C "$REPO_ROOT" show "${TARGET_BRANCH}:${metadata_log_path}" > "$LOG_FILE"
|
|
205
|
+
LOG_SOURCE="branch"
|
|
206
|
+
LOG_PATH="$metadata_log_path"
|
|
207
|
+
elif [ -f "$REPO_ROOT/$GROUPED_LOG" ]; then
|
|
208
|
+
cp "$REPO_ROOT/$GROUPED_LOG" "$LOG_FILE"
|
|
209
|
+
LOG_SOURCE="worktree"
|
|
210
|
+
LOG_PATH="$GROUPED_LOG"
|
|
211
|
+
elif [ -f "$REPO_ROOT/$FLAT_LOG" ]; then
|
|
212
|
+
cp "$REPO_ROOT/$FLAT_LOG" "$LOG_FILE"
|
|
213
|
+
LOG_SOURCE="worktree"
|
|
214
|
+
LOG_PATH="$FLAT_LOG"
|
|
215
|
+
elif metadata_log_path="$(find_worktree_log_by_metadata "$GROUPED_PARENT")"; then
|
|
216
|
+
cp "$REPO_ROOT/$metadata_log_path" "$LOG_FILE"
|
|
217
|
+
LOG_SOURCE="worktree"
|
|
218
|
+
LOG_PATH="$metadata_log_path"
|
|
219
|
+
else
|
|
220
|
+
block "blocked-missing-log" \
|
|
221
|
+
"session log is missing from root $BASE_BRANCH and target branch" \
|
|
222
|
+
"Restore or create the chat session log before convergence."
|
|
223
|
+
fi
|
|
224
|
+
|
|
225
|
+
metadata_branch="$(chat_log_metadata_value "$LOG_FILE" "branch")"
|
|
226
|
+
metadata_worktree="$(chat_log_metadata_value "$LOG_FILE" "worktree")"
|
|
227
|
+
metadata_latest_sha="$(chat_log_metadata_value "$LOG_FILE" "latest_commit_sha")"
|
|
228
|
+
|
|
229
|
+
if [ "$metadata_branch" != "$TARGET_BRANCH" ]; then
|
|
230
|
+
block "blocked-invalid-metadata" \
|
|
231
|
+
"session log branch metadata is '$metadata_branch', expected '$TARGET_BRANCH'" \
|
|
232
|
+
"Fix the session log metadata before convergence."
|
|
233
|
+
fi
|
|
234
|
+
|
|
235
|
+
WORKTREE_PATH="$(chat_worktree_path_for_branch "$REPO_ROOT" "$TARGET_BRANCH")"
|
|
236
|
+
if [ "$metadata_worktree" != "$WORKTREE_PATH" ]; then
|
|
237
|
+
block "blocked-invalid-metadata" \
|
|
238
|
+
"session log worktree metadata is '$metadata_worktree', expected '$WORKTREE_PATH'" \
|
|
239
|
+
"Fix the session log worktree metadata before convergence."
|
|
240
|
+
fi
|
|
241
|
+
|
|
242
|
+
branch_worktrees="$(
|
|
243
|
+
git -C "$REPO_ROOT" worktree list --porcelain \
|
|
244
|
+
| awk -v branch="refs/heads/${TARGET_BRANCH}" '
|
|
245
|
+
/^worktree / { path = substr($0, 10) }
|
|
246
|
+
/^branch / && substr($0, 8) == branch { print path }
|
|
247
|
+
'
|
|
248
|
+
)"
|
|
249
|
+
|
|
250
|
+
found_canonical_worktree="no"
|
|
251
|
+
while IFS= read -r branch_worktree; do
|
|
252
|
+
if [ -z "${branch_worktree// }" ]; then
|
|
253
|
+
continue
|
|
254
|
+
fi
|
|
255
|
+
|
|
256
|
+
branch_worktree="$(cd "$branch_worktree" && pwd -P)"
|
|
257
|
+
if [ "$branch_worktree" = "$PRIMARY_PATH" ]; then
|
|
258
|
+
block "blocked-branch-in-root-worktree" \
|
|
259
|
+
"target chat branch is checked out in the root integration worktree" \
|
|
260
|
+
"Switch root back to $BASE_BRANCH before convergence."
|
|
261
|
+
fi
|
|
262
|
+
|
|
263
|
+
if [ "$branch_worktree" != "$WORKTREE_PATH" ]; then
|
|
264
|
+
block "blocked-wrong-worktree" \
|
|
265
|
+
"target chat branch is checked out in '$branch_worktree', expected '$WORKTREE_PATH'" \
|
|
266
|
+
"Move or recreate the chat-owned worktree before convergence."
|
|
267
|
+
fi
|
|
268
|
+
|
|
269
|
+
found_canonical_worktree="yes"
|
|
270
|
+
done <<< "$branch_worktrees"
|
|
271
|
+
|
|
272
|
+
if [ "$found_canonical_worktree" != "yes" ]; then
|
|
273
|
+
block "blocked-missing-worktree" \
|
|
274
|
+
"canonical chat-owned worktree is missing" \
|
|
275
|
+
"Run ensure-chat-worktree after session log verification, then rerun convergence verification."
|
|
276
|
+
fi
|
|
277
|
+
|
|
278
|
+
if ! git -C "$WORKTREE_PATH" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
279
|
+
block "blocked-missing-worktree" \
|
|
280
|
+
"canonical chat-owned worktree path is not a git worktree" \
|
|
281
|
+
"Recreate the chat-owned worktree before convergence."
|
|
282
|
+
fi
|
|
283
|
+
|
|
284
|
+
worktree_branch="$(git -C "$WORKTREE_PATH" branch --show-current)"
|
|
285
|
+
if [ "$worktree_branch" != "$TARGET_BRANCH" ]; then
|
|
286
|
+
block "blocked-wrong-worktree" \
|
|
287
|
+
"chat worktree is on '$worktree_branch', expected '$TARGET_BRANCH'" \
|
|
288
|
+
"Check out the target chat branch in its canonical worktree."
|
|
289
|
+
fi
|
|
290
|
+
|
|
291
|
+
if [ -n "$(git -C "$WORKTREE_PATH" status --porcelain)" ]; then
|
|
292
|
+
block "blocked-dirty-chat-worktree" \
|
|
293
|
+
"chat-owned worktree is dirty" \
|
|
294
|
+
"Commit, inspect, preserve, or explicitly discard chat work before convergence."
|
|
295
|
+
fi
|
|
296
|
+
|
|
297
|
+
ahead="$(git -C "$REPO_ROOT" rev-list --count "${BASE_BRANCH}..${TARGET_BRANCH}")"
|
|
298
|
+
behind="$(git -C "$REPO_ROOT" rev-list --count "${TARGET_BRANCH}..${BASE_BRANCH}")"
|
|
299
|
+
|
|
300
|
+
if [ "$behind" != "0" ] && [ "$ahead" != "0" ]; then
|
|
301
|
+
block "blocked-diverged" \
|
|
302
|
+
"chat branch and $BASE_BRANCH both have unique commits" \
|
|
303
|
+
"Use the governed refresh path before convergence."
|
|
304
|
+
fi
|
|
305
|
+
|
|
306
|
+
if [ "$behind" != "0" ]; then
|
|
307
|
+
block "blocked-behind" \
|
|
308
|
+
"chat branch is behind $BASE_BRANCH" \
|
|
309
|
+
"Merge $BASE_BRANCH into the chat branch from the chat-owned worktree before convergence."
|
|
310
|
+
fi
|
|
311
|
+
|
|
312
|
+
if [ "$ahead" = "0" ]; then
|
|
313
|
+
block "blocked-even" \
|
|
314
|
+
"chat branch has no commits beyond $BASE_BRANCH" \
|
|
315
|
+
"Do not merge; use cleanup or reporting flow instead."
|
|
316
|
+
fi
|
|
317
|
+
|
|
318
|
+
if [ -z "${metadata_latest_sha// }" ]; then
|
|
319
|
+
block "blocked-unrecorded-commit" \
|
|
320
|
+
"session log does not record latest_commit_sha" \
|
|
321
|
+
"Record the latest task commit, or explain the no-task-commit case before convergence."
|
|
322
|
+
fi
|
|
323
|
+
|
|
324
|
+
if ! git -C "$REPO_ROOT" cat-file -e "${metadata_latest_sha}^{commit}" 2>/dev/null; then
|
|
325
|
+
block "blocked-log-head-mismatch" \
|
|
326
|
+
"recorded latest_commit_sha does not resolve to a commit: $metadata_latest_sha" \
|
|
327
|
+
"Fix the session log commit evidence before convergence."
|
|
328
|
+
fi
|
|
329
|
+
|
|
330
|
+
if ! git -C "$REPO_ROOT" merge-base --is-ancestor "$metadata_latest_sha" "$TARGET_BRANCH"; then
|
|
331
|
+
block "blocked-log-head-mismatch" \
|
|
332
|
+
"recorded latest_commit_sha is not contained in the chat branch" \
|
|
333
|
+
"Record a commit that is present on the target chat branch before convergence."
|
|
334
|
+
fi
|
|
335
|
+
|
|
336
|
+
echo "State: eligible"
|
|
337
|
+
info "Base branch" "$BASE_BRANCH"
|
|
338
|
+
info "Branch" "$TARGET_BRANCH"
|
|
339
|
+
info "Ahead of base" "$ahead"
|
|
340
|
+
info "Behind base" "$behind"
|
|
341
|
+
info "Session log source" "$LOG_SOURCE"
|
|
342
|
+
info "Session log path" "$LOG_PATH"
|
|
343
|
+
info "Chat worktree" "$WORKTREE_PATH"
|
|
344
|
+
info "Recorded latest task commit" "$metadata_latest_sha"
|
|
345
|
+
echo "Next step: ask for explicit approval, then merge from the root integration worktree."
|