@pugi/cli 1.0.0-alpha.252 → 1.0.0-alpha.254
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 +18 -7
- package/bin/pugi +95 -22
- package/models.json +1 -1
- package/package.json +16 -12
- package/postinstall.mjs +158 -23
- package/release.json +5 -5
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pugi/cli",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
4
|
-
"description": "Pugi CLI
|
|
3
|
+
"version": "1.0.0-alpha.254",
|
|
4
|
+
"description": "Pugi CLI: an AI product team in your terminal that plans, builds, tests, security-checks and publishes from a plain-language brief",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://pugi.io",
|
|
7
7
|
"repository": {
|
|
@@ -12,9 +12,13 @@
|
|
|
12
12
|
"pugi",
|
|
13
13
|
"cli",
|
|
14
14
|
"ai",
|
|
15
|
-
"agents",
|
|
16
|
-
"
|
|
17
|
-
"
|
|
15
|
+
"ai-agents",
|
|
16
|
+
"coding-agent",
|
|
17
|
+
"website-builder",
|
|
18
|
+
"app-builder",
|
|
19
|
+
"security",
|
|
20
|
+
"mcp",
|
|
21
|
+
"terminal"
|
|
18
22
|
],
|
|
19
23
|
"bin": {
|
|
20
24
|
"pugi": "./bin/pugi"
|
|
@@ -42,12 +46,12 @@
|
|
|
42
46
|
"THIRD_PARTY_NOTICES.md"
|
|
43
47
|
],
|
|
44
48
|
"optionalDependencies": {
|
|
45
|
-
"@pugi/cli-darwin-arm64": "1.0.0-alpha.
|
|
46
|
-
"@pugi/cli-darwin-x64": "1.0.0-alpha.
|
|
47
|
-
"@pugi/cli-linux-arm64": "1.0.0-alpha.
|
|
48
|
-
"@pugi/cli-linux-x64": "1.0.0-alpha.
|
|
49
|
-
"@pugi/cli-windows-arm64": "1.0.0-alpha.
|
|
50
|
-
"@pugi/cli-windows-x64": "1.0.0-alpha.
|
|
49
|
+
"@pugi/cli-darwin-arm64": "1.0.0-alpha.254",
|
|
50
|
+
"@pugi/cli-darwin-x64": "1.0.0-alpha.254",
|
|
51
|
+
"@pugi/cli-linux-arm64": "1.0.0-alpha.254",
|
|
52
|
+
"@pugi/cli-linux-x64": "1.0.0-alpha.254",
|
|
53
|
+
"@pugi/cli-windows-arm64": "1.0.0-alpha.254",
|
|
54
|
+
"@pugi/cli-windows-x64": "1.0.0-alpha.254"
|
|
51
55
|
},
|
|
52
|
-
"gitHead": "
|
|
56
|
+
"gitHead": "8d53bb12da5629b20b4cd4cd4e25a59afb762dd9"
|
|
53
57
|
}
|
package/postinstall.mjs
CHANGED
|
@@ -1,31 +1,166 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
// Postinstall of the @pugi/cli npm package (PUG-44). `bin/pugi` ships as a Node
|
|
3
|
+
// launcher (launcher.cjs) that works wherever Node is installed. This script
|
|
4
|
+
// swaps it for the native binary where that is safe: on POSIX under npm or bun,
|
|
5
|
+
// whose global bin link is a symlink that stays valid when its target becomes a
|
|
6
|
+
// native binary. That also spares a bun user without Node the launcher's
|
|
7
|
+
// `#!/usr/bin/env node` (review on #363). Elsewhere (Windows, where npm's shims
|
|
8
|
+
// run the launcher with node; pnpm, whose shim fixes the interpreter from the
|
|
9
|
+
// shebang; an unknown or missing user agent, e.g. this script run by hand) it
|
|
10
|
+
// leaves the launcher alone.
|
|
11
|
+
//
|
|
12
|
+
// It never fails the install: the launcher already works without it. Until the
|
|
13
|
+
// final rename succeeds, `bin/pugi` is the original launcher.
|
|
14
|
+
import childProcess from "child_process"
|
|
2
15
|
import fs from "fs"
|
|
3
16
|
import os from "os"
|
|
4
17
|
import path from "path"
|
|
5
18
|
import { createRequire } from "module"
|
|
6
19
|
import { fileURLToPath } from "url"
|
|
7
20
|
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
const PLATFORMS = { darwin: "darwin", linux: "linux", win32: "windows" }
|
|
22
|
+
const ARCHES = { x64: "x64", arm64: "arm64" }
|
|
23
|
+
const VERIFY_TIMEOUT_MS = 20_000
|
|
24
|
+
|
|
25
|
+
export function shouldReplaceLauncher({ platform, userAgent }) {
|
|
26
|
+
return platform !== "win32" && typeof userAgent === "string" && /^(npm|bun)\//.test(userAgent)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The env for the `--version` check. The engine creates its XDG directories
|
|
31
|
+
* and `<tmpdir>/pugi` as soon as it loads (core/src/global.ts), before it reads
|
|
32
|
+
* its arguments. Under `sudo npm i -g` with HOME kept (the macOS default) they
|
|
33
|
+
* would be created as root in the user's home and /tmp, and the user's own
|
|
34
|
+
* `pugi` would later fail with EACCES (review on #363). So the check runs with
|
|
35
|
+
* all of them inside a throwaway directory.
|
|
36
|
+
*/
|
|
37
|
+
export function sandboxEnv(dir, env = process.env) {
|
|
38
|
+
return {
|
|
39
|
+
...env,
|
|
40
|
+
HOME: dir,
|
|
41
|
+
USERPROFILE: dir,
|
|
42
|
+
XDG_CONFIG_HOME: path.join(dir, "config"),
|
|
43
|
+
XDG_DATA_HOME: path.join(dir, "data"),
|
|
44
|
+
XDG_CACHE_HOME: path.join(dir, "cache"),
|
|
45
|
+
XDG_STATE_HOME: path.join(dir, "state"),
|
|
46
|
+
TMPDIR: path.join(dir, "tmp"),
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Put `source` in place of `binDir/pugi` atomically: prepare a temp file beside
|
|
52
|
+
* it, check that it runs, then rename it over the launcher. Returns the step
|
|
53
|
+
* that failed, or ok. On failure the launcher is untouched and the temp file is
|
|
54
|
+
* removed.
|
|
55
|
+
*/
|
|
56
|
+
export function replaceLauncher({ binDir, source, pid = process.pid, fsApi = fs, spawnSync = childProcess.spawnSync }) {
|
|
57
|
+
const target = path.join(binDir, "pugi")
|
|
58
|
+
const tmp = path.join(binDir, `.pugi-native-${pid}.tmp`)
|
|
59
|
+
const cleanup = () => {
|
|
60
|
+
try {
|
|
61
|
+
fsApi.rmSync(tmp, { force: true })
|
|
62
|
+
} catch {
|
|
63
|
+
// Nothing more to do; the launcher is still in place.
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
fsApi.rmSync(tmp, { force: true })
|
|
69
|
+
try {
|
|
70
|
+
fsApi.linkSync(source, tmp)
|
|
71
|
+
} catch {
|
|
72
|
+
fsApi.copyFileSync(source, tmp)
|
|
73
|
+
}
|
|
74
|
+
fsApi.chmodSync(tmp, 0o755)
|
|
75
|
+
} catch (error) {
|
|
76
|
+
cleanup()
|
|
77
|
+
return { ok: false, step: "prepare", error }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const removeDir = (dir) => {
|
|
81
|
+
try {
|
|
82
|
+
fsApi.rmSync(dir, { recursive: true, force: true })
|
|
83
|
+
} catch {
|
|
84
|
+
// A leftover directory under the system temp dir is harmless.
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const sandbox = (() => {
|
|
88
|
+
const dir = (() => {
|
|
89
|
+
try {
|
|
90
|
+
return fsApi.mkdtempSync(path.join(os.tmpdir(), "pugi-postinstall-"))
|
|
91
|
+
} catch {
|
|
92
|
+
return undefined
|
|
93
|
+
}
|
|
94
|
+
})()
|
|
95
|
+
if (!dir) return undefined
|
|
96
|
+
try {
|
|
97
|
+
fsApi.mkdirSync(path.join(dir, "tmp"))
|
|
98
|
+
return dir
|
|
99
|
+
} catch {
|
|
100
|
+
// Created but unusable: remove it too (Codex review, round 3).
|
|
101
|
+
removeDir(dir)
|
|
102
|
+
return undefined
|
|
103
|
+
}
|
|
104
|
+
})()
|
|
105
|
+
if (!sandbox) {
|
|
106
|
+
cleanup()
|
|
107
|
+
return { ok: false, step: "verify" }
|
|
108
|
+
}
|
|
109
|
+
const check = spawnSync(tmp, ["--version"], {
|
|
110
|
+
stdio: "ignore",
|
|
111
|
+
timeout: VERIFY_TIMEOUT_MS,
|
|
112
|
+
killSignal: "SIGKILL",
|
|
113
|
+
env: sandboxEnv(sandbox),
|
|
114
|
+
})
|
|
115
|
+
removeDir(sandbox)
|
|
116
|
+
if (check.error || check.status !== 0) {
|
|
117
|
+
cleanup()
|
|
118
|
+
return { ok: false, step: "verify", error: check.error }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
fsApi.renameSync(tmp, target)
|
|
123
|
+
} catch (error) {
|
|
124
|
+
cleanup()
|
|
125
|
+
return { ok: false, step: "rename", error }
|
|
126
|
+
}
|
|
127
|
+
// When the target is already a hard link to the same file (a second run,
|
|
128
|
+
// e.g. `npm rebuild`), POSIX rename succeeds without moving anything and
|
|
129
|
+
// leaves the temp name behind (Codex review F2).
|
|
130
|
+
cleanup()
|
|
131
|
+
return { ok: true }
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function main() {
|
|
135
|
+
if (!shouldReplaceLauncher({ platform: process.platform, userAgent: process.env.npm_config_user_agent })) return
|
|
136
|
+
const here = path.dirname(fileURLToPath(import.meta.url))
|
|
137
|
+
const require = createRequire(import.meta.url)
|
|
138
|
+
const name = `@pugi/cli-${PLATFORMS[process.platform] || process.platform}-${ARCHES[process.arch] || process.arch}`
|
|
139
|
+
const source = (() => {
|
|
140
|
+
try {
|
|
141
|
+
return path.join(path.dirname(require.resolve(`${name}/package.json`)), "bin", "pugi")
|
|
142
|
+
} catch {
|
|
143
|
+
return undefined
|
|
144
|
+
}
|
|
145
|
+
})()
|
|
146
|
+
if (!source) {
|
|
147
|
+
console.warn(`@pugi/cli: ${name} is not installed; pugi will report it when it starts.`)
|
|
148
|
+
return
|
|
149
|
+
}
|
|
150
|
+
const result = replaceLauncher({ binDir: path.join(here, "bin"), source })
|
|
151
|
+
if (!result.ok) {
|
|
152
|
+
const reason = result.error && result.error.message ? `: ${result.error.message}` : ""
|
|
153
|
+
console.warn(`@pugi/cli: kept the Node launcher (the native binary failed at "${result.step}"${reason}). pugi still works.`)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Run only as the lifecycle script, not when a test imports this module. Real
|
|
158
|
+
// paths, because a package manager may start it through a symlink.
|
|
159
|
+
const realpath = (file) => {
|
|
160
|
+
try {
|
|
161
|
+
return fs.realpathSync(file)
|
|
162
|
+
} catch {
|
|
163
|
+
return undefined
|
|
164
|
+
}
|
|
31
165
|
}
|
|
166
|
+
if (process.argv[1] && realpath(process.argv[1]) === realpath(fileURLToPath(import.meta.url))) main()
|
package/release.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.0.0-alpha.
|
|
2
|
+
"version": "1.0.0-alpha.254",
|
|
3
3
|
"channel": "latest",
|
|
4
|
-
"coreCommit": "
|
|
5
|
-
"sandboxCommit": "
|
|
6
|
-
"consoleCommit": "
|
|
7
|
-
"consoleWebVersion": "1.14.
|
|
4
|
+
"coreCommit": "8d53bb12da5629b20b4cd4cd4e25a59afb762dd9",
|
|
5
|
+
"sandboxCommit": "f0aefee3583ea1ce1e0ed2294eb7dfa4695023e2",
|
|
6
|
+
"consoleCommit": "4fb73cff00fc758549d8e5cd421bdace8eef0f15",
|
|
7
|
+
"consoleWebVersion": "1.14.48"
|
|
8
8
|
}
|