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,416 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# agentic-artifact:
|
|
5
|
+
# schema: agentic-artifact/v2
|
|
6
|
+
# id: harness.script.check-deterministic-process-drift
|
|
7
|
+
# version: 1
|
|
8
|
+
# status: active
|
|
9
|
+
# layer: 01.harness
|
|
10
|
+
# domain: governance
|
|
11
|
+
# disciplines:
|
|
12
|
+
# - agentic
|
|
13
|
+
# kind: script
|
|
14
|
+
# purpose: Flag process prose that should likely be represented as deterministic scripts
|
|
15
|
+
# or gates.
|
|
16
|
+
# portability:
|
|
17
|
+
# class: required
|
|
18
|
+
# targets:
|
|
19
|
+
# - llm-workbench
|
|
20
|
+
# used_by:
|
|
21
|
+
# - id: chat.checklists.before-commit
|
|
22
|
+
# path: .agentic/00.chat/checklists/before-commit.md
|
|
23
|
+
# - id: shared.workflows.change-shared-process
|
|
24
|
+
# path: .agentic/shared/workflows/change-shared-process.md
|
|
25
|
+
# effects:
|
|
26
|
+
# - read-only
|
|
27
|
+
|
|
28
|
+
MODE=""
|
|
29
|
+
COMMIT_SHA=""
|
|
30
|
+
PATH_ARGS=()
|
|
31
|
+
|
|
32
|
+
usage() {
|
|
33
|
+
cat <<'EOF'
|
|
34
|
+
Usage:
|
|
35
|
+
check-deterministic-process-drift.sh --staged
|
|
36
|
+
check-deterministic-process-drift.sh --commit <sha>
|
|
37
|
+
check-deterministic-process-drift.sh --paths <path> [path...]
|
|
38
|
+
check-deterministic-process-drift.sh --all
|
|
39
|
+
|
|
40
|
+
Flags harness process prose that looks like it could be represented by a
|
|
41
|
+
deterministic script or gate. The check suggests changes only; it never rewrites
|
|
42
|
+
files.
|
|
43
|
+
|
|
44
|
+
Allow intentional governance prose with:
|
|
45
|
+
<!-- deterministic-check: allow reason="requires human approval judgment" -->
|
|
46
|
+
EOF
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
while [ $# -gt 0 ]; do
|
|
50
|
+
case "$1" in
|
|
51
|
+
--staged|--all)
|
|
52
|
+
if [ -n "$MODE" ]; then
|
|
53
|
+
echo "ERROR: choose exactly one mode." >&2
|
|
54
|
+
exit 2
|
|
55
|
+
fi
|
|
56
|
+
MODE="${1#--}"
|
|
57
|
+
shift
|
|
58
|
+
;;
|
|
59
|
+
--commit)
|
|
60
|
+
if [ -n "$MODE" ]; then
|
|
61
|
+
echo "ERROR: choose exactly one mode." >&2
|
|
62
|
+
exit 2
|
|
63
|
+
fi
|
|
64
|
+
if [ $# -lt 2 ] || [ -z "${2:-}" ]; then
|
|
65
|
+
echo "ERROR: --commit requires a commit sha." >&2
|
|
66
|
+
exit 2
|
|
67
|
+
fi
|
|
68
|
+
MODE="commit"
|
|
69
|
+
COMMIT_SHA="$2"
|
|
70
|
+
shift 2
|
|
71
|
+
;;
|
|
72
|
+
--paths)
|
|
73
|
+
if [ -n "$MODE" ]; then
|
|
74
|
+
echo "ERROR: choose exactly one mode." >&2
|
|
75
|
+
exit 2
|
|
76
|
+
fi
|
|
77
|
+
MODE="paths"
|
|
78
|
+
shift
|
|
79
|
+
if [ $# -eq 0 ]; then
|
|
80
|
+
echo "ERROR: --paths requires at least one path." >&2
|
|
81
|
+
exit 2
|
|
82
|
+
fi
|
|
83
|
+
while [ $# -gt 0 ]; do
|
|
84
|
+
PATH_ARGS+=("$1")
|
|
85
|
+
shift
|
|
86
|
+
done
|
|
87
|
+
;;
|
|
88
|
+
--help|-h)
|
|
89
|
+
usage
|
|
90
|
+
exit 0
|
|
91
|
+
;;
|
|
92
|
+
*)
|
|
93
|
+
echo "ERROR: unknown argument: $1" >&2
|
|
94
|
+
usage >&2
|
|
95
|
+
exit 2
|
|
96
|
+
;;
|
|
97
|
+
esac
|
|
98
|
+
done
|
|
99
|
+
|
|
100
|
+
if [ -z "$MODE" ]; then
|
|
101
|
+
usage >&2
|
|
102
|
+
exit 2
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
is_scannable_path() {
|
|
106
|
+
local path="$1"
|
|
107
|
+
|
|
108
|
+
case "$path" in
|
|
109
|
+
docs/harness/architecture/adrs/*.md)
|
|
110
|
+
return 1
|
|
111
|
+
;;
|
|
112
|
+
AGENTS.md|.agentic/*.md|.agentic/**/*.md|docs/harness/*.md|docs/harness/**/*.md)
|
|
113
|
+
return 0
|
|
114
|
+
;;
|
|
115
|
+
*)
|
|
116
|
+
return 1
|
|
117
|
+
;;
|
|
118
|
+
esac
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
collect_all_paths() {
|
|
122
|
+
{
|
|
123
|
+
[ -f AGENTS.md ] && printf '%s\n' AGENTS.md
|
|
124
|
+
[ -d .agentic ] && find .agentic -type f
|
|
125
|
+
[ -d docs/harness ] && find docs/harness -type f
|
|
126
|
+
} | sort -u
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
collect_paths_from_args() {
|
|
130
|
+
local path
|
|
131
|
+
|
|
132
|
+
for path in "${PATH_ARGS[@]}"; do
|
|
133
|
+
if [ -d "$path" ]; then
|
|
134
|
+
find "$path" -type f
|
|
135
|
+
elif [ -f "$path" ]; then
|
|
136
|
+
printf '%s\n' "$path"
|
|
137
|
+
else
|
|
138
|
+
echo "WARN: path does not exist, skipping: $path" >&2
|
|
139
|
+
fi
|
|
140
|
+
done | sort -u
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
scan_file_content() {
|
|
144
|
+
local source_path="$1"
|
|
145
|
+
local content_file="$2"
|
|
146
|
+
|
|
147
|
+
awk -v source="$source_path" '
|
|
148
|
+
function finding(type, text) {
|
|
149
|
+
printf "%s:%d\n", source, NR
|
|
150
|
+
printf " Type: %s\n", type
|
|
151
|
+
printf " Text: %s\n", text
|
|
152
|
+
printf " Suggestion: Move deterministic checks into a script or gate, or add an allow marker with a reason when the prose is intentionally human-governed.\n\n"
|
|
153
|
+
findings++
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/```/ {
|
|
157
|
+
in_code = !in_code
|
|
158
|
+
next
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/deterministic-check: allow/ {
|
|
162
|
+
if ($0 !~ /reason="[^"]+"/) {
|
|
163
|
+
finding("allow-marker-missing-reason", $0)
|
|
164
|
+
}
|
|
165
|
+
allow_until = NR + 8
|
|
166
|
+
next
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
in_code {
|
|
170
|
+
next
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
NR <= allow_until {
|
|
174
|
+
next
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
{
|
|
178
|
+
line = $0
|
|
179
|
+
lower = tolower(line)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
lower ~ /(check|verify|ensure|confirm) that / {
|
|
183
|
+
finding("scriptable-check", line)
|
|
184
|
+
next
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
lower ~ /(current branch contains|file exists|files exist|path exists|if .*missing|if .*dirty|if .*exists|when .*missing|must contain)/ {
|
|
188
|
+
finding("scriptable-condition", line)
|
|
189
|
+
next
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
lower ~ /(run .*(and|then).*(inspect|check|verify|confirm)|rerun .*(checklist|gate|script))/ {
|
|
193
|
+
finding("scriptable-sequence", line)
|
|
194
|
+
next
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
lower ~ /^[-0-9. ]+(check|verify|ensure|confirm|inspect) / {
|
|
198
|
+
procedural_bullets++
|
|
199
|
+
if (procedural_bullets == 3) {
|
|
200
|
+
finding("scriptable-enumeration", "Three or more nearby checklist items begin with deterministic process verbs.")
|
|
201
|
+
}
|
|
202
|
+
next
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
line !~ /^[-0-9. ]/ {
|
|
206
|
+
procedural_bullets = 0
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
END {
|
|
210
|
+
exit findings > 0 ? 1 : 0
|
|
211
|
+
}
|
|
212
|
+
' "$content_file"
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
scan_worktree_file() {
|
|
216
|
+
local path="$1"
|
|
217
|
+
local result
|
|
218
|
+
|
|
219
|
+
if ! is_scannable_path "$path"; then
|
|
220
|
+
return 0
|
|
221
|
+
fi
|
|
222
|
+
|
|
223
|
+
set +e
|
|
224
|
+
scan_file_content "$path" "$path"
|
|
225
|
+
result=$?
|
|
226
|
+
set -e
|
|
227
|
+
return "$result"
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
scan_git_blob() {
|
|
231
|
+
local ref="$1"
|
|
232
|
+
local path="$2"
|
|
233
|
+
local tmp
|
|
234
|
+
|
|
235
|
+
if ! is_scannable_path "$path"; then
|
|
236
|
+
return 0
|
|
237
|
+
fi
|
|
238
|
+
|
|
239
|
+
tmp="$(mktemp)"
|
|
240
|
+
if ! git show "${ref}:${path}" > "$tmp" 2>/dev/null; then
|
|
241
|
+
rm -f "$tmp"
|
|
242
|
+
return 0
|
|
243
|
+
fi
|
|
244
|
+
|
|
245
|
+
set +e
|
|
246
|
+
scan_file_content "$path" "$tmp"
|
|
247
|
+
local result=$?
|
|
248
|
+
set -e
|
|
249
|
+
rm -f "$tmp"
|
|
250
|
+
return "$result"
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
scan_diff_added_lines() {
|
|
254
|
+
local source_path="$1"
|
|
255
|
+
local diff_file="$2"
|
|
256
|
+
|
|
257
|
+
if ! is_scannable_path "$source_path"; then
|
|
258
|
+
return 0
|
|
259
|
+
fi
|
|
260
|
+
|
|
261
|
+
awk -v source="$source_path" '
|
|
262
|
+
function finding(type, text) {
|
|
263
|
+
printf "%s:%d\n", source, line_no
|
|
264
|
+
printf " Type: %s\n", type
|
|
265
|
+
printf " Text: %s\n", text
|
|
266
|
+
printf " Suggestion: Move deterministic checks into a script or gate, or add an allow marker with a reason when the prose is intentionally human-governed.\n\n"
|
|
267
|
+
findings++
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function scan_added_line(text, lower) {
|
|
271
|
+
if (text ~ /```/) {
|
|
272
|
+
in_code = !in_code
|
|
273
|
+
return
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (text ~ /deterministic-check: allow/) {
|
|
277
|
+
if (text !~ /reason="[^"]+"/) {
|
|
278
|
+
finding("allow-marker-missing-reason", text)
|
|
279
|
+
}
|
|
280
|
+
allow_until = line_no + 8
|
|
281
|
+
return
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (in_code || line_no <= allow_until) {
|
|
285
|
+
return
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
lower = tolower(text)
|
|
289
|
+
|
|
290
|
+
if (lower ~ /(check|verify|ensure|confirm) that /) {
|
|
291
|
+
finding("scriptable-check", text)
|
|
292
|
+
return
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (lower ~ /(current branch contains|file exists|files exist|path exists|if .*missing|if .*dirty|if .*exists|when .*missing|must contain)/) {
|
|
296
|
+
finding("scriptable-condition", text)
|
|
297
|
+
return
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (lower ~ /(run .*(and|then).*(inspect|check|verify|confirm)|rerun .*(checklist|gate|script))/) {
|
|
301
|
+
finding("scriptable-sequence", text)
|
|
302
|
+
return
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (lower ~ /^[-0-9. ]+(check|verify|ensure|confirm|inspect) /) {
|
|
306
|
+
procedural_bullets++
|
|
307
|
+
if (procedural_bullets == 3) {
|
|
308
|
+
finding("scriptable-enumeration", "Three or more nearby added checklist items begin with deterministic process verbs.")
|
|
309
|
+
}
|
|
310
|
+
return
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (text !~ /^[-0-9. ]/) {
|
|
314
|
+
procedural_bullets = 0
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/^@@ / {
|
|
319
|
+
hunk = $0
|
|
320
|
+
sub(/^.* \+/, "", hunk)
|
|
321
|
+
sub(/ .*/, "", hunk)
|
|
322
|
+
split(hunk, parts, ",")
|
|
323
|
+
line_no = parts[1] - 1
|
|
324
|
+
next
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/^\+\+\+ / {
|
|
328
|
+
next
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/^\+/ {
|
|
332
|
+
line_no++
|
|
333
|
+
scan_added_line(substr($0, 2))
|
|
334
|
+
next
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/^ / {
|
|
338
|
+
line_no++
|
|
339
|
+
next
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
END {
|
|
343
|
+
exit findings > 0 ? 1 : 0
|
|
344
|
+
}
|
|
345
|
+
' "$diff_file"
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
TOTAL_FINDINGS=0
|
|
349
|
+
|
|
350
|
+
scan_path_list() {
|
|
351
|
+
local path
|
|
352
|
+
|
|
353
|
+
while IFS= read -r path; do
|
|
354
|
+
if [ -z "${path// }" ]; then
|
|
355
|
+
continue
|
|
356
|
+
fi
|
|
357
|
+
|
|
358
|
+
if ! scan_worktree_file "$path"; then
|
|
359
|
+
TOTAL_FINDINGS=$((TOTAL_FINDINGS + 1))
|
|
360
|
+
fi
|
|
361
|
+
done
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
case "$MODE" in
|
|
365
|
+
staged)
|
|
366
|
+
while IFS= read -r path; do
|
|
367
|
+
if [ -z "${path// }" ]; then
|
|
368
|
+
continue
|
|
369
|
+
fi
|
|
370
|
+
|
|
371
|
+
tmp="$(mktemp)"
|
|
372
|
+
git diff --cached -U0 --no-ext-diff -- "$path" > "$tmp"
|
|
373
|
+
if ! scan_diff_added_lines "$path" "$tmp"; then
|
|
374
|
+
TOTAL_FINDINGS=$((TOTAL_FINDINGS + 1))
|
|
375
|
+
fi
|
|
376
|
+
rm -f "$tmp"
|
|
377
|
+
done < <(git diff --cached --name-only --diff-filter=ACMR)
|
|
378
|
+
;;
|
|
379
|
+
commit)
|
|
380
|
+
if ! git rev-parse --verify --quiet "$COMMIT_SHA" >/dev/null; then
|
|
381
|
+
echo "ERROR: commit does not exist: $COMMIT_SHA" >&2
|
|
382
|
+
exit 2
|
|
383
|
+
fi
|
|
384
|
+
|
|
385
|
+
while IFS= read -r path; do
|
|
386
|
+
if [ -z "${path// }" ]; then
|
|
387
|
+
continue
|
|
388
|
+
fi
|
|
389
|
+
|
|
390
|
+
tmp="$(mktemp)"
|
|
391
|
+
git show --format= --unified=0 --no-ext-diff "$COMMIT_SHA" -- "$path" > "$tmp"
|
|
392
|
+
if ! scan_diff_added_lines "$path" "$tmp"; then
|
|
393
|
+
TOTAL_FINDINGS=$((TOTAL_FINDINGS + 1))
|
|
394
|
+
fi
|
|
395
|
+
rm -f "$tmp"
|
|
396
|
+
done < <(git diff-tree --no-commit-id --name-only -r "$COMMIT_SHA")
|
|
397
|
+
;;
|
|
398
|
+
paths)
|
|
399
|
+
scan_path_list < <(collect_paths_from_args)
|
|
400
|
+
;;
|
|
401
|
+
all)
|
|
402
|
+
scan_path_list < <(collect_all_paths)
|
|
403
|
+
;;
|
|
404
|
+
*)
|
|
405
|
+
echo "ERROR: unsupported mode: $MODE" >&2
|
|
406
|
+
exit 2
|
|
407
|
+
;;
|
|
408
|
+
esac
|
|
409
|
+
|
|
410
|
+
if [ "$TOTAL_FINDINGS" -gt 0 ]; then
|
|
411
|
+
echo "ERROR: deterministic process drift found." >&2
|
|
412
|
+
echo "Review the suggestions, then either move deterministic procedure into a script/gate or add an allow marker with a reason." >&2
|
|
413
|
+
exit 1
|
|
414
|
+
fi
|
|
415
|
+
|
|
416
|
+
echo "No deterministic process drift found."
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# agentic-artifact:
|
|
5
|
+
# schema: agentic-artifact/v2
|
|
6
|
+
# id: harness.script.check-governed-script-command-drift
|
|
7
|
+
# version: 1
|
|
8
|
+
# status: active
|
|
9
|
+
# layer: 01.harness
|
|
10
|
+
# domain: governance
|
|
11
|
+
# disciplines:
|
|
12
|
+
# - agentic
|
|
13
|
+
# kind: script
|
|
14
|
+
# purpose: Flag approval-sensitive governed script references that bypass the governed
|
|
15
|
+
# runner.
|
|
16
|
+
# portability:
|
|
17
|
+
# class: required
|
|
18
|
+
# targets:
|
|
19
|
+
# - llm-workbench
|
|
20
|
+
# used_by:
|
|
21
|
+
# - id: chat.script.session-log.prepare-chat-session-before-commit
|
|
22
|
+
# path: scripts/00.chat/session-log/prepare-chat-session-before-commit/script.sh
|
|
23
|
+
# - id: harness.standards.governed-script-permissions
|
|
24
|
+
# effects:
|
|
25
|
+
# - read-only
|
|
26
|
+
|
|
27
|
+
usage() {
|
|
28
|
+
cat <<'EOF'
|
|
29
|
+
Usage:
|
|
30
|
+
check-governed-script-command-drift.sh [--paths <path>...]
|
|
31
|
+
|
|
32
|
+
Flags active agent-facing artifacts that show approval-sensitive governed
|
|
33
|
+
scripts without routing through the governed runner.
|
|
34
|
+
EOF
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
PATH_ARGS=()
|
|
38
|
+
|
|
39
|
+
while [ $# -gt 0 ]; do
|
|
40
|
+
case "$1" in
|
|
41
|
+
--paths)
|
|
42
|
+
shift
|
|
43
|
+
if [ $# -eq 0 ]; then
|
|
44
|
+
echo "ERROR: --paths requires at least one path." >&2
|
|
45
|
+
exit 2
|
|
46
|
+
fi
|
|
47
|
+
while [ $# -gt 0 ]; do
|
|
48
|
+
PATH_ARGS+=("$1")
|
|
49
|
+
shift
|
|
50
|
+
done
|
|
51
|
+
;;
|
|
52
|
+
-h|--help)
|
|
53
|
+
usage
|
|
54
|
+
exit 0
|
|
55
|
+
;;
|
|
56
|
+
*)
|
|
57
|
+
echo "ERROR: unknown argument: $1" >&2
|
|
58
|
+
usage >&2
|
|
59
|
+
exit 2
|
|
60
|
+
;;
|
|
61
|
+
esac
|
|
62
|
+
done
|
|
63
|
+
|
|
64
|
+
collect_default_paths() {
|
|
65
|
+
{
|
|
66
|
+
if [ -f AGENTS.md ]; then
|
|
67
|
+
printf '%s\n' AGENTS.md
|
|
68
|
+
fi
|
|
69
|
+
if [ -d .agentic ]; then
|
|
70
|
+
find .agentic -type f
|
|
71
|
+
fi
|
|
72
|
+
if [ -d docs/harness ]; then
|
|
73
|
+
find docs/harness -type f
|
|
74
|
+
fi
|
|
75
|
+
} | sort -u
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
collect_paths_from_args() {
|
|
79
|
+
local path
|
|
80
|
+
|
|
81
|
+
for path in "${PATH_ARGS[@]}"; do
|
|
82
|
+
if [ -d "$path" ]; then
|
|
83
|
+
find "$path" -type f
|
|
84
|
+
elif [ -f "$path" ]; then
|
|
85
|
+
printf '%s\n' "$path"
|
|
86
|
+
else
|
|
87
|
+
echo "WARN: path does not exist, skipping: $path" >&2
|
|
88
|
+
fi
|
|
89
|
+
done | sort -u
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
is_scannable_path() {
|
|
93
|
+
local path="$1"
|
|
94
|
+
|
|
95
|
+
case "$path" in
|
|
96
|
+
docs/harness/architecture/adrs/*.md)
|
|
97
|
+
return 1
|
|
98
|
+
;;
|
|
99
|
+
AGENTS.md|.agentic/*.md|.agentic/**/*.md|docs/harness/*.md|docs/harness/**/*.md)
|
|
100
|
+
return 0
|
|
101
|
+
;;
|
|
102
|
+
*)
|
|
103
|
+
return 1
|
|
104
|
+
;;
|
|
105
|
+
esac
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
APPROVED_SCRIPTS="$(bash scripts/01.harness/run-governed-script.sh --list \
|
|
109
|
+
| awk '$1 == "approved" { print $2 }')"
|
|
110
|
+
|
|
111
|
+
if [ -z "${APPROVED_SCRIPTS// }" ]; then
|
|
112
|
+
echo "ERROR: governed runner returned no approved scripts." >&2
|
|
113
|
+
exit 1
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
if [ "${#PATH_ARGS[@]}" -gt 0 ]; then
|
|
117
|
+
PATHS="$(collect_paths_from_args)"
|
|
118
|
+
else
|
|
119
|
+
PATHS="$(collect_default_paths)"
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
FINDINGS=0
|
|
123
|
+
|
|
124
|
+
scan_file() {
|
|
125
|
+
local path="$1"
|
|
126
|
+
local script
|
|
127
|
+
local line_no
|
|
128
|
+
local text
|
|
129
|
+
local previous_text=""
|
|
130
|
+
|
|
131
|
+
is_scannable_path "$path" || return 0
|
|
132
|
+
|
|
133
|
+
while IFS=: read -r line_no text; do
|
|
134
|
+
[ -n "$line_no" ] || continue
|
|
135
|
+
for script in $APPROVED_SCRIPTS; do
|
|
136
|
+
case "$text" in
|
|
137
|
+
*"$script"*)
|
|
138
|
+
case "$text" in
|
|
139
|
+
*"bash $script"*)
|
|
140
|
+
;;
|
|
141
|
+
*)
|
|
142
|
+
continue
|
|
143
|
+
;;
|
|
144
|
+
esac
|
|
145
|
+
case "$text" in
|
|
146
|
+
*"bash scripts/01.harness/run-governed-script.sh --approved-action $script"*)
|
|
147
|
+
;;
|
|
148
|
+
*)
|
|
149
|
+
case "$path:$text" in
|
|
150
|
+
scripts/shared/*:*"exec bash $script"*)
|
|
151
|
+
continue
|
|
152
|
+
;;
|
|
153
|
+
esac
|
|
154
|
+
case "$previous_text" in
|
|
155
|
+
*"bash scripts/01.harness/run-governed-script.sh --approved-action \\"*)
|
|
156
|
+
continue
|
|
157
|
+
;;
|
|
158
|
+
esac
|
|
159
|
+
printf '%s:%s\n' "$path" "$line_no"
|
|
160
|
+
printf ' Type: direct-approved-governed-script\n'
|
|
161
|
+
printf ' Text: %s\n' "$text"
|
|
162
|
+
printf ' Suggestion: Use bash scripts/01.harness/run-governed-script.sh --approved-action %s\n\n' "$script"
|
|
163
|
+
FINDINGS=$((FINDINGS + 1))
|
|
164
|
+
break
|
|
165
|
+
;;
|
|
166
|
+
esac
|
|
167
|
+
;;
|
|
168
|
+
esac
|
|
169
|
+
done
|
|
170
|
+
previous_text="$text"
|
|
171
|
+
done < <(grep -n 'scripts/' "$path" || true)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
while IFS= read -r path; do
|
|
175
|
+
[ -n "$path" ] || continue
|
|
176
|
+
scan_file "$path"
|
|
177
|
+
done <<< "$PATHS"
|
|
178
|
+
|
|
179
|
+
if [ "$FINDINGS" -gt 0 ]; then
|
|
180
|
+
echo "Governed script command drift found: $FINDINGS finding(s)." >&2
|
|
181
|
+
exit 1
|
|
182
|
+
fi
|
|
183
|
+
|
|
184
|
+
echo "No governed script command drift found."
|