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.
Files changed (170) hide show
  1. package/.agentic/00.chat/README.md +78 -0
  2. package/.agentic/00.chat/checklists/before-commit.md +195 -0
  3. package/.agentic/00.chat/checklists/llm-workbench-public-beta.md +94 -0
  4. package/.agentic/00.chat/commands/README.md +108 -0
  5. package/.agentic/00.chat/migration-plan.md +132 -0
  6. package/.agentic/00.chat/skills/session-summary.md +48 -0
  7. package/.agentic/00.chat/standards/llm-workbench-public-beta-contract.md +216 -0
  8. package/.agentic/00.chat/standards/main-refresh-conflict-types.md +358 -0
  9. package/.agentic/00.chat/workflows/README.md +40 -0
  10. package/.agentic/00.chat/workflows/bootstrap-chat-workbench-repo.md +212 -0
  11. package/.agentic/00.chat/workflows/chat-cleanup.md +102 -0
  12. package/.agentic/00.chat/workflows/chat-commit.md +56 -0
  13. package/.agentic/00.chat/workflows/chat-promote-to-main.md +169 -0
  14. package/.agentic/00.chat/workflows/chat-refresh-from-main.md +242 -0
  15. package/.agentic/00.chat/workflows/chat-reporting.md +69 -0
  16. package/.agentic/00.chat/workflows/chat-start.md +173 -0
  17. package/.agentic/00.chat/workflows/chat-upstream-reusable-lesson.md +123 -0
  18. package/.agentic/shared/standards/README.md +32 -0
  19. package/.agentic/shared/standards/upstream-repo-bootstrap.md +131 -0
  20. package/.agentic/shared/workflows/README.md +35 -0
  21. package/.agentic/shared/workflows/capability-resolution-workflow.md +189 -0
  22. package/.agentic/shared/workflows/change-shared-process.md +92 -0
  23. package/.cursor/rules/llm-workbench.mdc +17 -0
  24. package/.github/copilot-instructions.md +16 -0
  25. package/AGENTS.md +63 -0
  26. package/CLAUDE.md +16 -0
  27. package/CONTRIBUTING.md +57 -0
  28. package/LICENSE +21 -0
  29. package/LLM_WORKBENCH.md +17 -0
  30. package/README.md +98 -0
  31. package/SECURITY.md +44 -0
  32. package/bin/llm-workbench.js +672 -0
  33. package/docs/00.chat/README.md +47 -0
  34. package/docs/00.chat/llm-workbench-acceptance-matrix.md +55 -0
  35. package/docs/00.chat/script-layout.md +107 -0
  36. package/docs/adapting-to-your-repo.md +29 -0
  37. package/docs/concepts.md +38 -0
  38. package/docs/install.md +114 -0
  39. package/docs/public-beta-contract.md +45 -0
  40. package/docs/workflows.md +103 -0
  41. package/examples/minimal-repo/README.md +13 -0
  42. package/package.json +93 -0
  43. package/scripts/00.chat/README.md +46 -0
  44. package/scripts/00.chat/bootstrap/README.md +35 -0
  45. package/scripts/00.chat/bootstrap/audit-chat-bootstrap-file-set/README.md +39 -0
  46. package/scripts/00.chat/bootstrap/audit-chat-bootstrap-file-set/script.sh +213 -0
  47. package/scripts/00.chat/closeout/README.md +30 -0
  48. package/scripts/00.chat/closeout/build-closeout-prompt/README.md +35 -0
  49. package/scripts/00.chat/closeout/build-closeout-prompt/script.sh +124 -0
  50. package/scripts/00.chat/command/README.md +31 -0
  51. package/scripts/00.chat/command/close/README.md +30 -0
  52. package/scripts/00.chat/command/close/script.sh +25 -0
  53. package/scripts/00.chat/command/dispatcher/README.md +46 -0
  54. package/scripts/00.chat/command/dispatcher/script.sh +91 -0
  55. package/scripts/00.chat/command/dispatcher/smoke-test.sh +168 -0
  56. package/scripts/00.chat/command/new/README.md +32 -0
  57. package/scripts/00.chat/command/new/script.sh +28 -0
  58. package/scripts/00.chat/command/open-window/README.md +38 -0
  59. package/scripts/00.chat/command/open-window/script.sh +25 -0
  60. package/scripts/00.chat/command/package-scripts/README.md +34 -0
  61. package/scripts/00.chat/command/package-scripts/smoke-test.sh +113 -0
  62. package/scripts/00.chat/git/README.md +30 -0
  63. package/scripts/00.chat/git/cleanup-empty-chat-branches/README.md +36 -0
  64. package/scripts/00.chat/git/cleanup-empty-chat-branches/script.sh +243 -0
  65. package/scripts/00.chat/git/cleanup-empty-chat-branches/smoke-test.sh +136 -0
  66. package/scripts/00.chat/local-merge/README.md +30 -0
  67. package/scripts/00.chat/local-merge/list-active-chat-branches/README.md +29 -0
  68. package/scripts/00.chat/local-merge/list-active-chat-branches/script.sh +109 -0
  69. package/scripts/00.chat/local-merge/report-chat-branch-overlaps/README.md +29 -0
  70. package/scripts/00.chat/local-merge/report-chat-branch-overlaps/script.sh +142 -0
  71. package/scripts/00.chat/local-merge/verify-chat-ready-to-merge-local-main/README.md +33 -0
  72. package/scripts/00.chat/local-merge/verify-chat-ready-to-merge-local-main/script.sh +345 -0
  73. package/scripts/00.chat/local-merge/verify-chat-ready-to-merge-local-main/smoke-test.sh +244 -0
  74. package/scripts/00.chat/main-refresh/README.md +39 -0
  75. package/scripts/00.chat/main-refresh/apply-rehearsed-refresh/README.md +32 -0
  76. package/scripts/00.chat/main-refresh/apply-rehearsed-refresh/script.sh +198 -0
  77. package/scripts/00.chat/main-refresh/check-chat-is-current-with-main/README.md +30 -0
  78. package/scripts/00.chat/main-refresh/check-chat-is-current-with-main/script.sh +121 -0
  79. package/scripts/00.chat/main-refresh/classify-conflict/README.md +39 -0
  80. package/scripts/00.chat/main-refresh/classify-conflict/script.sh +169 -0
  81. package/scripts/00.chat/main-refresh/classify-conflict/smoke-test.sh +137 -0
  82. package/scripts/00.chat/main-refresh/classify-refresh-readiness/README.md +35 -0
  83. package/scripts/00.chat/main-refresh/classify-refresh-readiness/script.sh +171 -0
  84. package/scripts/00.chat/main-refresh/classify-refresh-readiness/smoke-test.sh +132 -0
  85. package/scripts/00.chat/main-refresh/rehearse-refresh-from-main/README.md +34 -0
  86. package/scripts/00.chat/main-refresh/rehearse-refresh-from-main/script.sh +124 -0
  87. package/scripts/00.chat/main-refresh/rehearse-refresh-from-main/smoke-test.sh +257 -0
  88. package/scripts/00.chat/main-refresh/show-main-update-status/README.md +31 -0
  89. package/scripts/00.chat/main-refresh/show-main-update-status/script.sh +73 -0
  90. package/scripts/00.chat/main-refresh/verify-conflict-audit/README.md +37 -0
  91. package/scripts/00.chat/main-refresh/verify-conflict-audit/script.sh +154 -0
  92. package/scripts/00.chat/main-refresh/verify-conflict-audit/smoke-test.sh +99 -0
  93. package/scripts/00.chat/metrics/README.md +35 -0
  94. package/scripts/00.chat/metrics/data/chat-pricing.json +107 -0
  95. package/scripts/00.chat/metrics/data/chat-pricing.schema.json +63 -0
  96. package/scripts/00.chat/metrics/estimate-chat-cost/README.md +40 -0
  97. package/scripts/00.chat/metrics/estimate-chat-cost/script.js +130 -0
  98. package/scripts/00.chat/migration/README.md +30 -0
  99. package/scripts/00.chat/migration/audit-chat-layer-migration/README.md +33 -0
  100. package/scripts/00.chat/migration/audit-chat-layer-migration/script.sh +127 -0
  101. package/scripts/00.chat/recovery/README.md +30 -0
  102. package/scripts/00.chat/recovery/import-active-paths-to-chat-worktree/README.md +76 -0
  103. package/scripts/00.chat/recovery/import-active-paths-to-chat-worktree/script.sh +212 -0
  104. package/scripts/00.chat/recovery/import-active-paths-to-chat-worktree/smoke-test.sh +162 -0
  105. package/scripts/00.chat/reporting/README.md +30 -0
  106. package/scripts/00.chat/reporting/generate-commit-log-summary/README.md +35 -0
  107. package/scripts/00.chat/reporting/generate-commit-log-summary/script.sh +299 -0
  108. package/scripts/00.chat/reporting/generate-commit-log-summary/smoke-test.sh +93 -0
  109. package/scripts/00.chat/reporting/report-chat-workspaces/README.md +32 -0
  110. package/scripts/00.chat/reporting/report-chat-workspaces/script.sh +82 -0
  111. package/scripts/00.chat/session-log/README.md +33 -0
  112. package/scripts/00.chat/session-log/check-commit-prerequisites/README.md +89 -0
  113. package/scripts/00.chat/session-log/check-commit-prerequisites/script.sh +121 -0
  114. package/scripts/00.chat/session-log/check-commit-prerequisites/smoke-test.sh +119 -0
  115. package/scripts/00.chat/session-log/check-commitlog-deletions/README.md +90 -0
  116. package/scripts/00.chat/session-log/check-commitlog-deletions/script.sh +131 -0
  117. package/scripts/00.chat/session-log/check-commitlog-deletions/smoke-test.sh +123 -0
  118. package/scripts/00.chat/session-log/checkpoint-chat-session-log/README.md +98 -0
  119. package/scripts/00.chat/session-log/checkpoint-chat-session-log/script.sh +126 -0
  120. package/scripts/00.chat/session-log/paths/README.md +38 -0
  121. package/scripts/00.chat/session-log/paths/lib.sh +133 -0
  122. package/scripts/00.chat/session-log/prepare-chat-session-before-commit/README.md +90 -0
  123. package/scripts/00.chat/session-log/prepare-chat-session-before-commit/script.sh +145 -0
  124. package/scripts/00.chat/session-log/read-current-chat-log/README.md +44 -0
  125. package/scripts/00.chat/session-log/read-current-chat-log/script.sh +92 -0
  126. package/scripts/00.chat/session-log/read-current-chat-log/smoke-test.sh +127 -0
  127. package/scripts/00.chat/session-log/record-chat-commit/README.md +133 -0
  128. package/scripts/00.chat/session-log/record-chat-commit/script.sh +394 -0
  129. package/scripts/00.chat/session-log/record-chat-commit/smoke-test.sh +227 -0
  130. package/scripts/00.chat/session-log/record-main-refresh-conflict/README.md +34 -0
  131. package/scripts/00.chat/session-log/record-main-refresh-conflict/script.sh +239 -0
  132. package/scripts/00.chat/session-log/rename-current-chat-log-folder/README.md +32 -0
  133. package/scripts/00.chat/session-log/rename-current-chat-log-folder/script.sh +112 -0
  134. package/scripts/00.chat/session-log/update-chat-log/README.md +32 -0
  135. package/scripts/00.chat/session-log/update-chat-log/script.sh +294 -0
  136. package/scripts/00.chat/startup/README.md +37 -0
  137. package/scripts/00.chat/startup/auto-start-missing-session/README.md +113 -0
  138. package/scripts/00.chat/startup/auto-start-missing-session/script.sh +54 -0
  139. package/scripts/00.chat/startup/resolve-current-chat-session/README.md +57 -0
  140. package/scripts/00.chat/startup/resolve-current-chat-session/script.sh +47 -0
  141. package/scripts/00.chat/startup/resolve-current-chat-session/smoke-test.sh +130 -0
  142. package/scripts/00.chat/startup/start-chat-session/README.md +197 -0
  143. package/scripts/00.chat/startup/start-chat-session/script.sh +330 -0
  144. package/scripts/00.chat/startup/start-chat-session/smoke-test.sh +182 -0
  145. package/scripts/00.chat/startup/start-new-chat/README.md +31 -0
  146. package/scripts/00.chat/startup/start-new-chat/script.sh +29 -0
  147. package/scripts/00.chat/transcript/README.md +36 -0
  148. package/scripts/00.chat/transcript/discover-codex-session-log/README.md +32 -0
  149. package/scripts/00.chat/transcript/discover-codex-session-log/script.sh +106 -0
  150. package/scripts/00.chat/transcript/register-codex-session-log/README.md +32 -0
  151. package/scripts/00.chat/transcript/register-codex-session-log/script.sh +115 -0
  152. package/scripts/00.chat/worktree/README.md +32 -0
  153. package/scripts/00.chat/worktree/check-write-location/README.md +87 -0
  154. package/scripts/00.chat/worktree/check-write-location/script.sh +95 -0
  155. package/scripts/00.chat/worktree/dirty-worktree-check/README.md +77 -0
  156. package/scripts/00.chat/worktree/dirty-worktree-check/script.sh +93 -0
  157. package/scripts/00.chat/worktree/ensure-chat-worktree/README.md +33 -0
  158. package/scripts/00.chat/worktree/ensure-chat-worktree/script.sh +132 -0
  159. package/scripts/00.chat/worktree/open-window/README.md +34 -0
  160. package/scripts/00.chat/worktree/open-window/script.sh +131 -0
  161. package/scripts/00.chat/worktree/paths/README.md +32 -0
  162. package/scripts/00.chat/worktree/paths/lib.sh +71 -0
  163. package/scripts/01.harness/artifact-metadata/check-headers/script.sh +522 -0
  164. package/scripts/01.harness/artifact-metadata/check-headers/smoke-test.sh +48 -0
  165. package/scripts/01.harness/check-deterministic-process-drift.sh +416 -0
  166. package/scripts/01.harness/check-governed-script-command-drift.sh +184 -0
  167. package/scripts/01.harness/run-governed-script.sh +178 -0
  168. package/scripts/install.sh +503 -0
  169. package/scripts/uninstall.sh +199 -0
  170. package/tests/smoke-test-install.sh +70 -0
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # agentic-artifact:
5
+ # schema: agentic-artifact/v2
6
+ # id: chat.script.session-log.read-current-chat-log.smoke-test
7
+ # version: 1
8
+ # status: active
9
+ # layer: 00.chat
10
+ # domain: session-log
11
+ # disciplines:
12
+ # - agentic
13
+ # kind: script
14
+ # purpose: Smoke test current chat metadata reads and recorded-session reuse guard.
15
+ # portability:
16
+ # class: reusable
17
+ # targets:
18
+ # - llm-workbench
19
+ # used_by:
20
+ # - id: chat.script.session-log.read-current-chat-log.readme
21
+ # path: scripts/00.chat/session-log/read-current-chat-log/README.md
22
+ # - id: chat.script.session-log.read-current-chat-log
23
+ # path: scripts/00.chat/session-log/read-current-chat-log/script.sh
24
+ # effects:
25
+ # - writes-files
26
+ # - branches
27
+ # - commits
28
+ fail() {
29
+ echo "FAIL: $*" >&2
30
+ exit 1
31
+ }
32
+
33
+ SOURCE_ROOT="$(git rev-parse --show-toplevel)"
34
+ TMP_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/read-current-chat-log-smoke.XXXXXX")"
35
+
36
+ cleanup() {
37
+ rm -rf "$TMP_ROOT"
38
+ }
39
+
40
+ trap cleanup EXIT
41
+
42
+ REPO="$TMP_ROOT/repo"
43
+ mkdir -p "$REPO"
44
+ git -C "$REPO" init --quiet --initial-branch=main
45
+
46
+ mkdir -p \
47
+ "$REPO/scripts/00.chat/session-log/read-current-chat-log" \
48
+ "$REPO/scripts/00.chat/session-log/paths" \
49
+ "$REPO/commitLogs/2026/jun/23/2026-06-23-18-00-empty-session" \
50
+ "$REPO/commitLogs/2026/jun/23/2026-06-23-18-05-recorded-session"
51
+
52
+ cp "$SOURCE_ROOT/scripts/00.chat/session-log/paths/lib.sh" "$REPO/scripts/00.chat/session-log/paths/lib.sh"
53
+ cp "$SOURCE_ROOT/scripts/00.chat/session-log/read-current-chat-log/script.sh" "$REPO/scripts/00.chat/session-log/read-current-chat-log/script.sh"
54
+ chmod +x "$REPO/scripts/00.chat/session-log/read-current-chat-log/script.sh"
55
+
56
+ cat > "$REPO/commitLogs/2026/jun/23/2026-06-23-18-00-empty-session/README.md" <<'EOF'
57
+ # Chat Session: empty
58
+
59
+ <!-- agentic-session
60
+ id: 2026-06-23-18-00-empty-session
61
+ task: empty
62
+ branch: chat/2026-06-23-18-00-empty-session
63
+ worktree:
64
+ chat_lifecycle_workflow: .agentic/00.chat/workflows/chat-start.md
65
+ latest_context_packet_id:
66
+ latest_context_packet_routing_summary:
67
+ latest_context_packet_at_utc:
68
+ status: ready
69
+ latest_commit_sha:
70
+ -->
71
+ EOF
72
+
73
+ cat > "$REPO/commitLogs/2026/jun/23/2026-06-23-18-05-recorded-session/README.md" <<'EOF'
74
+ # Chat Session: recorded
75
+
76
+ <!-- agentic-session
77
+ id: 2026-06-23-18-05-recorded-session
78
+ task: recorded
79
+ branch: chat/2026-06-23-18-05-recorded-session
80
+ worktree:
81
+ chat_lifecycle_workflow: .agentic/00.chat/workflows/chat-start.md
82
+ latest_context_packet_id: packet.selector-fixture.previous
83
+ latest_context_packet_routing_summary: previous prompt routed to 02.rag-rulebook discovery
84
+ latest_context_packet_at_utc: 2026-06-23T18:05:00Z
85
+ status: ready
86
+ latest_commit_sha: abc1234
87
+ -->
88
+ EOF
89
+
90
+ git -C "$REPO" add .
91
+ git -C "$REPO" -c user.name='Smoke Test' -c user.email='smoke@example.invalid' commit --quiet -m 'base'
92
+
93
+ git -C "$REPO" switch --quiet -c chat/2026-06-23-18-00-empty-session
94
+ bash -c 'cd "$1" && shift && "$@"' sh "$REPO" \
95
+ bash scripts/00.chat/session-log/read-current-chat-log/script.sh \
96
+ >"$TMP_ROOT/empty.out"
97
+
98
+ grep -q '^chat_lifecycle_workflow: .agentic/00.chat/workflows/chat-start.md$' "$TMP_ROOT/empty.out" \
99
+ || fail "empty session lifecycle metadata was not printed"
100
+
101
+ grep -q '^latest_context_packet_id:$' "$TMP_ROOT/empty.out" \
102
+ || fail "empty session context packet field was not printed"
103
+
104
+ if grep -Eq '^(layer|mode|workflow): ' "$TMP_ROOT/empty.out"; then
105
+ fail "empty session printed durable classification metadata"
106
+ fi
107
+
108
+ git -C "$REPO" switch --quiet main
109
+ git -C "$REPO" switch --quiet -c chat/2026-06-23-18-05-recorded-session
110
+
111
+ if bash -c 'cd "$1" && shift && "$@"' sh "$REPO" \
112
+ bash scripts/00.chat/session-log/read-current-chat-log/script.sh \
113
+ >"$TMP_ROOT/recorded.out" 2>&1; then
114
+ fail "recorded session metadata printed without explicit approval"
115
+ fi
116
+
117
+ grep -q '^ERROR: recorded-session-approval-required$' "$TMP_ROOT/recorded.out" \
118
+ || fail "recorded session did not require explicit approval"
119
+
120
+ bash -c 'cd "$1" && shift && "$@"' sh "$REPO" \
121
+ bash scripts/00.chat/session-log/read-current-chat-log/script.sh --allow-recorded-session \
122
+ >"$TMP_ROOT/recorded-allowed.out"
123
+
124
+ grep -q '^latest_commit_sha: abc1234$' "$TMP_ROOT/recorded-allowed.out" \
125
+ || fail "approved recorded session metadata was not printed"
126
+
127
+ echo "read-current-chat-log smoke test passed."
@@ -0,0 +1,133 @@
1
+ <!-- agentic-artifact:
2
+ schema: agentic-artifact/v2
3
+ id: chat.script.session-log.record-chat-commit.readme
4
+ version: 1
5
+ status: active
6
+ layer: 00.chat
7
+ domain: session-log
8
+ disciplines:
9
+ - agentic
10
+ kind: capability-readme
11
+ purpose: Explain how task commits are recorded into chat session logs and metrics.
12
+ portability:
13
+ class: required
14
+ targets:
15
+ - llm-workbench
16
+ used_by:
17
+ - id: chat.script.session-log.record-chat-commit
18
+ path: scripts/00.chat/session-log/record-chat-commit/script.sh
19
+ - id: chat.script.session-log.record-chat-commit.smoke-test
20
+ path: scripts/00.chat/session-log/record-chat-commit/smoke-test.sh
21
+ - id: harness.architecture.adr.0017-organize-scripts-by-owner-domain-and-capability
22
+ -->
23
+ # Record Chat Commit
24
+
25
+ `script.sh` records a completed task commit in the current chat session log.
26
+
27
+ It is the bridge between Git history and the durable chat record. The Git commit
28
+ contains the actual file changes. The session log explains what that commit
29
+ meant inside the conversation, when it happened, what it changed, and which chat
30
+ metrics were known at that boundary.
31
+
32
+ ## Mental Model
33
+
34
+ Chat work has two kinds of commits:
35
+
36
+ - task commits, which contain the real harness, product, or documentation
37
+ changes
38
+ - bookkeeping commits, which update the session log after the task commit is
39
+ recorded
40
+
41
+ `record-chat-commit` runs after the task commit exists. It edits the current
42
+ session log so the log points back to the commit SHA and captures the human
43
+ summary, ADR impact, chat duration, transcript-derived token estimate, and cost
44
+ estimate.
45
+
46
+ If recording the commit leaves only the session log dirty, the normal next step
47
+ is to checkpoint that bookkeeping separately with
48
+ `checkpoint-chat-session-log.sh`.
49
+
50
+ ## Inputs
51
+
52
+ ```bash
53
+ record-chat-commit.sh <sha> <message> <summary> [adr-impact]
54
+ ```
55
+
56
+ - `sha`: the task commit SHA to record.
57
+ - `message`: the task commit message.
58
+ - `summary`: a human explanation of what changed.
59
+ - `adr-impact`: optional note about whether the change is covered by existing
60
+ ADRs or needs follow-up.
61
+
62
+ The script must run on a `chat/*` branch so it can derive the session id and
63
+ find the matching session log.
64
+
65
+ ## Metrics
66
+
67
+ The script records chat metrics at the commit boundary.
68
+
69
+ Preferred transcript sources:
70
+
71
+ 1. `CHAT_TRANSCRIPT_BYTES`, when a caller supplies a byte count directly.
72
+ 2. Neutral session metadata such as `transcript_path` and `transcript_provider`.
73
+ 3. An explicit assistant adapter, for example `CHAT_TRANSCRIPT_PROVIDER=codex`
74
+ for Codex JSONL discovery.
75
+
76
+ If transcript metrics cannot be found, portable mode records the metric as
77
+ unavailable. Set `CHAT_TRANSCRIPT_METRICS_MODE=strict` when a workflow requires
78
+ exact transcript metrics before recording the commit.
79
+
80
+ When a numeric token estimate is available, the script calls
81
+ `scripts/00.chat/metrics/estimate-chat-cost/script.js` to record a cost estimate
82
+ and pricing basis.
83
+
84
+ ## What It Updates
85
+
86
+ The script updates:
87
+
88
+ - `## Commits`
89
+ - `## Activity Log`
90
+ - session metadata fields such as `latest_commit_at_utc`,
91
+ `latest_commit_sha`, `chat_duration`, `estimated_chat_tokens`,
92
+ `estimated_chat_cost`, and `estimated_chat_cost_basis`
93
+ - visible `## Session Metrics` fields
94
+
95
+ It also upgrades older `estimated_tokens` and `Final commit` fields to the newer
96
+ chat-specific names when encountered.
97
+
98
+ ## What This Does Not Do
99
+
100
+ - It does not create the task commit.
101
+ - It does not stage or commit the session-log bookkeeping.
102
+ - It does not push anything.
103
+ - It does not run the before-commit gate.
104
+ - It does not decide ADR disposition for the human.
105
+
106
+ ## Validation
107
+
108
+ `smoke-test.sh` creates a throwaway chat branch and session log, then verifies:
109
+
110
+ - missing transcript metrics fail clearly
111
+ - the legacy missing-metrics escape hatch records unavailable metrics
112
+ - assistant transcript discovery records provider, path, token estimate, cost,
113
+ and basis
114
+ - supplied transcript byte counts override discovery
115
+ - session-log file size is not used as a token source
116
+
117
+ Run the canonical smoke test with:
118
+
119
+ ```bash
120
+ bash scripts/00.chat/session-log/record-chat-commit/smoke-test.sh
121
+ ```
122
+
123
+ ## Compatibility
124
+
125
+ The governed runner still approves the old path:
126
+
127
+ ```bash
128
+ scripts/00.chat/session-log/record-chat-commit/script.sh
129
+ ```
130
+
131
+ That file is now a compatibility wrapper around the canonical implementation.
132
+ Commit checklists should keep using the approved shared path until the governed
133
+ runner allowlist policy is migrated.
@@ -0,0 +1,394 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # agentic-artifact:
5
+ # schema: agentic-artifact/v2
6
+ # id: chat.script.session-log.record-chat-commit
7
+ # version: 1
8
+ # status: active
9
+ # layer: 00.chat
10
+ # domain: session-log
11
+ # disciplines:
12
+ # - agentic
13
+ # kind: script
14
+ # purpose: Record a task commit and chat metrics in the current session log.
15
+ # portability:
16
+ # class: required
17
+ # targets:
18
+ # - llm-workbench
19
+ # used_by:
20
+ # - id: chat.script.session-log.record-chat-commit.readme
21
+ # path: scripts/00.chat/session-log/record-chat-commit/README.md
22
+ # - id: chat.script.session-log.record-chat-commit.smoke-test
23
+ # path: scripts/00.chat/session-log/record-chat-commit/smoke-test.sh
24
+ # effects:
25
+ # - writes-files
26
+
27
+ # shellcheck source=../paths/lib.sh
28
+ source "scripts/00.chat/session-log/paths/lib.sh"
29
+
30
+ usage() {
31
+ cat <<'EOF'
32
+ Usage:
33
+ record-chat-commit.sh <sha> <message> <summary> [adr-impact]
34
+
35
+ Records a commit in the current chat session log and updates rolling latest
36
+ commit session metrics.
37
+
38
+ The script estimates chat tokens from CHAT_TRANSCRIPT_BYTES when supplied.
39
+ Otherwise it uses neutral transcript_path metadata. Codex transcript discovery
40
+ is available when CHAT_TRANSCRIPT_PROVIDER=codex or LLM_WORKBENCH_TRANSCRIPT_PROVIDER=codex.
41
+
42
+ The script estimates chat cost from the resulting estimated chat-token count
43
+ when a pricing profile is available.
44
+ EOF
45
+ }
46
+
47
+ if [ $# -lt 3 ] || [ $# -gt 4 ]; then
48
+ usage >&2
49
+ exit 2
50
+ fi
51
+
52
+ COMMIT_SHA="$1"
53
+ COMMIT_MESSAGE="$2"
54
+ COMMIT_SUMMARY="$3"
55
+ ADR_IMPACT="${4:-covered by session ADR disposition}"
56
+
57
+ BRANCH="$(git branch --show-current)"
58
+
59
+ if ! SESSION_ID="$(chat_session_id_from_branch "$BRANCH")"; then
60
+ echo "ERROR: current branch is not a chat branch: $BRANCH" >&2
61
+ exit 1
62
+ fi
63
+
64
+ LOG_FILE="$(chat_log_file_for_session "$SESSION_ID")"
65
+
66
+ if [ ! -f "$LOG_FILE" ]; then
67
+ echo "ERROR: missing chat log: $LOG_FILE" >&2
68
+ exit 1
69
+ fi
70
+
71
+ COMMIT_AT_UTC="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
72
+
73
+ metadata_value() {
74
+ local key="$1"
75
+ sed -n "/<!-- agentic-session/,/-->/s/^${key}: //p" "$LOG_FILE" | head -n 1
76
+ }
77
+
78
+ format_duration_seconds() {
79
+ local total_seconds="$1"
80
+ local days hours minutes seconds
81
+
82
+ days=$((total_seconds / 86400))
83
+ hours=$(((total_seconds % 86400) / 3600))
84
+ minutes=$(((total_seconds % 3600) / 60))
85
+ seconds=$((total_seconds % 60))
86
+
87
+ printf '%ss (%02d:%02d:%02d:%02d)\n' \
88
+ "$total_seconds" "$days" "$hours" "$minutes" "$seconds"
89
+ }
90
+
91
+ insert_section_entry() {
92
+ local section="$1"
93
+ local entry="$2"
94
+ local tmp
95
+ local entry_tmp
96
+
97
+ tmp="$(mktemp)"
98
+ entry_tmp="$(mktemp)"
99
+ printf '%s\n' "$entry" > "$entry_tmp"
100
+
101
+ if awk -v section="$section" -v entry_path="$entry_tmp" '
102
+ BEGIN {
103
+ in_section = 0
104
+ inserted = 0
105
+ found = 0
106
+ entry = ""
107
+ while ((getline line < entry_path) > 0) {
108
+ entry = entry (entry == "" ? "" : "\n") line
109
+ }
110
+ close(entry_path)
111
+ }
112
+ $0 == section {
113
+ found = 1
114
+ in_section = 1
115
+ print
116
+ next
117
+ }
118
+ in_section && /^## / && inserted == 0 {
119
+ print ""
120
+ print entry
121
+ print ""
122
+ inserted = 1
123
+ in_section = 0
124
+ }
125
+ in_section && $0 == "- None recorded yet." {
126
+ next
127
+ }
128
+ {
129
+ print
130
+ }
131
+ END {
132
+ if (found == 0) {
133
+ print ""
134
+ print section
135
+ print ""
136
+ print entry
137
+ } else if (in_section == 1 && inserted == 0) {
138
+ print ""
139
+ print entry
140
+ }
141
+ }
142
+ ' "$LOG_FILE" > "$tmp"; then
143
+ mv "$tmp" "$LOG_FILE"
144
+ else
145
+ rm -f "$tmp"
146
+ rm -f "$entry_tmp"
147
+ return 1
148
+ fi
149
+
150
+ rm -f "$entry_tmp"
151
+ }
152
+
153
+ RAISED_AT_UTC="$(metadata_value "raised_at_utc")"
154
+ CHAT_DURATION="unknown"
155
+
156
+ if [ -n "${RAISED_AT_UTC// }" ]; then
157
+ if RAISED_SECONDS="$(date -u -d "$RAISED_AT_UTC" +"%s" 2>/dev/null)" &&
158
+ COMMIT_SECONDS="$(date -u -d "$COMMIT_AT_UTC" +"%s" 2>/dev/null)"; then
159
+ DURATION_SECONDS=$((COMMIT_SECONDS - RAISED_SECONDS))
160
+ if [ "$DURATION_SECONDS" -ge 0 ]; then
161
+ CHAT_DURATION="$(format_duration_seconds "$DURATION_SECONDS")"
162
+ fi
163
+ fi
164
+ fi
165
+
166
+ TRANSCRIPT_PROVIDER="${CHAT_TRANSCRIPT_PROVIDER:-${TRANSCRIPT_PROVIDER:-$(metadata_value "transcript_provider")}}"
167
+ TRANSCRIPT_PATH="${CHAT_TRANSCRIPT_PATH:-${TRANSCRIPT_PATH:-$(metadata_value "transcript_path")}}"
168
+ TRANSCRIPT_BYTES="${CHAT_TRANSCRIPT_BYTES:-${TRANSCRIPT_BYTES:-$(metadata_value "transcript_bytes")}}"
169
+ TRANSCRIPT_SOURCE="${CHAT_TRANSCRIPT_SOURCE:-${TRANSCRIPT_SOURCE:-$(metadata_value "transcript_source")}}"
170
+ TRANSCRIPT_METRICS_MODE="${CHAT_TRANSCRIPT_METRICS_MODE:-portable}"
171
+
172
+ if [ -n "${CODEX_SESSION_LOG_PATH:-}" ]; then
173
+ TRANSCRIPT_PROVIDER="${TRANSCRIPT_PROVIDER:-codex}"
174
+ TRANSCRIPT_PATH="$CODEX_SESSION_LOG_PATH"
175
+ fi
176
+
177
+ case "${TRANSCRIPT_PROVIDER:-${LLM_WORKBENCH_TRANSCRIPT_PROVIDER:-}}" in
178
+ codex)
179
+ if [ -z "${TRANSCRIPT_PATH// }" ]; then
180
+ TRANSCRIPT_PATH="$(bash scripts/00.chat/transcript/discover-codex-session-log/script.sh "$SESSION_ID" "$LOG_FILE" 2>/dev/null || true)"
181
+ fi
182
+ if [ -n "${TRANSCRIPT_PATH// }" ]; then
183
+ TRANSCRIPT_PROVIDER="codex"
184
+ fi
185
+ ;;
186
+ esac
187
+
188
+ if [ -z "${TRANSCRIPT_BYTES:-}" ] && [ -n "${TRANSCRIPT_PATH// }" ] && [ -f "$TRANSCRIPT_PATH" ]; then
189
+ TRANSCRIPT_BYTES="$(wc -c < "$TRANSCRIPT_PATH" | tr -d ' ')"
190
+ TRANSCRIPT_SOURCE="${TRANSCRIPT_SOURCE:-${TRANSCRIPT_PROVIDER:-transcript} path: ${TRANSCRIPT_PATH}}"
191
+ fi
192
+
193
+ if [ -n "${TRANSCRIPT_BYTES:-}" ]; then
194
+ case "$TRANSCRIPT_BYTES" in
195
+ ''|*[!0-9]*)
196
+ echo "ERROR: CHAT_TRANSCRIPT_BYTES must be a non-negative integer." >&2
197
+ exit 1
198
+ ;;
199
+ esac
200
+
201
+ TRANSCRIPT_PROVIDER="${TRANSCRIPT_PROVIDER:-manual}"
202
+ TRANSCRIPT_SOURCE="${TRANSCRIPT_SOURCE:-chat-supplied transcript byte count}"
203
+ CHAT_TOKEN_ESTIMATE="$(( (TRANSCRIPT_BYTES + 3) / 4 )) estimated from chat transcript bytes (${TRANSCRIPT_BYTES} bytes; source: ${TRANSCRIPT_SOURCE})"
204
+ elif [ -n "${ESTIMATED_CHAT_TOKENS:-}" ]; then
205
+ CHAT_TOKEN_ESTIMATE="$ESTIMATED_CHAT_TOKENS"
206
+ elif [ "$TRANSCRIPT_METRICS_MODE" = "strict" ] && [ "${ALLOW_MISSING_CHAT_TRANSCRIPT_METRICS:-}" != "yes" ]; then
207
+ echo "ERROR: missing chat transcript metrics." >&2
208
+ echo "Set CHAT_TRANSCRIPT_BYTES, CHAT_TRANSCRIPT_PATH, ESTIMATED_CHAT_TOKENS, or use portable transcript metrics mode." >&2
209
+ exit 1
210
+ else
211
+ CHAT_TOKEN_ESTIMATE="unavailable; transcript source not supplied by chat"
212
+ fi
213
+
214
+ CHAT_COST_ESTIMATE="unavailable; estimated chat tokens are unavailable"
215
+ CHAT_COST_BASIS="unavailable; estimated chat tokens are unavailable"
216
+
217
+ if [[ "$CHAT_TOKEN_ESTIMATE" =~ ^([0-9]+)[[:space:]] ]]; then
218
+ CHAT_TOKEN_COUNT="${BASH_REMATCH[1]}"
219
+ CHAT_COST_OUTPUT="$(node scripts/00.chat/metrics/estimate-chat-cost/script.js "$CHAT_TOKEN_COUNT")"
220
+ CHAT_COST_ESTIMATE="$(printf '%s\n' "$CHAT_COST_OUTPUT" | sed -n 's/^estimated_chat_cost: //p' | head -n 1)"
221
+ CHAT_COST_BASIS="$(printf '%s\n' "$CHAT_COST_OUTPUT" | sed -n 's/^estimated_chat_cost_basis: //p' | head -n 1)"
222
+ fi
223
+
224
+ insert_section_entry "## Commits" "- Commit: \`${COMMIT_SHA}\`
225
+ Time UTC: ${COMMIT_AT_UTC}
226
+ Message: ${COMMIT_MESSAGE}
227
+ Summary: ${COMMIT_SUMMARY}
228
+ ADR impact: ${ADR_IMPACT}"
229
+
230
+ insert_section_entry "## Activity Log" "### ${COMMIT_AT_UTC} - Commit recorded
231
+
232
+ Commit: \`${COMMIT_SHA}\`
233
+
234
+ Message: ${COMMIT_MESSAGE}
235
+
236
+ Summary: ${COMMIT_SUMMARY}
237
+
238
+ ADR impact: ${ADR_IMPACT}"
239
+
240
+ tmp="$(mktemp)"
241
+
242
+ awk \
243
+ -v latest_at="$COMMIT_AT_UTC" \
244
+ -v latest_sha="$COMMIT_SHA" \
245
+ -v transcript_provider="$TRANSCRIPT_PROVIDER" \
246
+ -v transcript_path="$TRANSCRIPT_PATH" \
247
+ -v transcript_bytes="$TRANSCRIPT_BYTES" \
248
+ -v transcript_source="$TRANSCRIPT_SOURCE" \
249
+ -v duration="$CHAT_DURATION" \
250
+ -v chat_tokens="$CHAT_TOKEN_ESTIMATE" \
251
+ -v chat_cost="$CHAT_COST_ESTIMATE" \
252
+ -v chat_cost_basis="$CHAT_COST_BASIS" '
253
+ BEGIN {
254
+ in_meta = 0
255
+ wrote_transcript_provider = 0
256
+ wrote_transcript_path = 0
257
+ wrote_transcript_bytes = 0
258
+ wrote_transcript_source = 0
259
+ wrote_chat_cost = 0
260
+ wrote_chat_cost_basis = 0
261
+ }
262
+ /^<!-- agentic-session/ {
263
+ in_meta = 1
264
+ print
265
+ next
266
+ }
267
+ in_meta && /^transcript_provider:/ {
268
+ print "transcript_provider: " transcript_provider
269
+ wrote_transcript_provider = 1
270
+ next
271
+ }
272
+ in_meta && /^transcript_path:/ {
273
+ print "transcript_path: " transcript_path
274
+ wrote_transcript_path = 1
275
+ next
276
+ }
277
+ in_meta && /^transcript_bytes:/ {
278
+ print "transcript_bytes: " transcript_bytes
279
+ wrote_transcript_bytes = 1
280
+ next
281
+ }
282
+ in_meta && /^transcript_source:/ {
283
+ print "transcript_source: " transcript_source
284
+ wrote_transcript_source = 1
285
+ next
286
+ }
287
+ in_meta && /^codex_session_log_path:/ {
288
+ next
289
+ }
290
+ in_meta && /^-->/ {
291
+ if (wrote_transcript_provider == 0) {
292
+ print "transcript_provider: " transcript_provider
293
+ wrote_transcript_provider = 1
294
+ }
295
+ if (wrote_transcript_path == 0) {
296
+ print "transcript_path: " transcript_path
297
+ wrote_transcript_path = 1
298
+ }
299
+ if (wrote_transcript_bytes == 0) {
300
+ print "transcript_bytes: " transcript_bytes
301
+ wrote_transcript_bytes = 1
302
+ }
303
+ if (wrote_transcript_source == 0) {
304
+ print "transcript_source: " transcript_source
305
+ wrote_transcript_source = 1
306
+ }
307
+ if (wrote_chat_cost == 0) {
308
+ print "estimated_chat_cost: " chat_cost
309
+ wrote_chat_cost = 1
310
+ }
311
+ if (wrote_chat_cost_basis == 0) {
312
+ print "estimated_chat_cost_basis: " chat_cost_basis
313
+ wrote_chat_cost_basis = 1
314
+ }
315
+ in_meta = 0
316
+ print
317
+ next
318
+ }
319
+ /^final_commit_at_utc:/ {
320
+ print "latest_commit_at_utc: " latest_at
321
+ print "latest_commit_sha: " latest_sha
322
+ next
323
+ }
324
+ /^latest_commit_at_utc:/ {
325
+ print "latest_commit_at_utc: " latest_at
326
+ next
327
+ }
328
+ /^latest_commit_sha:/ {
329
+ print "latest_commit_sha: " latest_sha
330
+ next
331
+ }
332
+ /^chat_duration:/ {
333
+ print "chat_duration: " duration
334
+ next
335
+ }
336
+ /^estimated_tokens:/ {
337
+ print "estimated_chat_tokens: " chat_tokens
338
+ next
339
+ }
340
+ /^estimated_chat_tokens:/ {
341
+ print "estimated_chat_tokens: " chat_tokens
342
+ next
343
+ }
344
+ /^estimated_chat_cost:/ {
345
+ print "estimated_chat_cost: " chat_cost
346
+ wrote_chat_cost = 1
347
+ next
348
+ }
349
+ /^estimated_chat_cost_basis:/ {
350
+ print "estimated_chat_cost_basis: " chat_cost_basis
351
+ wrote_chat_cost_basis = 1
352
+ next
353
+ }
354
+ /^Final commit at UTC:/ {
355
+ print "Latest commit at UTC: " latest_at
356
+ print "Latest commit SHA: " latest_sha
357
+ next
358
+ }
359
+ /^Latest commit at UTC:/ {
360
+ print "Latest commit at UTC: " latest_at
361
+ next
362
+ }
363
+ /^Latest commit SHA:/ {
364
+ print "Latest commit SHA: " latest_sha
365
+ next
366
+ }
367
+ /^Chat duration:/ {
368
+ print "Chat duration: " duration
369
+ next
370
+ }
371
+ /^Estimated tokens:/ {
372
+ print "Estimated chat tokens: " chat_tokens
373
+ next
374
+ }
375
+ /^Estimated chat tokens:/ {
376
+ print "Estimated chat tokens: " chat_tokens
377
+ print "Estimated chat cost: " chat_cost
378
+ print "Estimated chat cost basis: " chat_cost_basis
379
+ next
380
+ }
381
+ /^Estimated chat cost:/ {
382
+ next
383
+ }
384
+ /^Estimated chat cost basis:/ {
385
+ next
386
+ }
387
+ {
388
+ print
389
+ }
390
+ ' "$LOG_FILE" > "$tmp"
391
+
392
+ mv "$tmp" "$LOG_FILE"
393
+
394
+ echo "Recorded chat commit: $COMMIT_SHA"