@alivault/pico 0.1.6 → 0.1.7

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 CHANGED
@@ -64,6 +64,12 @@ You can choose a different port with:
64
64
  pico-app --port 3000
65
65
  ```
66
66
 
67
+ Update a global install with:
68
+
69
+ ```bash
70
+ pico-app update
71
+ ```
72
+
67
73
  ## Developing from source
68
74
 
69
75
  Install dependencies:
package/bin/pico.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { spawn } from "node:child_process"
3
+ import { spawn, spawnSync } from "node:child_process"
4
4
  import { existsSync, readFileSync } from "node:fs"
5
5
  import process from "node:process"
6
6
  import { dirname, join } from "node:path"
@@ -10,22 +10,35 @@ const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)))
10
10
  const packageJsonPath = join(packageRoot, "package.json")
11
11
  const serverEntry = join(packageRoot, ".output", "server", "index.mjs")
12
12
 
13
- function readPackageVersion() {
13
+ function readPackageMetadata() {
14
14
  try {
15
15
  const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"))
16
- return typeof packageJson.version === "string"
17
- ? packageJson.version
18
- : "0.0.0"
16
+ return {
17
+ name:
18
+ typeof packageJson.name === "string"
19
+ ? packageJson.name
20
+ : "@alivault/pico",
21
+ version:
22
+ typeof packageJson.version === "string" ? packageJson.version : "0.0.0",
23
+ }
19
24
  } catch {
20
- return "0.0.0"
25
+ return { name: "@alivault/pico", version: "0.0.0" }
21
26
  }
22
27
  }
23
28
 
29
+ function readPackageVersion() {
30
+ return readPackageMetadata().version
31
+ }
32
+
24
33
  function printHelp() {
25
34
  console.log(`Pico - local browser workspace for Pi coding-agent sessions
26
35
 
27
36
  Usage:
28
37
  pico-app [options]
38
+ pico-app update
39
+
40
+ Commands:
41
+ update Update the globally installed Pico package to latest
29
42
 
30
43
  Options:
31
44
  --port <port> Port to listen on (default: 3141)
@@ -52,6 +65,83 @@ function readOptionValue(args, index, name) {
52
65
  return value
53
66
  }
54
67
 
68
+ function packageManagerCommandFor(packageName) {
69
+ const packageSpec = `${packageName}@latest`
70
+ const npmExecPath = process.env.npm_execpath || ""
71
+ const npmUserAgent = process.env.npm_config_user_agent || ""
72
+ const detectionText = `${npmExecPath} ${npmUserAgent}`.toLowerCase()
73
+ const packageRootSegments = packageRoot.split(/[\\/]+/)
74
+ const normalizedPackageRoot = packageRoot.replaceAll("\\", "/")
75
+ const isPnpmLayout =
76
+ packageRootSegments.includes(".pnpm") ||
77
+ normalizedPackageRoot.includes("/pnpm/global/")
78
+ const isBunLayout = normalizedPackageRoot.includes("/.bun/install/global/")
79
+ const isYarnLayout = normalizedPackageRoot.includes("/yarn/global/")
80
+
81
+ if (detectionText.includes("pnpm") || isPnpmLayout) {
82
+ return { command: "pnpm", args: ["add", "-g", packageSpec] }
83
+ }
84
+
85
+ if (detectionText.includes("bun") || isBunLayout) {
86
+ return { command: "bun", args: ["add", "-g", packageSpec] }
87
+ }
88
+
89
+ if (detectionText.includes("yarn") || isYarnLayout) {
90
+ return { command: "yarn", args: ["global", "add", packageSpec] }
91
+ }
92
+
93
+ return { command: "npm", args: ["install", "-g", packageSpec] }
94
+ }
95
+
96
+ function runUpdate(args) {
97
+ if (args.includes("--help")) {
98
+ console.log(`Pico self update
99
+
100
+ Usage:
101
+ pico-app update
102
+
103
+ Updates the globally installed Pico package to the latest npm release.`)
104
+ process.exit(0)
105
+ }
106
+
107
+ if (args.length > 0) {
108
+ console.error(`Unknown update option: ${args[0]}`)
109
+ console.error("Run `pico-app update --help` for usage.")
110
+ process.exit(1)
111
+ }
112
+
113
+ const metadata = readPackageMetadata()
114
+ const updateCommand = packageManagerCommandFor(metadata.name)
115
+
116
+ console.log(
117
+ `Updating ${metadata.name} from ${metadata.version} to latest with ${updateCommand.command}...`
118
+ )
119
+
120
+ const result = spawnSync(updateCommand.command, updateCommand.args, {
121
+ stdio: "inherit",
122
+ shell: process.platform === "win32",
123
+ })
124
+
125
+ if (result.error) {
126
+ console.error(
127
+ `Failed to run ${updateCommand.command}: ${result.error.message}`
128
+ )
129
+ process.exit(1)
130
+ }
131
+
132
+ if (result.signal) {
133
+ process.kill(process.pid, result.signal)
134
+ return
135
+ }
136
+
137
+ if (result.status !== 0) {
138
+ process.exit(result.status ?? 1)
139
+ }
140
+
141
+ console.log("Pico update complete.")
142
+ process.exit(0)
143
+ }
144
+
55
145
  function parseArgs(args) {
56
146
  const options = {
57
147
  open: process.env.PICO_OPEN !== "0",
@@ -150,7 +240,13 @@ function openBrowser(url) {
150
240
  child.unref()
151
241
  }
152
242
 
153
- const options = parseArgs(process.argv.slice(2))
243
+ const args = process.argv.slice(2)
244
+
245
+ if (args[0] === "update") {
246
+ runUpdate(args.slice(1))
247
+ }
248
+
249
+ const options = parseArgs(args)
154
250
 
155
251
  if (!existsSync(serverEntry)) {
156
252
  console.error("Pico server build was not found in this package.")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alivault/pico",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "A local, keyboard-friendly browser workspace for Pi coding-agent sessions.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "module",