OverviewFilesCommitsIssuesDocsReleasesPeers

pgh commits / aa554af

0.1.147: honour abstract sockets in every CLI socket guard, not just one
`fs.existsSync('@pgh-celltron')` is always false — a Linux abstract-namespace socket has no filesystem entry. Seven command modules gated their sidecar calls on that check, so on any host using an abstract socket every one of them reported "pgh-sidecar is not running" while the sidecar was listening. Confirmed on celltron: /proc/net/unix shows @pgh-celltron in state 01 (listening) and the CLI refused to connect. daemon-client.js already had the fix, with a comment spelling out exactly this failure. It was never propagated: device.js user.js overlay.js names.js releases.js publish.js app.js isAbstract is now exported from daemon-client.js and used by all of them. app.js's guard also gated bare-name resolution, so `pgh app install <name>` could not resolve a name on those hosts either. Consequence beyond the error message: publish.js used the same check to decide whether to append via the sidecar or fall back to a direct corestore append — so on an abstract-socket host it silently took the fallback path. 331/331, 941/941. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aa554af22a9232415eb71d48aade706f433e3e12
by plankatron <fleeky@gmail.com> · 2026-08-25T21:12:59.000Z

Changed files (9) +16 -9

lib/commands/app.js +2 -1
……@@ -1,6 +1,7 @@
11/** pgh app install|update|rollback|list|remove|start|stop|restart|status|log|autostart|boot|shutdown|adopt */
22
33import process from '#node:process'
4import { isAbstract } from '../daemon-client.js'
45import { spawn } from '#node:child_process'
56import { execSync } from '../_compat-exec.js'
67import path from '#node:path'
……@@ -219,7 +220,7 @@ export async function run (client, args) {
219220 // Bare name — ask pgh-sidecar's NameRegistry to resolve. If that
220221 // works, synthesize the pgh:// URL and proceed with the normal
221222 // install flow.
222 if (fs.existsSync(SIDECAR_SOCK) && /^[a-zA-Z0-9_-][a-zA-Z0-9_.-]*$/.test(target)) {
223 if ((isAbstract(SIDECAR_SOCK) || fs.existsSync(SIDECAR_SOCK)) && /^[a-zA-Z0-9_-][a-zA-Z0-9_.-]*$/.test(target)) {
223224 const resolved = await resolveBareName(target)
224225 if (resolved) {
225226 console.log('Resolved "' + target + '" → registry ' + resolved.publisher.registryKey.slice(0, 12) + '… via pgh-sidecar NameRegistry')
lib/commands/device.js +2 -1
……@@ -13,6 +13,7 @@
1313 */
1414
1515import process from '#node:process'
16import { isAbstract } from '../daemon-client.js'
1617import fs from '#node:fs'
1718import path from '#node:path'
1819import { homedir } from '#node:os'
……@@ -125,7 +126,7 @@ async function runLabel (args, globals) {
125126// the autobase bootstrap keys + repo-tracker map needed for the bundle).
126127async function daemonClient (appName) {
127128 const SIDECAR_SOCK = process.env.PGH_SIDECAR_SOCK || path.join(homedir(), '.pgh', 'svc.sock')
128 if (!fs.existsSync(SIDECAR_SOCK)) {
129 if (!isAbstract(SIDECAR_SOCK) && !fs.existsSync(SIDECAR_SOCK)) {
129130 throw new Error('pgh-sidecar is not running (no socket at ' + SIDECAR_SOCK + ')')
130131 }
131132 const { Client } = await import('hyper-svc')
lib/commands/names.js +2 -1
……@@ -18,6 +18,7 @@ import { homedir } from '#node:os'
1818import fs from '#node:fs'
1919
2020import { Client } from 'hyper-svc'
21import { isAbstract } from '../daemon-client.js'
2122
2223const SIDECAR_SOCK = process.env.PGH_SIDECAR_SOCK || path.join(homedir(), '.pgh', 'svc.sock')
2324
……@@ -36,7 +37,7 @@ export const usage = `pgh names / claim / release — NameRegistry (sidecar-owne
3637 pgh names subscriptions List own + subscribed name registries`
3738
3839async function withClient (fn) {
39 if (!fs.existsSync(SIDECAR_SOCK)) {
40 if (!isAbstract(SIDECAR_SOCK) && !fs.existsSync(SIDECAR_SOCK)) {
4041 throw new Error('pgh-sidecar is not running (no socket at ' + SIDECAR_SOCK + ')')
4142 }
4243 const c = await Client.connectUds(SIDECAR_SOCK)
lib/commands/overlay.js +2 -1
……@@ -49,6 +49,7 @@ import { execSync } from '../_compat-exec.js'
4949import { pipeline } from '#node:stream/promises'
5050import { Transform } from '#node:stream'
5151import { Client } from 'hyper-svc'
52import { isAbstract } from '../daemon-client.js'
5253
5354// Hash + chunk + pointer primitives are owned by hyper-overlay (canonical
5455// source). Importing keeps pgh's clean/smudge wire-compatible with every
……@@ -72,7 +73,7 @@ async function sidecarClient () {
7273 // overlay subcommands talk to pgh-sidecar (not pear-git-v3), so they
7374 // open their own UDS client. Dispatcher's pure-local routing passes
7475 // null for `client` since the receiver is fixed.
75 if (!fs.existsSync(SIDECAR_SOCK)) {
76 if (!isAbstract(SIDECAR_SOCK) && !fs.existsSync(SIDECAR_SOCK)) {
7677 throw new Error('pgh-sidecar not running (no socket at ' + SIDECAR_SOCK + ')')
7778 }
7879 return Client.connectUds(SIDECAR_SOCK)
lib/commands/publish.js +2 -1
……@@ -7,6 +7,7 @@ import { homedir, tmpdir } from '#node:os'
77import Corestore from 'corestore'
88
99import { Client } from 'hyper-svc'
10import { isAbstract } from '../daemon-client.js'
1011
1112import { computeLockfile, writeLockfile, buildPublishIgnore } from '../publish.js'
1213import { PublishedIndex } from '../published-index.js'
……@@ -381,7 +382,7 @@ export async function run (client, args) {
381382 // registry lock, so talking to it over UDS avoids contention with
382383 // `pgh seed` / another pgh process. Fall back to direct only when
383384 // sidecar isn't running.
384 const sidecarAvailable = fs.existsSync(SIDECAR_SOCK)
385 const sidecarAvailable = isAbstract(SIDECAR_SOCK) || fs.existsSync(SIDECAR_SOCK)
385386 if (sidecarAvailable) {
386387 try {
387388 const client = await Client.connectUds(SIDECAR_SOCK)
lib/commands/releases.js +2 -1
……@@ -7,6 +7,7 @@ import { homedir } from '#node:os'
77import Corestore from 'corestore'
88
99import { Client } from 'hyper-svc'
10import { isAbstract } from '../daemon-client.js'
1011
1112export const usage = `pgh releases — inspect the local ReleaseRegistry
1213
……@@ -28,7 +29,7 @@ const SIDECAR_SOCK = process.env.PGH_SIDECAR_SOCK || path.join(homedir(), '.pgh'
2829// Prefer pgh-sidecar (which owns the registry lock). Fall back to
2930// opening the corestore directly when the sidecar isn't running.
3031async function withRegistry (fn) {
31 if (fs.existsSync(SIDECAR_SOCK)) {
32 if (isAbstract(SIDECAR_SOCK) || fs.existsSync(SIDECAR_SOCK)) {
3233 let client = null
3334 try {
3435 client = await Client.connectUds(SIDECAR_SOCK)
lib/commands/user.js +2 -1
……@@ -12,6 +12,7 @@
1212 */
1313
1414import process from '#node:process'
15import { isAbstract } from '../daemon-client.js'
1516import fs from '#node:fs'
1617import path from '#node:path'
1718import { homedir } from '#node:os'
……@@ -27,7 +28,7 @@ export const usage = `pgh user — manage users on a pgh-managed app
2728The app must be running and registered with pgh-sidecar.`
2829
2930async function appClient (appName) {
30 if (!fs.existsSync(SIDECAR_SOCK)) {
31 if (!isAbstract(SIDECAR_SOCK) && !fs.existsSync(SIDECAR_SOCK)) {
3132 throw new Error('pgh-sidecar is not running (no socket at ' + SIDECAR_SOCK + ')')
3233 }
3334 const { Client } = await import('hyper-svc')
lib/daemon-client.js +1 -1
……@@ -20,7 +20,7 @@ const SIDECAR_SOCK = process.env.PGH_SIDECAR_SOCK ||
2020
2121// An '@'-prefixed socket is a Linux abstract-namespace socket (no filesystem
2222// entry), used where SELinux denies pathname sockets (unrooted Android/celltron).
23function isAbstract (p) {
23export function isAbstract (p) {
2424 return typeof p === 'string' && p.length > 1 && p[0] === '@'
2525}
2626
package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "pgh",
3 "version": "0.1.146",
3 "version": "0.1.147",
44 "description": "pgh \u2014 P2P content-addressed package manager and app launcher",
55 "type": "module",
66 "main": "index.js",