theslopmachine 0.3.5 → 0.3.6
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/assets/slopmachine/beads-init.js +10 -1
- package/package.json +1 -1
- package/src/init.js +17 -3
- package/src/install.js +108 -13
- package/src/utils.js +14 -5
|
@@ -17,6 +17,14 @@ function die(message) {
|
|
|
17
17
|
process.exit(1)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
function quoteShellArg(value) {
|
|
21
|
+
if (/^[A-Za-z0-9_./:-]+$/.test(value)) {
|
|
22
|
+
return value
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return `'${value.replaceAll(`'`, `'\\''`)}'`
|
|
26
|
+
}
|
|
27
|
+
|
|
20
28
|
function run(command, args, options = {}) {
|
|
21
29
|
return new Promise((resolve, reject) => {
|
|
22
30
|
const child = spawn(command, args, {
|
|
@@ -86,9 +94,10 @@ async function chooseNoninteractiveInitModeFlag(isGitRepo) {
|
|
|
86
94
|
async function configureGitMergeDriver() {
|
|
87
95
|
const attributesFile = path.join(target, '.git', 'info', 'attributes')
|
|
88
96
|
const attributesLine = '.beads/*.jsonl merge=beads'
|
|
97
|
+
const mergeDriverCommand = `${quoteShellArg(bdCommand)} merge %A %O %A %B`
|
|
89
98
|
|
|
90
99
|
log('Configuring local git merge driver for Beads')
|
|
91
|
-
let result = await run('git', ['-C', target, 'config', 'merge.beads.driver',
|
|
100
|
+
let result = await run('git', ['-C', target, 'config', 'merge.beads.driver', mergeDriverCommand])
|
|
92
101
|
if (result.code !== 0) die(result.stderr || 'Failed configuring git merge driver')
|
|
93
102
|
|
|
94
103
|
await fs.mkdir(path.dirname(attributesFile), { recursive: true })
|
package/package.json
CHANGED
package/src/init.js
CHANGED
|
@@ -21,6 +21,16 @@ const GITIGNORE_ENTRIES = [
|
|
|
21
21
|
'antigravity-logs/',
|
|
22
22
|
]
|
|
23
23
|
|
|
24
|
+
function getUnixBeadsCommandCandidates(paths) {
|
|
25
|
+
return [
|
|
26
|
+
path.join(paths.home, '.local', 'bin', 'bd'),
|
|
27
|
+
path.join(paths.home, '.linuxbrew', 'bin', 'bd'),
|
|
28
|
+
'/opt/homebrew/bin/bd',
|
|
29
|
+
'/usr/local/bin/bd',
|
|
30
|
+
'/home/linuxbrew/.linuxbrew/bin/bd',
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
|
|
24
34
|
function getWindowsBeadsCommandCandidates() {
|
|
25
35
|
if (process.platform !== 'win32') {
|
|
26
36
|
return []
|
|
@@ -32,8 +42,12 @@ function getWindowsBeadsCommandCandidates() {
|
|
|
32
42
|
].filter(Boolean)
|
|
33
43
|
}
|
|
34
44
|
|
|
35
|
-
async function resolveBeadsCommand() {
|
|
36
|
-
|
|
45
|
+
async function resolveBeadsCommand(paths) {
|
|
46
|
+
const candidates = process.platform === 'win32'
|
|
47
|
+
? getWindowsBeadsCommandCandidates()
|
|
48
|
+
: getUnixBeadsCommandCandidates(paths)
|
|
49
|
+
|
|
50
|
+
return resolveCommand('bd', { additionalCandidates: candidates, preferCandidates: true })
|
|
37
51
|
}
|
|
38
52
|
|
|
39
53
|
function parseInitArgs(args) {
|
|
@@ -119,7 +133,7 @@ async function runBeadsBootstrap(paths, targetPath, beadsScript) {
|
|
|
119
133
|
throw new Error('Unable to locate the current Node.js executable for Beads bootstrap.')
|
|
120
134
|
}
|
|
121
135
|
|
|
122
|
-
const beadsCommand = await resolveBeadsCommand()
|
|
136
|
+
const beadsCommand = await resolveBeadsCommand(paths)
|
|
123
137
|
|
|
124
138
|
log('Running Beads setup')
|
|
125
139
|
const result = await runCommand(nodeExecutable, [beadsScript, targetPath], {
|
package/src/install.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from 'node:fs/promises'
|
|
2
|
+
import os from 'node:os'
|
|
2
3
|
import path from 'node:path'
|
|
3
4
|
|
|
4
5
|
import {
|
|
@@ -16,6 +17,7 @@ import {
|
|
|
16
17
|
copyDirIfMissing,
|
|
17
18
|
copyFileIfMissing,
|
|
18
19
|
ensureDir,
|
|
20
|
+
findBashExecutable,
|
|
19
21
|
getGlobalNpmPackageVersion,
|
|
20
22
|
log,
|
|
21
23
|
makeExecutableIfShellScript,
|
|
@@ -34,6 +36,21 @@ function assetsRoot() {
|
|
|
34
36
|
return path.join(PACKAGE_ROOT, 'assets')
|
|
35
37
|
}
|
|
36
38
|
|
|
39
|
+
function getHomeDir() {
|
|
40
|
+
return buildPaths().home
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getUnixBeadsBinDirs() {
|
|
44
|
+
const home = getHomeDir()
|
|
45
|
+
return [
|
|
46
|
+
path.join(home, '.local', 'bin'),
|
|
47
|
+
path.join(home, '.linuxbrew', 'bin'),
|
|
48
|
+
'/opt/homebrew/bin',
|
|
49
|
+
'/usr/local/bin',
|
|
50
|
+
'/home/linuxbrew/.linuxbrew/bin',
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
|
|
37
54
|
function getWindowsBeadsBinDirs() {
|
|
38
55
|
if (process.platform !== 'win32') {
|
|
39
56
|
return []
|
|
@@ -47,12 +64,16 @@ function getWindowsBeadsBinDirs() {
|
|
|
47
64
|
return [...new Set(dirs)]
|
|
48
65
|
}
|
|
49
66
|
|
|
50
|
-
function
|
|
51
|
-
|
|
67
|
+
function getBeadsCommandCandidates() {
|
|
68
|
+
if (process.platform === 'win32') {
|
|
69
|
+
return getWindowsBeadsBinDirs().map((dir) => path.join(dir, 'bd.exe'))
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return getUnixBeadsBinDirs().map((dir) => path.join(dir, 'bd'))
|
|
52
73
|
}
|
|
53
74
|
|
|
54
75
|
async function resolveBeadsCommand() {
|
|
55
|
-
return resolveCommand('bd', { additionalCandidates:
|
|
76
|
+
return resolveCommand('bd', { additionalCandidates: getBeadsCommandCandidates(), preferCandidates: true })
|
|
56
77
|
}
|
|
57
78
|
|
|
58
79
|
async function getBeadsVersion() {
|
|
@@ -69,6 +90,25 @@ async function getBeadsVersion() {
|
|
|
69
90
|
return { command, version: (result.stdout || result.stderr).trim() }
|
|
70
91
|
}
|
|
71
92
|
|
|
93
|
+
async function probeBeadsRuntime(command) {
|
|
94
|
+
const probeDir = await fs.mkdtemp(path.join(os.tmpdir(), 'slopmachine-beads-probe-'))
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
const result = await runCommand(command, ['init', '--quiet', '--stealth', '--skip-hooks'], {
|
|
98
|
+
cwd: probeDir,
|
|
99
|
+
env: { ...process.env, CI: '1' },
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
const output = `${result.stdout}${result.stderr}`.trim()
|
|
103
|
+
return {
|
|
104
|
+
ok: result.code === 0,
|
|
105
|
+
output,
|
|
106
|
+
}
|
|
107
|
+
} finally {
|
|
108
|
+
await fs.rm(probeDir, { recursive: true, force: true })
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
72
112
|
function quotePowerShell(value) {
|
|
73
113
|
return `'${String(value).replaceAll(`'`, `''`)}'`
|
|
74
114
|
}
|
|
@@ -116,6 +156,20 @@ async function ensureWindowsBeadsPath() {
|
|
|
116
156
|
}
|
|
117
157
|
}
|
|
118
158
|
|
|
159
|
+
async function ensureUnixBeadsPath() {
|
|
160
|
+
if (process.platform === 'win32') {
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
for (const dir of getUnixBeadsBinDirs()) {
|
|
165
|
+
if (!(await pathExists(path.join(dir, 'bd')))) {
|
|
166
|
+
continue
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
prependToProcessPath(dir)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
119
173
|
async function installBeadsOnWindows() {
|
|
120
174
|
const shell = await resolveCommand('pwsh') || await resolveCommand('powershell')
|
|
121
175
|
if (!shell) {
|
|
@@ -135,6 +189,37 @@ async function installBeadsOnWindows() {
|
|
|
135
189
|
return result
|
|
136
190
|
}
|
|
137
191
|
|
|
192
|
+
async function installBeadsOnUnix() {
|
|
193
|
+
const managers = await detectPackageManagers()
|
|
194
|
+
if (managers.brew) {
|
|
195
|
+
log('Installing Beads via Homebrew')
|
|
196
|
+
const result = await runCommand('brew', ['install', 'beads'], { stdio: 'inherit' })
|
|
197
|
+
await ensureUnixBeadsPath()
|
|
198
|
+
return result
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const bashExecutable = await findBashExecutable()
|
|
202
|
+
if (!bashExecutable) {
|
|
203
|
+
return { code: 1, stdout: '', stderr: 'bash is required to run the Beads installer on this platform' }
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (await commandExists('curl')) {
|
|
207
|
+
log('Installing Beads with the upstream Unix install script')
|
|
208
|
+
const result = await runCommand(bashExecutable, ['-lc', 'curl -fsSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash'], { stdio: 'inherit' })
|
|
209
|
+
await ensureUnixBeadsPath()
|
|
210
|
+
return result
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (await commandExists('wget')) {
|
|
214
|
+
log('Installing Beads with the upstream Unix install script')
|
|
215
|
+
const result = await runCommand(bashExecutable, ['-lc', 'wget -qO- https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash'], { stdio: 'inherit' })
|
|
216
|
+
await ensureUnixBeadsPath()
|
|
217
|
+
return result
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return { code: 1, stdout: '', stderr: 'curl or wget is required to install Beads on this platform' }
|
|
221
|
+
}
|
|
222
|
+
|
|
138
223
|
async function getCommandVersion(command, args = ['--version']) {
|
|
139
224
|
const exists = await commandExists(command)
|
|
140
225
|
if (!exists) return null
|
|
@@ -184,8 +269,7 @@ async function tryInstallCoreDependency(name) {
|
|
|
184
269
|
return installBeadsOnWindows()
|
|
185
270
|
}
|
|
186
271
|
|
|
187
|
-
|
|
188
|
-
return runCommand('npm', ['install', '-g', `@beads/bd@${BEADS_VERSION}`], { stdio: 'inherit' })
|
|
272
|
+
return installBeadsOnUnix()
|
|
189
273
|
}
|
|
190
274
|
|
|
191
275
|
const managers = await detectPackageManagers()
|
|
@@ -263,11 +347,16 @@ async function ensureDependency({ name, checkCommand, requiredVersion, installab
|
|
|
263
347
|
if (checkCommand === 'bd') {
|
|
264
348
|
const beads = await getBeadsVersion()
|
|
265
349
|
if (beads) {
|
|
266
|
-
|
|
267
|
-
if (
|
|
268
|
-
warn(`${name}
|
|
350
|
+
const probe = await probeBeadsRuntime(beads.command)
|
|
351
|
+
if (!probe.ok) {
|
|
352
|
+
warn(`${name} was found at ${beads.command}, but it failed a runtime probe.${probe.output ? ` ${probe.output}` : ''}`)
|
|
353
|
+
} else {
|
|
354
|
+
log(`${name} detected via ${beads.command}: ${beads.version}`)
|
|
355
|
+
if (requiredVersion && !beads.version.includes(requiredVersion)) {
|
|
356
|
+
warn(`${name} version differs from tested reference ${requiredVersion}`)
|
|
357
|
+
}
|
|
358
|
+
return
|
|
269
359
|
}
|
|
270
|
-
return
|
|
271
360
|
}
|
|
272
361
|
}
|
|
273
362
|
|
|
@@ -288,7 +377,7 @@ async function ensureDependency({ name, checkCommand, requiredVersion, installab
|
|
|
288
377
|
|
|
289
378
|
const shouldInstall = await promptYesNo(`Attempt to install ${name} automatically?`, true)
|
|
290
379
|
if (!shouldInstall) {
|
|
291
|
-
|
|
380
|
+
warn(`Skipping ${name} installation. Please install it manually before using theslopmachine.`)
|
|
292
381
|
return
|
|
293
382
|
}
|
|
294
383
|
|
|
@@ -315,10 +404,16 @@ async function ensureDependency({ name, checkCommand, requiredVersion, installab
|
|
|
315
404
|
if (checkCommand === 'bd') {
|
|
316
405
|
const beads = await getBeadsVersion()
|
|
317
406
|
if (beads) {
|
|
318
|
-
|
|
319
|
-
if (
|
|
320
|
-
|
|
407
|
+
const probe = await probeBeadsRuntime(beads.command)
|
|
408
|
+
if (probe.ok) {
|
|
409
|
+
log(`Installed ${name} via ${beads.command}: ${beads.version}`)
|
|
410
|
+
if (process.platform === 'win32' && !(await commandExists('bd'))) {
|
|
411
|
+
warn('Beads was installed, but `bd` is not visible in this shell PATH yet. The installer added the common Windows Beads directories to PATH for future shells.')
|
|
412
|
+
}
|
|
413
|
+
return
|
|
321
414
|
}
|
|
415
|
+
|
|
416
|
+
warn(`${name} was installed at ${beads.command}, but it still failed a runtime probe.${probe.output ? ` ${probe.output}` : ''}`)
|
|
322
417
|
return
|
|
323
418
|
}
|
|
324
419
|
|
package/src/utils.js
CHANGED
|
@@ -155,12 +155,25 @@ async function getGlobalNpmPrefix() {
|
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
export async function resolveCommand(command, options = {}) {
|
|
158
|
+
const candidates = []
|
|
159
|
+
|
|
160
|
+
if (Array.isArray(options.additionalCandidates)) {
|
|
161
|
+
candidates.push(...options.additionalCandidates)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (options.preferCandidates) {
|
|
165
|
+
for (const candidate of candidates) {
|
|
166
|
+
if (await pathExists(candidate)) {
|
|
167
|
+
return candidate
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
158
172
|
if (await commandExists(command)) {
|
|
159
173
|
return command
|
|
160
174
|
}
|
|
161
175
|
|
|
162
176
|
const prefix = await getGlobalNpmPrefix()
|
|
163
|
-
const candidates = []
|
|
164
177
|
|
|
165
178
|
if (prefix) {
|
|
166
179
|
candidates.push(...(process.platform === 'win32'
|
|
@@ -175,10 +188,6 @@ export async function resolveCommand(command, options = {}) {
|
|
|
175
188
|
]))
|
|
176
189
|
}
|
|
177
190
|
|
|
178
|
-
if (Array.isArray(options.additionalCandidates)) {
|
|
179
|
-
candidates.push(...options.additionalCandidates)
|
|
180
|
-
}
|
|
181
|
-
|
|
182
191
|
for (const candidate of candidates) {
|
|
183
192
|
if (await pathExists(candidate)) {
|
|
184
193
|
return candidate
|