picocode-core 0.9.132 → 0.9.134
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/package.json +1 -1
- package/src/git.js +25 -4
package/package.json
CHANGED
package/src/git.js
CHANGED
|
@@ -3,7 +3,7 @@ import { readFileSync, statSync, watch } from 'node:fs'
|
|
|
3
3
|
import { dirname, isAbsolute, join, resolve } from 'node:path'
|
|
4
4
|
|
|
5
5
|
const DEBOUNCE_MS = 500
|
|
6
|
-
const POLL_MS =
|
|
6
|
+
const POLL_MS = 5000
|
|
7
7
|
const GIT_TIMEOUT_MS = 5000
|
|
8
8
|
|
|
9
9
|
function findGitDir(startDir) {
|
|
@@ -48,6 +48,7 @@ export function createGitService({ onChange = () => {} } = {}) {
|
|
|
48
48
|
let gitDir = null
|
|
49
49
|
let epoch = 0
|
|
50
50
|
let watcher = null
|
|
51
|
+
let treeWatcher = null
|
|
51
52
|
let poll = null
|
|
52
53
|
let debounce = null
|
|
53
54
|
let child = null
|
|
@@ -58,6 +59,8 @@ export function createGitService({ onChange = () => {} } = {}) {
|
|
|
58
59
|
epoch += 1
|
|
59
60
|
watcher?.close()
|
|
60
61
|
watcher = null
|
|
62
|
+
treeWatcher?.close()
|
|
63
|
+
treeWatcher = null
|
|
61
64
|
if (poll) clearInterval(poll)
|
|
62
65
|
poll = null
|
|
63
66
|
if (debounce) clearTimeout(debounce)
|
|
@@ -85,6 +88,20 @@ export function createGitService({ onChange = () => {} } = {}) {
|
|
|
85
88
|
} catch {
|
|
86
89
|
watcher = null
|
|
87
90
|
}
|
|
91
|
+
// the working tree too, so an edit shows up right away rather than at
|
|
92
|
+
// the next poll. recursive watching rides on FSEvents on macOS; the
|
|
93
|
+
// refresh is debounced so a burst of writes costs one git call
|
|
94
|
+
try {
|
|
95
|
+
treeWatcher = watch(root, { recursive: true }, (_event, file) => {
|
|
96
|
+
if (epoch !== started) return
|
|
97
|
+
const name = String(file ?? '')
|
|
98
|
+
if (name === '.git' || name.startsWith('.git/') || name.includes('node_modules')) return
|
|
99
|
+
refresh()
|
|
100
|
+
})
|
|
101
|
+
treeWatcher.on('error', () => {})
|
|
102
|
+
} catch {
|
|
103
|
+
treeWatcher = null
|
|
104
|
+
}
|
|
88
105
|
poll = setInterval(run, POLL_MS)
|
|
89
106
|
poll.unref?.()
|
|
90
107
|
run()
|
|
@@ -107,7 +124,9 @@ export function createGitService({ onChange = () => {} } = {}) {
|
|
|
107
124
|
}
|
|
108
125
|
const started = epoch
|
|
109
126
|
const branch = readBranch(gitDir)
|
|
110
|
-
|
|
127
|
+
// one shell round trip: the tracked diff stat, then a marker, then the
|
|
128
|
+
// porcelain status so untracked files count too
|
|
129
|
+
const proc = spawn('sh', ['-c', 'git --no-optional-locks diff HEAD --shortstat; echo __status__; git --no-optional-locks status --porcelain --untracked-files=all'], {
|
|
111
130
|
cwd: root,
|
|
112
131
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
113
132
|
})
|
|
@@ -125,8 +144,10 @@ export function createGitService({ onChange = () => {} } = {}) {
|
|
|
125
144
|
clearTimeout(timeout)
|
|
126
145
|
if (child === proc) child = null
|
|
127
146
|
if (epoch !== started) return
|
|
128
|
-
const
|
|
129
|
-
const
|
|
147
|
+
const [diff = '', status = ''] = output.split('__status__')
|
|
148
|
+
const stats = code === 0 ? parseShortstat(diff) : { added: 0, removed: 0 }
|
|
149
|
+
const untracked = code === 0 ? status.split('\n').filter((line) => line.startsWith('??')).length : 0
|
|
150
|
+
const next = branch ? { branch, ...stats, untracked } : null
|
|
130
151
|
if (JSON.stringify(next) !== JSON.stringify(current)) {
|
|
131
152
|
current = next
|
|
132
153
|
onChange()
|