@searls/turbocommit 0.16.2 → 0.16.3

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/README.md CHANGED
@@ -76,7 +76,7 @@ Each touched checkout:
76
76
  - Reads its own merged global and project configuration.
77
77
  - Stages only paths attributed to the current session, preserving unrelated
78
78
  staged and unstaged work.
79
- - Gets an independent commit with the full turn transcript.
79
+ - Gets an independent commit with the turn transcript (up to 16 KiB).
80
80
  - Gives the configured title agent repository-specific bounded diff context.
81
81
 
82
82
  Turbocommit attempts every commit before pushing every successful commit whose
@@ -118,7 +118,10 @@ upgrade, Turbocommit discards those unsafe retry entries and records a
118
118
  `legacy-manifest` monitor event rather than guessing which files they owned.
119
119
 
120
120
  The commit message headline is generated by a title agent (configurable).
121
- The body contains the full prompt/response transcript. When planning
121
+ The body contains the prompt/response transcript, capped at 16 KiB of UTF-8 text.
122
+ Oversized bodies retain the beginning and end with an explicit truncation marker.
123
+ The cap also applies to combined planning context and agent-generated bodies;
124
+ Git trailers are appended separately and preserved. When planning
122
125
  context was buffered from ancestor sessions, it appears under a
123
126
  `## Planning` section before the `## Implementation` section.
124
127
 
package/lib/run.js CHANGED
@@ -2,7 +2,7 @@ const fs = require('fs')
2
2
  const os = require('os')
3
3
  const path = require('path')
4
4
  const { loadJson } = require('./io')
5
- const { parseTranscript, parseCodexTranscript, formatBody, formatTitleTranscript, extractHeadline, extractModel, extractCodexModel } = require('./transcript')
5
+ const { parseTranscript, parseCodexTranscript, formatBody, capTranscript, formatTitleTranscript, extractHeadline, extractModel, extractCodexModel } = require('./transcript')
6
6
  const { runTitleAgent, runBodyAgent } = require('./agent')
7
7
  const { withGitRetry, gitRoot, hasChanges, changedPaths, addAndCommit, stagePaths, commitPaths, commitStagedPaths, stagedChangeContext, currentBranch, pushClean, hasRepositoryOperation } = require('./git')
8
8
  const { logEvent } = require('./log')
@@ -388,7 +388,7 @@ function runSingle (input, opts = {}) {
388
388
  }
389
389
 
390
390
  // Wrap body lines if configured
391
- const wrappedBody = wrapText(combinedBody, config.body?.maxLineLength)
391
+ const wrappedBody = capTranscript(wrapText(combinedBody, config.body?.maxLineLength))
392
392
 
393
393
  // Resolve coauthor trailer
394
394
  const coauthor = resolveCoauthor(config, transcriptPath, root, {
@@ -545,7 +545,7 @@ function runMulti (hookInput, anchor, currentRepos, manifest, opts = {}) {
545
545
  continue
546
546
  }
547
547
 
548
- const rawBody = repo.work.map(item => item.body).join('\n\n---\n\n')
548
+ const rawBody = capTranscript(repo.work.map(item => item.body).join('\n\n---\n\n'))
549
549
  const redactions = buildRedactions()
550
550
  const changeContext = redact(stagedChangeContext(root, 10000, stagedPaths), redactions)
551
551
  const titleInput = `${changeContext}\n\nTranscript:\n${rawBody}`.slice(0, 20000)
@@ -566,7 +566,7 @@ function runMulti (hookInput, anchor, currentRepos, manifest, opts = {}) {
566
566
  ? readMultiWatermark(root, [sessionId, ...ancestors])
567
567
  : null
568
568
  if (parent?.commit) body = `Continuation of ${parent.commit.slice(0, 7)}\n\n${body}`
569
- body = wrapText(body, config.body?.maxLineLength)
569
+ body = capTranscript(wrapText(body, config.body?.maxLineLength))
570
570
 
571
571
  const trailers = []
572
572
  for (const work of repo.work) {
package/lib/transcript.js CHANGED
@@ -121,7 +121,23 @@ function formatPair (p) {
121
121
  */
122
122
  function formatBody (pairs) {
123
123
  if (pairs.length === 0) return '(no transcript)'
124
- return pairs.map(formatPair).join('\n\n---\n\n')
124
+ return capTranscript(pairs.map(formatPair).join('\n\n---\n\n'))
125
+ }
126
+
127
+ // Keep both the original intent and latest outcome, with a hard UTF-8 byte cap.
128
+ function capTranscript (text) {
129
+ const budget = 16 * 1024
130
+ const bytes = Buffer.from(text)
131
+ if (bytes.length <= budget) return text
132
+
133
+ const marker = '\n\n[... transcript truncated ...]\n\n'
134
+ const available = budget - Buffer.byteLength(marker)
135
+ let headEnd = Math.floor(available / 2)
136
+ let tailStart = bytes.length - (available - headEnd)
137
+ // Move cuts to UTF-8 code point boundaries.
138
+ while ((bytes[headEnd] & 0xc0) === 0x80) headEnd--
139
+ while ((bytes[tailStart] & 0xc0) === 0x80) tailStart++
140
+ return bytes.subarray(0, headEnd).toString() + marker + bytes.subarray(tailStart).toString()
125
141
  }
126
142
 
127
143
  /**
@@ -134,7 +150,7 @@ function formatTitleTranscript (pairs, budget) {
134
150
  budget = budget || 20000
135
151
  if (pairs.length === 0) return '(no transcript)'
136
152
 
137
- const full = formatBody(pairs)
153
+ const full = pairs.map(formatPair).join('\n\n---\n\n')
138
154
  if (full.length <= budget) return full
139
155
 
140
156
  const sep = '\n\n---\n\n'
@@ -221,6 +237,7 @@ module.exports = {
221
237
  parseCodexTranscript,
222
238
  formatPair,
223
239
  formatBody,
240
+ capTranscript,
224
241
  formatTitleTranscript,
225
242
  extractHeadline,
226
243
  fallbackHeadline,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@searls/turbocommit",
3
- "version": "0.16.2",
3
+ "version": "0.16.3",
4
4
  "description": "Auto-commit after every AI coding agent turn",
5
5
  "bin": {
6
6
  "turbocommit": "./cli.js"