@searls/turbocommit 0.12.0 → 0.12.1
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/lib/git.js +12 -0
- package/lib/session.js +27 -9
- package/lib/track.js +9 -3
- package/package.json +1 -1
package/lib/git.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { execSync } = require('child_process')
|
|
2
|
+
const path = require('path')
|
|
2
3
|
|
|
3
4
|
function git (args, opts = {}) {
|
|
4
5
|
const cwd = opts.cwd || process.cwd()
|
|
@@ -17,6 +18,16 @@ function gitRoot (cwd) {
|
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
function gitCommonDir (cwd) {
|
|
22
|
+
try {
|
|
23
|
+
const out = git('rev-parse --git-common-dir', { cwd })
|
|
24
|
+
if (!out) return null
|
|
25
|
+
return path.isAbsolute(out) ? out : path.resolve(cwd, out)
|
|
26
|
+
} catch {
|
|
27
|
+
return null
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
20
31
|
function hasChanges (cwd) {
|
|
21
32
|
try {
|
|
22
33
|
git('diff --quiet HEAD', { cwd })
|
|
@@ -72,6 +83,7 @@ function esc (s) {
|
|
|
72
83
|
module.exports = {
|
|
73
84
|
git,
|
|
74
85
|
gitRoot,
|
|
86
|
+
gitCommonDir,
|
|
75
87
|
hasChanges,
|
|
76
88
|
addAndCommit,
|
|
77
89
|
hasCommits,
|
package/lib/session.js
CHANGED
|
@@ -1,28 +1,36 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
3
|
const { ensureDir } = require('./io')
|
|
4
|
+
const { gitCommonDir } = require('./git')
|
|
4
5
|
|
|
5
6
|
const BREADCRUMB_THRESHOLD_MS = 2000
|
|
6
7
|
const STALE_TTL_MS = 24 * 60 * 60 * 1000
|
|
7
8
|
|
|
8
9
|
function turbocommitDir (root) {
|
|
9
|
-
|
|
10
|
+
if (!root) return null
|
|
11
|
+
const gitDir = gitCommonDir(root)
|
|
12
|
+
if (!gitDir) return null
|
|
13
|
+
return path.join(gitDir, 'turbocommit')
|
|
10
14
|
}
|
|
11
15
|
|
|
12
16
|
function breadcrumbDir (root) {
|
|
13
|
-
|
|
17
|
+
const base = turbocommitDir(root)
|
|
18
|
+
return base && path.join(base, 'breadcrumbs')
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
function chainDir (root) {
|
|
17
|
-
|
|
22
|
+
const base = turbocommitDir(root)
|
|
23
|
+
return base && path.join(base, 'chains')
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
function pendingDir (root) {
|
|
21
|
-
|
|
27
|
+
const base = turbocommitDir(root)
|
|
28
|
+
return base && path.join(base, 'pending')
|
|
22
29
|
}
|
|
23
30
|
|
|
24
31
|
function watermarkDir (root) {
|
|
25
|
-
|
|
32
|
+
const base = turbocommitDir(root)
|
|
33
|
+
return base && path.join(base, 'watermarks')
|
|
26
34
|
}
|
|
27
35
|
|
|
28
36
|
/**
|
|
@@ -42,6 +50,7 @@ function handleSessionEnd (input, root) {
|
|
|
42
50
|
if (!sessionId) return
|
|
43
51
|
|
|
44
52
|
const dir = breadcrumbDir(root)
|
|
53
|
+
if (!dir) return
|
|
45
54
|
ensureDir(dir)
|
|
46
55
|
const data = { session_id: sessionId, timestamp: Date.now() }
|
|
47
56
|
fs.writeFileSync(path.join(dir, sessionId + '.json'), JSON.stringify(data) + '\n')
|
|
@@ -67,7 +76,7 @@ function handleSessionStart (input, root) {
|
|
|
67
76
|
if (source !== 'clear' && source !== 'resume') return
|
|
68
77
|
|
|
69
78
|
const dir = breadcrumbDir(root)
|
|
70
|
-
if (!fs.existsSync(dir)) return
|
|
79
|
+
if (!dir || !fs.existsSync(dir)) return
|
|
71
80
|
|
|
72
81
|
// Scan breadcrumbs for closest match
|
|
73
82
|
const now = Date.now()
|
|
@@ -108,6 +117,7 @@ function handleSessionStart (input, root) {
|
|
|
108
117
|
|
|
109
118
|
// Write chain for this session
|
|
110
119
|
const cDir = chainDir(root)
|
|
120
|
+
if (!cDir) return
|
|
111
121
|
ensureDir(cDir)
|
|
112
122
|
const chain = { parent: best.session_id, ancestors }
|
|
113
123
|
fs.writeFileSync(path.join(cDir, sessionId + '.json'), JSON.stringify(chain) + '\n')
|
|
@@ -134,7 +144,9 @@ function getAncestors (root, sessionId) {
|
|
|
134
144
|
*/
|
|
135
145
|
let pendingSeq = 0
|
|
136
146
|
function savePending (root, sessionId, transcript) {
|
|
137
|
-
const
|
|
147
|
+
const base = pendingDir(root)
|
|
148
|
+
if (!base) return
|
|
149
|
+
const dir = path.join(base, sessionId)
|
|
138
150
|
ensureDir(dir)
|
|
139
151
|
const timestamp = String(Date.now()) + '-' + String(pendingSeq++).padStart(4, '0')
|
|
140
152
|
fs.writeFileSync(path.join(dir, timestamp + '.txt'), transcript)
|
|
@@ -146,8 +158,10 @@ function savePending (root, sessionId, transcript) {
|
|
|
146
158
|
*/
|
|
147
159
|
function collectPending (root, sessionIds) {
|
|
148
160
|
const results = []
|
|
161
|
+
const base = pendingDir(root)
|
|
162
|
+
if (!base) return results
|
|
149
163
|
for (const sid of sessionIds) {
|
|
150
|
-
const dir = path.join(
|
|
164
|
+
const dir = path.join(base, sid)
|
|
151
165
|
let files
|
|
152
166
|
try {
|
|
153
167
|
files = fs.readdirSync(dir).sort()
|
|
@@ -183,6 +197,7 @@ function readWatermark (root, sessionId) {
|
|
|
183
197
|
*/
|
|
184
198
|
function saveWatermark (root, sessionId, pairs, commit) {
|
|
185
199
|
const dir = watermarkDir(root)
|
|
200
|
+
if (!dir) return
|
|
186
201
|
ensureDir(dir)
|
|
187
202
|
fs.writeFileSync(path.join(dir, sessionId + '.json'), JSON.stringify({ pairs, commit }) + '\n')
|
|
188
203
|
}
|
|
@@ -209,9 +224,11 @@ function resolveParentCommit (root, sessionId) {
|
|
|
209
224
|
* Delete consumed pending + chain files after commit.
|
|
210
225
|
*/
|
|
211
226
|
function cleanupConsumed (root, sessionIds) {
|
|
227
|
+
const base = pendingDir(root)
|
|
228
|
+
if (!base) return
|
|
212
229
|
for (const sid of sessionIds) {
|
|
213
230
|
// Remove pending dir
|
|
214
|
-
const dir = path.join(
|
|
231
|
+
const dir = path.join(base, sid)
|
|
215
232
|
try {
|
|
216
233
|
const files = fs.readdirSync(dir)
|
|
217
234
|
for (const file of files) {
|
|
@@ -232,6 +249,7 @@ function cleanupStale (root, maxAgeMs) {
|
|
|
232
249
|
const ttl = maxAgeMs != null ? maxAgeMs : STALE_TTL_MS
|
|
233
250
|
const now = Date.now()
|
|
234
251
|
const base = turbocommitDir(root)
|
|
252
|
+
if (!base) return
|
|
235
253
|
|
|
236
254
|
for (const sub of ['breadcrumbs', 'chains', 'tracking', 'watermarks']) {
|
|
237
255
|
const dir = path.join(base, sub)
|
package/lib/track.js
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
3
|
const { ensureDir } = require('./io')
|
|
4
|
+
const { turbocommitDir } = require('./session')
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
* Directory under
|
|
7
|
+
* Directory under the git common dir where turbocommit stores tracking state.
|
|
8
|
+
* Returns null when the root isn't resolvable to a git repo (including when
|
|
9
|
+
* run outside a repo, which is not expected during normal operation).
|
|
7
10
|
*/
|
|
8
11
|
function trackingDir (root) {
|
|
9
|
-
|
|
12
|
+
const base = turbocommitDir(root)
|
|
13
|
+
return base && path.join(base, 'tracking')
|
|
10
14
|
}
|
|
11
15
|
|
|
12
16
|
function trackingPath (root, sessionId) {
|
|
13
|
-
|
|
17
|
+
const dir = trackingDir(root)
|
|
18
|
+
return dir && path.join(dir, sessionId + '.jsonl')
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
/**
|
|
@@ -72,6 +77,7 @@ function handleTrack (input, root) {
|
|
|
72
77
|
if (toolName === 'Bash' && typeof toolInput.command !== 'string') return
|
|
73
78
|
|
|
74
79
|
const file = trackingPath(root, sessionId)
|
|
80
|
+
if (!file) return
|
|
75
81
|
ensureDir(path.dirname(file))
|
|
76
82
|
fs.appendFileSync(file, JSON.stringify(entry) + '\n')
|
|
77
83
|
}
|