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,178 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# agentic-artifact:
|
|
5
|
+
# schema: agentic-artifact/v2
|
|
6
|
+
# id: harness.script.run-governed-script
|
|
7
|
+
# version: 1
|
|
8
|
+
# status: active
|
|
9
|
+
# layer: 01.harness
|
|
10
|
+
# domain: governance
|
|
11
|
+
# disciplines:
|
|
12
|
+
# - agentic
|
|
13
|
+
# kind: script
|
|
14
|
+
# purpose: Run only explicitly governed repository scripts with approval-sensitive routing.
|
|
15
|
+
# portability:
|
|
16
|
+
# class: required
|
|
17
|
+
# targets:
|
|
18
|
+
# - llm-workbench
|
|
19
|
+
# used_by:
|
|
20
|
+
# - id: harness.standards.governed-script-permissions
|
|
21
|
+
# - id: chat.workflows.chat-start
|
|
22
|
+
# path: .agentic/00.chat/workflows/chat-start.md
|
|
23
|
+
# effects:
|
|
24
|
+
# - read-only
|
|
25
|
+
|
|
26
|
+
usage() {
|
|
27
|
+
cat <<'EOF'
|
|
28
|
+
Usage:
|
|
29
|
+
run-governed-script.sh [--approved-action] <script> [args...]
|
|
30
|
+
run-governed-script.sh --list
|
|
31
|
+
|
|
32
|
+
Runs only explicitly governed repository scripts.
|
|
33
|
+
|
|
34
|
+
Use --approved-action only after the current chat has explicit approval for the
|
|
35
|
+
action class governed by the active workflow.
|
|
36
|
+
EOF
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
has_artifact_header() {
|
|
40
|
+
sed -n '1,80p' "$1" | grep -Fq "agentic-artifact:"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
metadata_has_line() {
|
|
44
|
+
local path="$1"
|
|
45
|
+
local value="$2"
|
|
46
|
+
|
|
47
|
+
sed -n '1,140p' "$path" | grep -Eq "^[#[:space:]]*-[[:space:]]*$value[[:space:]]*$"
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
has_never_persistent_effect() {
|
|
51
|
+
local path="$1"
|
|
52
|
+
|
|
53
|
+
case "$path" in
|
|
54
|
+
scripts/00.chat/main-refresh/apply-rehearsed-refresh/script.sh)
|
|
55
|
+
return 1
|
|
56
|
+
;;
|
|
57
|
+
esac
|
|
58
|
+
|
|
59
|
+
metadata_has_line "$path" "destructive" ||
|
|
60
|
+
metadata_has_line "$path" "push" ||
|
|
61
|
+
metadata_has_line "$path" "history-rewrite" ||
|
|
62
|
+
metadata_has_line "$path" "overwrites" ||
|
|
63
|
+
metadata_has_line "$path" "cloud" ||
|
|
64
|
+
metadata_has_line "$path" "database"
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
classify_script() {
|
|
68
|
+
local path="$1"
|
|
69
|
+
|
|
70
|
+
case "$path" in
|
|
71
|
+
*/lib.sh)
|
|
72
|
+
echo "ERROR: governed library files must not be invoked directly: $path" >&2
|
|
73
|
+
return 1
|
|
74
|
+
;;
|
|
75
|
+
esac
|
|
76
|
+
|
|
77
|
+
case "$path" in
|
|
78
|
+
scripts/[0-9][0-9].*/*.sh|scripts/[0-9][0-9].*/*/script.sh|scripts/[0-9][0-9].*/*/smoke-test.sh|\
|
|
79
|
+
scripts/[0-9][0-9].*/*/*/script.sh|scripts/[0-9][0-9].*/*/*/smoke-test.sh)
|
|
80
|
+
;;
|
|
81
|
+
scripts/shared/*.sh|scripts/shared/*/*.sh)
|
|
82
|
+
echo "ERROR: retired shared script path must not be invoked directly: $path" >&2
|
|
83
|
+
return 1
|
|
84
|
+
;;
|
|
85
|
+
*)
|
|
86
|
+
echo "ERROR: refused script outside canonical governed script paths: $path" >&2
|
|
87
|
+
return 1
|
|
88
|
+
;;
|
|
89
|
+
esac
|
|
90
|
+
|
|
91
|
+
if [ ! -f "$path" ]; then
|
|
92
|
+
echo "ERROR: governed script does not exist: $path" >&2
|
|
93
|
+
return 1
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
if ! has_artifact_header "$path"; then
|
|
97
|
+
echo "ERROR: script is missing governed agentic-artifact metadata: $path" >&2
|
|
98
|
+
return 1
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
if has_never_persistent_effect "$path"; then
|
|
102
|
+
echo "ERROR: script has effects that are never persistent-auto-approved: $path" >&2
|
|
103
|
+
return 1
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
if metadata_has_line "$path" "read-only" &&
|
|
107
|
+
! metadata_has_line "$path" "writes-files" &&
|
|
108
|
+
! metadata_has_line "$path" "commits" &&
|
|
109
|
+
! metadata_has_line "$path" "network"; then
|
|
110
|
+
printf '%s\n' "always"
|
|
111
|
+
return 0
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
printf '%s\n' "approved"
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
APPROVED_ACTION="no"
|
|
118
|
+
|
|
119
|
+
if [ $# -eq 0 ]; then
|
|
120
|
+
usage >&2
|
|
121
|
+
exit 2
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
case "$1" in
|
|
125
|
+
--approved-action)
|
|
126
|
+
APPROVED_ACTION="yes"
|
|
127
|
+
shift
|
|
128
|
+
;;
|
|
129
|
+
--list)
|
|
130
|
+
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
|
131
|
+
cd "$REPO_ROOT"
|
|
132
|
+
git ls-files 'scripts/*.sh' 'scripts/*/*.sh' 'scripts/*/*/*.sh' 'scripts/*/*/*/*.sh' |
|
|
133
|
+
while IFS= read -r script_path; do
|
|
134
|
+
run_class="$(classify_script "$script_path" 2>/dev/null || true)"
|
|
135
|
+
if [ -n "$run_class" ]; then
|
|
136
|
+
printf '%s %s\n' "$run_class" "$script_path"
|
|
137
|
+
fi
|
|
138
|
+
done
|
|
139
|
+
exit 0
|
|
140
|
+
;;
|
|
141
|
+
-h|--help)
|
|
142
|
+
usage
|
|
143
|
+
exit 0
|
|
144
|
+
;;
|
|
145
|
+
esac
|
|
146
|
+
|
|
147
|
+
if [ $# -eq 0 ]; then
|
|
148
|
+
usage >&2
|
|
149
|
+
exit 2
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
SCRIPT_PATH="$1"
|
|
153
|
+
shift
|
|
154
|
+
|
|
155
|
+
case "$SCRIPT_PATH" in
|
|
156
|
+
/*|*../*|../*|*"/.."|*".."|*"
|
|
157
|
+
"*)
|
|
158
|
+
echo "ERROR: refused non-repository script path: $SCRIPT_PATH" >&2
|
|
159
|
+
exit 1
|
|
160
|
+
;;
|
|
161
|
+
esac
|
|
162
|
+
|
|
163
|
+
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
|
164
|
+
cd "$REPO_ROOT"
|
|
165
|
+
|
|
166
|
+
RUN_CLASS="$(classify_script "$SCRIPT_PATH")"
|
|
167
|
+
|
|
168
|
+
if [ "$RUN_CLASS" = "approved" ] && [ "$APPROVED_ACTION" != "yes" ]; then
|
|
169
|
+
echo "ERROR: approval-sensitive script requires --approved-action: $SCRIPT_PATH" >&2
|
|
170
|
+
exit 1
|
|
171
|
+
fi
|
|
172
|
+
|
|
173
|
+
if [ ! -f "$SCRIPT_PATH" ]; then
|
|
174
|
+
echo "ERROR: governed script does not exist: $SCRIPT_PATH" >&2
|
|
175
|
+
exit 1
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
exec bash "$SCRIPT_PATH" "$@"
|
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# agentic-artifact:
|
|
5
|
+
# schema: agentic-artifact/v2
|
|
6
|
+
# id: chat.script.install
|
|
7
|
+
# version: 1
|
|
8
|
+
# status: active
|
|
9
|
+
# layer: 00.chat
|
|
10
|
+
# domain: install
|
|
11
|
+
# disciplines:
|
|
12
|
+
# - agentic
|
|
13
|
+
# kind: script
|
|
14
|
+
# purpose: Install the llm-workbench chat harness into a target Git repository.
|
|
15
|
+
# portability:
|
|
16
|
+
# class: required
|
|
17
|
+
# targets:
|
|
18
|
+
# - llm-workbench
|
|
19
|
+
# used_by:
|
|
20
|
+
# - id: llm-workbench.docs.install
|
|
21
|
+
# effects:
|
|
22
|
+
# - writes-files
|
|
23
|
+
# - commits
|
|
24
|
+
|
|
25
|
+
usage() {
|
|
26
|
+
cat <<'EOF'
|
|
27
|
+
Usage:
|
|
28
|
+
scripts/install.sh [--dry-run|--apply] [--init-commit] <target-git-repo>
|
|
29
|
+
|
|
30
|
+
Installs the llm-workbench chat harness into a target Git repository.
|
|
31
|
+
|
|
32
|
+
The installer always plans first. Apply mode refuses to write when the plan has
|
|
33
|
+
conflicts. Existing package.json files are merged by adding only workbench-owned
|
|
34
|
+
chat:* scripts. Existing assistant instruction files are patched with a managed
|
|
35
|
+
llm-workbench block instead of being overwritten.
|
|
36
|
+
EOF
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
MODE=""
|
|
40
|
+
INIT_COMMIT="no"
|
|
41
|
+
TARGET_REPO=""
|
|
42
|
+
|
|
43
|
+
while [ $# -gt 0 ]; do
|
|
44
|
+
case "$1" in
|
|
45
|
+
--dry-run)
|
|
46
|
+
[ -z "$MODE" ] || { echo "ERROR: choose one mode." >&2; exit 2; }
|
|
47
|
+
MODE="dry-run"
|
|
48
|
+
shift
|
|
49
|
+
;;
|
|
50
|
+
--apply)
|
|
51
|
+
[ -z "$MODE" ] || { echo "ERROR: choose one mode." >&2; exit 2; }
|
|
52
|
+
MODE="apply"
|
|
53
|
+
shift
|
|
54
|
+
;;
|
|
55
|
+
--init-commit)
|
|
56
|
+
INIT_COMMIT="yes"
|
|
57
|
+
shift
|
|
58
|
+
;;
|
|
59
|
+
-h|--help)
|
|
60
|
+
usage
|
|
61
|
+
exit 0
|
|
62
|
+
;;
|
|
63
|
+
-*)
|
|
64
|
+
echo "ERROR: unknown argument: $1" >&2
|
|
65
|
+
usage >&2
|
|
66
|
+
exit 2
|
|
67
|
+
;;
|
|
68
|
+
*)
|
|
69
|
+
[ -z "$TARGET_REPO" ] || { echo "ERROR: target repo specified twice." >&2; exit 2; }
|
|
70
|
+
TARGET_REPO="$1"
|
|
71
|
+
shift
|
|
72
|
+
;;
|
|
73
|
+
esac
|
|
74
|
+
done
|
|
75
|
+
|
|
76
|
+
MODE="${MODE:-apply}"
|
|
77
|
+
|
|
78
|
+
if [ -z "$TARGET_REPO" ]; then
|
|
79
|
+
usage >&2
|
|
80
|
+
exit 2
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
if [ ! -d "$TARGET_REPO/.git" ]; then
|
|
84
|
+
echo "ERROR: target is not a Git repo: $TARGET_REPO" >&2
|
|
85
|
+
exit 1
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
if [ "$INIT_COMMIT" = "yes" ] && [ "$MODE" = "apply" ]; then
|
|
89
|
+
if git -C "$TARGET_REPO" rev-parse --verify HEAD >/dev/null 2>&1; then
|
|
90
|
+
echo "ERROR: --init-commit is only for repos with no existing HEAD." >&2
|
|
91
|
+
exit 2
|
|
92
|
+
fi
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
SOURCE_REPO="$(cd "$(dirname "$0")/.." && pwd)"
|
|
96
|
+
TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/llm-workbench-install-plan.XXXXXX")"
|
|
97
|
+
PLAN_PATHS="$TMP_DIR/planned-paths.txt"
|
|
98
|
+
FILE_ACTIONS="$TMP_DIR/file-actions.tsv"
|
|
99
|
+
PACKAGE_OUTPUT="$TMP_DIR/package-output.txt"
|
|
100
|
+
MANIFEST_OUTPUT="$TMP_DIR/install-manifest.tsv"
|
|
101
|
+
MANIFEST_PATH="$TARGET_REPO/.llm-workbench/install-manifest.tsv"
|
|
102
|
+
|
|
103
|
+
cleanup() {
|
|
104
|
+
rm -rf "$TMP_DIR"
|
|
105
|
+
}
|
|
106
|
+
trap cleanup EXIT
|
|
107
|
+
|
|
108
|
+
: > "$PLAN_PATHS"
|
|
109
|
+
: > "$FILE_ACTIONS"
|
|
110
|
+
: > "$MANIFEST_OUTPUT"
|
|
111
|
+
|
|
112
|
+
CREATE_COUNT=0
|
|
113
|
+
SAME_COUNT=0
|
|
114
|
+
PATCH_COUNT=0
|
|
115
|
+
CONFLICT_COUNT=0
|
|
116
|
+
PACKAGE_CONFLICTS="no"
|
|
117
|
+
|
|
118
|
+
managed_block() {
|
|
119
|
+
cat <<'EOF'
|
|
120
|
+
|
|
121
|
+
<!-- llm-workbench:start -->
|
|
122
|
+
## llm-workbench
|
|
123
|
+
|
|
124
|
+
Follow `.agentic/00.chat/workflows/chat-start.md` at the start of each chat.
|
|
125
|
+
Use `commitLogs/<session>/README.md` as the first source of truth for chat
|
|
126
|
+
lifecycle, branch, worktree, context-packet references, commits, and metrics.
|
|
127
|
+
|
|
128
|
+
Do not assign the whole chat a durable layer, mode, or workflow. When a prompt
|
|
129
|
+
needs layer, mode, workflow, corpus, or rule context, use the current user
|
|
130
|
+
request, this repo's assistant instructions, and any repo-provided context
|
|
131
|
+
router if one exists.
|
|
132
|
+
|
|
133
|
+
Default mode after governed chat-start bootstrap is read-only until the user
|
|
134
|
+
explicitly grants write permission for task files.
|
|
135
|
+
<!-- llm-workbench:end -->
|
|
136
|
+
EOF
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
record_path() {
|
|
140
|
+
printf '%s\n' "$1" >> "$PLAN_PATHS"
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
plan_file() {
|
|
144
|
+
local source="$1"
|
|
145
|
+
local relative_path="$2"
|
|
146
|
+
local target="$TARGET_REPO/$relative_path"
|
|
147
|
+
|
|
148
|
+
record_path "$relative_path"
|
|
149
|
+
|
|
150
|
+
if [ -e "$target" ]; then
|
|
151
|
+
if cmp -s "$source" "$target"; then
|
|
152
|
+
echo "SAME $relative_path"
|
|
153
|
+
printf 'SAME\t%s\t%s\n' "$source" "$relative_path" >> "$FILE_ACTIONS"
|
|
154
|
+
SAME_COUNT=$((SAME_COUNT + 1))
|
|
155
|
+
else
|
|
156
|
+
echo "CONFLICT $relative_path"
|
|
157
|
+
printf 'CONFLICT\t%s\t%s\n' "$source" "$relative_path" >> "$FILE_ACTIONS"
|
|
158
|
+
CONFLICT_COUNT=$((CONFLICT_COUNT + 1))
|
|
159
|
+
fi
|
|
160
|
+
else
|
|
161
|
+
echo "CREATE $relative_path"
|
|
162
|
+
printf 'CREATE\t%s\t%s\n' "$source" "$relative_path" >> "$FILE_ACTIONS"
|
|
163
|
+
CREATE_COUNT=$((CREATE_COUNT + 1))
|
|
164
|
+
fi
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
plan_instruction_file() {
|
|
168
|
+
local source="$1"
|
|
169
|
+
local relative_path="$2"
|
|
170
|
+
local target="$TARGET_REPO/$relative_path"
|
|
171
|
+
|
|
172
|
+
[ -f "$source" ] || return 0
|
|
173
|
+
record_path "$relative_path"
|
|
174
|
+
|
|
175
|
+
if [ ! -e "$target" ]; then
|
|
176
|
+
echo "CREATE $relative_path"
|
|
177
|
+
printf 'CREATE\t%s\t%s\n' "$source" "$relative_path" >> "$FILE_ACTIONS"
|
|
178
|
+
CREATE_COUNT=$((CREATE_COUNT + 1))
|
|
179
|
+
return 0
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
if cmp -s "$source" "$target"; then
|
|
183
|
+
echo "SAME $relative_path"
|
|
184
|
+
printf 'SAME\t%s\t%s\n' "$source" "$relative_path" >> "$FILE_ACTIONS"
|
|
185
|
+
SAME_COUNT=$((SAME_COUNT + 1))
|
|
186
|
+
return 0
|
|
187
|
+
fi
|
|
188
|
+
|
|
189
|
+
if grep -q 'llm-workbench:start' "$target"; then
|
|
190
|
+
echo "SAME_BLOCK $relative_path"
|
|
191
|
+
printf 'SAME_BLOCK\t%s\t%s\n' "$source" "$relative_path" >> "$FILE_ACTIONS"
|
|
192
|
+
SAME_COUNT=$((SAME_COUNT + 1))
|
|
193
|
+
else
|
|
194
|
+
echo "PATCH_BLOCK $relative_path"
|
|
195
|
+
printf 'PATCH_BLOCK\t%s\t%s\n' "$source" "$relative_path" >> "$FILE_ACTIONS"
|
|
196
|
+
PATCH_COUNT=$((PATCH_COUNT + 1))
|
|
197
|
+
fi
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
plan_tree() {
|
|
201
|
+
local tree="$1"
|
|
202
|
+
local file
|
|
203
|
+
local relative_path
|
|
204
|
+
|
|
205
|
+
[ -d "$SOURCE_REPO/$tree" ] || return 0
|
|
206
|
+
|
|
207
|
+
while IFS= read -r file; do
|
|
208
|
+
relative_path="${file#$SOURCE_REPO/}"
|
|
209
|
+
case "$relative_path" in
|
|
210
|
+
scripts/00.chat/upstream/*)
|
|
211
|
+
continue
|
|
212
|
+
;;
|
|
213
|
+
esac
|
|
214
|
+
plan_file "$file" "$relative_path"
|
|
215
|
+
done < <(find "$SOURCE_REPO/$tree" -type f | sort)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
plan_selected_file() {
|
|
219
|
+
local path="$1"
|
|
220
|
+
|
|
221
|
+
[ -f "$SOURCE_REPO/$path" ] || return 0
|
|
222
|
+
plan_file "$SOURCE_REPO/$path" "$path"
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
plan_public_harness_scripts() {
|
|
226
|
+
plan_selected_file "scripts/01.harness/run-governed-script.sh"
|
|
227
|
+
plan_selected_file "scripts/01.harness/check-deterministic-process-drift.sh"
|
|
228
|
+
plan_selected_file "scripts/01.harness/check-governed-script-command-drift.sh"
|
|
229
|
+
plan_selected_file "scripts/01.harness/artifact-metadata/check-headers/script.sh"
|
|
230
|
+
plan_selected_file "scripts/01.harness/artifact-metadata/check-headers/smoke-test.sh"
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
plan_package_json() {
|
|
234
|
+
local target_package="$TARGET_REPO/package.json"
|
|
235
|
+
local template_package="$SOURCE_REPO/package.json"
|
|
236
|
+
|
|
237
|
+
record_path "package.json"
|
|
238
|
+
|
|
239
|
+
if [ ! -f "$target_package" ]; then
|
|
240
|
+
echo "CREATE package.json"
|
|
241
|
+
printf 'CREATE_PACKAGE\t%s\tpackage.json\n' "$template_package" >> "$FILE_ACTIONS"
|
|
242
|
+
CREATE_COUNT=$((CREATE_COUNT + 1))
|
|
243
|
+
return 0
|
|
244
|
+
fi
|
|
245
|
+
|
|
246
|
+
printf 'MERGE_PACKAGE\t%s\tpackage.json\n' "$template_package" >> "$FILE_ACTIONS"
|
|
247
|
+
|
|
248
|
+
if ! node - "$target_package" "$template_package" > "$PACKAGE_OUTPUT" <<'NODE'
|
|
249
|
+
const fs = require('fs');
|
|
250
|
+
const targetPath = process.argv[2];
|
|
251
|
+
const templatePath = process.argv[3];
|
|
252
|
+
|
|
253
|
+
let target;
|
|
254
|
+
let template;
|
|
255
|
+
|
|
256
|
+
try {
|
|
257
|
+
target = JSON.parse(fs.readFileSync(targetPath, 'utf8'));
|
|
258
|
+
} catch (error) {
|
|
259
|
+
console.log(`CONFLICT package.json invalid-json ${error.message}`);
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
try {
|
|
264
|
+
template = JSON.parse(fs.readFileSync(templatePath, 'utf8'));
|
|
265
|
+
} catch (error) {
|
|
266
|
+
console.log(`CONFLICT package.json template-invalid-json ${error.message}`);
|
|
267
|
+
process.exit(1);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const actualScripts = target.scripts || {};
|
|
271
|
+
const expectedScripts = template.scripts || {};
|
|
272
|
+
let conflicts = 0;
|
|
273
|
+
|
|
274
|
+
for (const [name, expected] of Object.entries(expectedScripts)) {
|
|
275
|
+
const actual = actualScripts[name];
|
|
276
|
+
if (!name.startsWith('chat:') && name !== 'chat') {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
if (actual === undefined) {
|
|
280
|
+
console.log(`PACKAGE_ADD_SCRIPT ${name} ${expected}`);
|
|
281
|
+
} else if (actual === expected) {
|
|
282
|
+
console.log(`PACKAGE_SAME_SCRIPT ${name}`);
|
|
283
|
+
} else {
|
|
284
|
+
console.log(`PACKAGE_CONFLICT_SCRIPT ${name} actual=${actual} expected=${expected}`);
|
|
285
|
+
conflicts += 1;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
for (const name of Object.keys(actualScripts).sort()) {
|
|
290
|
+
if (expectedScripts[name] === undefined || (!name.startsWith('chat:') && name !== 'chat')) {
|
|
291
|
+
console.log(`PACKAGE_PRESERVE_SCRIPT ${name} ${actualScripts[name]}`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
process.exit(conflicts > 0 ? 1 : 0);
|
|
296
|
+
NODE
|
|
297
|
+
then
|
|
298
|
+
PACKAGE_CONFLICTS="yes"
|
|
299
|
+
CONFLICT_COUNT=$((CONFLICT_COUNT + 1))
|
|
300
|
+
fi
|
|
301
|
+
|
|
302
|
+
cat "$PACKAGE_OUTPUT"
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
print_header() {
|
|
306
|
+
local head
|
|
307
|
+
local branch
|
|
308
|
+
|
|
309
|
+
head="$(git -C "$TARGET_REPO" rev-parse --verify HEAD 2>/dev/null || true)"
|
|
310
|
+
branch="$(git -C "$TARGET_REPO" branch --show-current 2>/dev/null || true)"
|
|
311
|
+
|
|
312
|
+
echo "llm-workbench install ${MODE}"
|
|
313
|
+
echo
|
|
314
|
+
echo "Source repo: $SOURCE_REPO"
|
|
315
|
+
echo "Target repo: $TARGET_REPO"
|
|
316
|
+
echo "Target branch: ${branch:-<none>}"
|
|
317
|
+
echo "Target HEAD: ${head:-<unborn>}"
|
|
318
|
+
echo "Target OS: ${LLM_WORKBENCH_TARGET_OS:-auto}"
|
|
319
|
+
echo
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
print_header
|
|
323
|
+
|
|
324
|
+
echo "Package plan:"
|
|
325
|
+
plan_package_json
|
|
326
|
+
echo
|
|
327
|
+
|
|
328
|
+
echo "File plan:"
|
|
329
|
+
plan_instruction_file "$SOURCE_REPO/AGENTS.md" "AGENTS.md"
|
|
330
|
+
plan_instruction_file "$SOURCE_REPO/CLAUDE.md" "CLAUDE.md"
|
|
331
|
+
plan_instruction_file "$SOURCE_REPO/.github/copilot-instructions.md" ".github/copilot-instructions.md"
|
|
332
|
+
plan_instruction_file "$SOURCE_REPO/.cursor/rules/llm-workbench.mdc" ".cursor/rules/llm-workbench.mdc"
|
|
333
|
+
plan_instruction_file "$SOURCE_REPO/LLM_WORKBENCH.md" "LLM_WORKBENCH.md"
|
|
334
|
+
plan_tree "bin"
|
|
335
|
+
plan_tree ".agentic/00.chat"
|
|
336
|
+
plan_tree ".agentic/shared"
|
|
337
|
+
plan_tree "scripts/00.chat"
|
|
338
|
+
plan_public_harness_scripts
|
|
339
|
+
echo
|
|
340
|
+
|
|
341
|
+
echo "Excluded source paths:"
|
|
342
|
+
echo "EXCLUDE commitLogs/"
|
|
343
|
+
echo "EXCLUDE .agentic/01.harness/"
|
|
344
|
+
echo "EXCLUDE scripts/00.chat/upstream/"
|
|
345
|
+
echo "EXCLUDE docs/"
|
|
346
|
+
echo "EXCLUDE public repo templates, local transcripts, and local worktree paths"
|
|
347
|
+
echo
|
|
348
|
+
|
|
349
|
+
echo "Summary:"
|
|
350
|
+
echo "create: $CREATE_COUNT"
|
|
351
|
+
echo "same: $SAME_COUNT"
|
|
352
|
+
echo "patch: $PATCH_COUNT"
|
|
353
|
+
echo "conflicts: $CONFLICT_COUNT"
|
|
354
|
+
echo "package_conflicts: $PACKAGE_CONFLICTS"
|
|
355
|
+
echo "mode: $MODE"
|
|
356
|
+
|
|
357
|
+
if [ "$CONFLICT_COUNT" -gt 0 ]; then
|
|
358
|
+
exit 1
|
|
359
|
+
fi
|
|
360
|
+
|
|
361
|
+
copy_file() {
|
|
362
|
+
local source="$1"
|
|
363
|
+
local relative_path="$2"
|
|
364
|
+
local target="$TARGET_REPO/$relative_path"
|
|
365
|
+
|
|
366
|
+
mkdir -p "$(dirname "$target")"
|
|
367
|
+
cp "$source" "$target"
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
record_manifest() {
|
|
371
|
+
local kind="$1"
|
|
372
|
+
local value="$2"
|
|
373
|
+
|
|
374
|
+
printf '%s\t%s\n' "$kind" "$value" >> "$MANIFEST_OUTPUT"
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
patch_instruction_file() {
|
|
378
|
+
local relative_path="$1"
|
|
379
|
+
local target="$TARGET_REPO/$relative_path"
|
|
380
|
+
|
|
381
|
+
managed_block >> "$target"
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
merge_package_json() {
|
|
385
|
+
local target_package="$TARGET_REPO/package.json"
|
|
386
|
+
local template_package="$SOURCE_REPO/package.json"
|
|
387
|
+
|
|
388
|
+
node - "$target_package" "$template_package" <<'NODE'
|
|
389
|
+
const fs = require('fs');
|
|
390
|
+
const targetPath = process.argv[2];
|
|
391
|
+
const templatePath = process.argv[3];
|
|
392
|
+
|
|
393
|
+
const target = JSON.parse(fs.readFileSync(targetPath, 'utf8'));
|
|
394
|
+
const template = JSON.parse(fs.readFileSync(templatePath, 'utf8'));
|
|
395
|
+
|
|
396
|
+
target.scripts = target.scripts || {};
|
|
397
|
+
for (const [name, expected] of Object.entries(template.scripts || {})) {
|
|
398
|
+
if (!name.startsWith('chat:') && name !== 'chat') {
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
if (target.scripts[name] === undefined || target.scripts[name] === expected) {
|
|
402
|
+
target.scripts[name] = expected;
|
|
403
|
+
} else {
|
|
404
|
+
throw new Error(`conflicting script during apply: ${name}`);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
fs.writeFileSync(targetPath, `${JSON.stringify(target, null, 2)}\n`);
|
|
409
|
+
NODE
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
record_added_package_scripts() {
|
|
413
|
+
sed -n 's/^PACKAGE_ADD_SCRIPT \([^ ]*\) .*/\1/p' "$PACKAGE_OUTPUT" \
|
|
414
|
+
| while IFS= read -r script_name; do
|
|
415
|
+
[ -n "$script_name" ] || continue
|
|
416
|
+
record_manifest "package-script" "$script_name"
|
|
417
|
+
done
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
apply_plan() {
|
|
421
|
+
local action
|
|
422
|
+
local source
|
|
423
|
+
local relative_path
|
|
424
|
+
|
|
425
|
+
echo
|
|
426
|
+
echo "Applying clean plan..."
|
|
427
|
+
|
|
428
|
+
while IFS=$'\t' read -r action source relative_path; do
|
|
429
|
+
case "$action" in
|
|
430
|
+
CREATE)
|
|
431
|
+
copy_file "$source" "$relative_path"
|
|
432
|
+
record_manifest "create" "$relative_path"
|
|
433
|
+
echo "APPLIED_CREATE $relative_path"
|
|
434
|
+
;;
|
|
435
|
+
CREATE_PACKAGE)
|
|
436
|
+
copy_file "$source" "$relative_path"
|
|
437
|
+
record_manifest "create" "$relative_path"
|
|
438
|
+
echo "APPLIED_CREATE package.json"
|
|
439
|
+
;;
|
|
440
|
+
MERGE_PACKAGE)
|
|
441
|
+
merge_package_json
|
|
442
|
+
record_added_package_scripts
|
|
443
|
+
echo "APPLIED_MERGE package.json"
|
|
444
|
+
;;
|
|
445
|
+
PATCH_BLOCK)
|
|
446
|
+
patch_instruction_file "$relative_path"
|
|
447
|
+
record_manifest "patch-block" "$relative_path"
|
|
448
|
+
echo "APPLIED_PATCH_BLOCK $relative_path"
|
|
449
|
+
;;
|
|
450
|
+
SAME|SAME_BLOCK)
|
|
451
|
+
:
|
|
452
|
+
;;
|
|
453
|
+
*)
|
|
454
|
+
echo "ERROR: unexpected action in clean plan: $action" >&2
|
|
455
|
+
exit 1
|
|
456
|
+
;;
|
|
457
|
+
esac
|
|
458
|
+
done < "$FILE_ACTIONS"
|
|
459
|
+
|
|
460
|
+
echo "Apply completed."
|
|
461
|
+
|
|
462
|
+
mkdir -p "$(dirname "$MANIFEST_PATH")"
|
|
463
|
+
cp "$MANIFEST_OUTPUT" "$MANIFEST_PATH"
|
|
464
|
+
echo "Wrote install manifest: ${MANIFEST_PATH#$TARGET_REPO/}"
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if [ "$MODE" = "apply" ]; then
|
|
468
|
+
apply_plan
|
|
469
|
+
fi
|
|
470
|
+
|
|
471
|
+
stage_install_paths() {
|
|
472
|
+
local kind
|
|
473
|
+
local value
|
|
474
|
+
local staged_package_json="no"
|
|
475
|
+
|
|
476
|
+
while IFS=$'\t' read -r kind value; do
|
|
477
|
+
case "$kind" in
|
|
478
|
+
create|patch-block)
|
|
479
|
+
git -C "$TARGET_REPO" add -- "$value"
|
|
480
|
+
;;
|
|
481
|
+
package-script)
|
|
482
|
+
if [ "$staged_package_json" = "no" ]; then
|
|
483
|
+
git -C "$TARGET_REPO" add -- package.json
|
|
484
|
+
staged_package_json="yes"
|
|
485
|
+
fi
|
|
486
|
+
;;
|
|
487
|
+
esac
|
|
488
|
+
done < "$MANIFEST_OUTPUT"
|
|
489
|
+
|
|
490
|
+
git -C "$TARGET_REPO" add -- .llm-workbench/install-manifest.tsv
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
if [ "$INIT_COMMIT" = "yes" ] && [ "$MODE" = "apply" ]; then
|
|
494
|
+
echo
|
|
495
|
+
echo "Creating install commit..."
|
|
496
|
+
stage_install_paths
|
|
497
|
+
if ! git -C "$TARGET_REPO" diff --cached --quiet; then
|
|
498
|
+
git -C "$TARGET_REPO" commit -m "Install llm-workbench harness"
|
|
499
|
+
echo "Install commit created."
|
|
500
|
+
else
|
|
501
|
+
echo "No install changes to commit."
|
|
502
|
+
fi
|
|
503
|
+
fi
|