@jelou/cli 1.108.2 → 1.110.0
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/bin/postinstall.js +103 -8
- package/package.json +11 -39
package/bin/postinstall.js
CHANGED
|
@@ -9,8 +9,15 @@
|
|
|
9
9
|
// cold-start) with a relative symlink to the platform binary itself.
|
|
10
10
|
// When npm wires `<global>/bin/jelou` -> `<wrapper>/bin/jelou`, the
|
|
11
11
|
// chain now resolves straight to the native binary, no node hop.
|
|
12
|
+
// 3. Record where that shim is, and what it points at, in
|
|
13
|
+
// `~/.jelou/install-manifest.json`. The CLI cannot rediscover this at
|
|
14
|
+
// runtime: `Deno.execPath()` returns the invoked path on macOS and the
|
|
15
|
+
// resolved one on Linux, so walking up to node_modules works on one and
|
|
16
|
+
// not the other. Writing it down here is the only reliable source.
|
|
17
|
+
// Best-effort — a manifest failure must never fail an install.
|
|
12
18
|
|
|
13
19
|
const fs = require("fs");
|
|
20
|
+
const os = require("os");
|
|
14
21
|
const path = require("path");
|
|
15
22
|
const {
|
|
16
23
|
PLATFORMS,
|
|
@@ -50,6 +57,71 @@ if (!fs.existsSync(binPath)) {
|
|
|
50
57
|
process.exit(1);
|
|
51
58
|
}
|
|
52
59
|
|
|
60
|
+
// --- install manifest ---
|
|
61
|
+
// Keyed by shim path, and merged rather than replaced: one machine can carry
|
|
62
|
+
// several independent global installs (e.g. a Homebrew node prefix and a
|
|
63
|
+
// user-owned ~/.local one), each with its own postinstall. A single-record
|
|
64
|
+
// manifest would let the last install to run claim a shim it does not own.
|
|
65
|
+
function manifestPath() {
|
|
66
|
+
const home = os.homedir();
|
|
67
|
+
return home ? path.join(home, ".jelou", "install-manifest.json") : null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function readManifest(file) {
|
|
71
|
+
try {
|
|
72
|
+
const parsed = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
73
|
+
if (parsed && typeof parsed === "object" && parsed.installs) return parsed;
|
|
74
|
+
} catch (_) {
|
|
75
|
+
// Missing or corrupt — start fresh rather than refusing to install.
|
|
76
|
+
}
|
|
77
|
+
return { version: 1, installs: {} };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function recordManifest(shimKind) {
|
|
81
|
+
const file = manifestPath();
|
|
82
|
+
if (!file) return;
|
|
83
|
+
try {
|
|
84
|
+
let wrapperVersion = null;
|
|
85
|
+
try {
|
|
86
|
+
wrapperVersion = require("../package.json").version || null;
|
|
87
|
+
} catch (_) {
|
|
88
|
+
// Version is informational; a missing one must not skip the manifest.
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const manifest = readManifest(file);
|
|
92
|
+
manifest.version = 1;
|
|
93
|
+
|
|
94
|
+
// Drop entries whose shim is gone (uninstalled prefix), but never touch a
|
|
95
|
+
// live sibling install. lstat, not existsSync: existsSync follows the
|
|
96
|
+
// link, so a sibling whose target is momentarily missing — that prefix
|
|
97
|
+
// running its own install — would look gone and be pruned.
|
|
98
|
+
for (const key of Object.keys(manifest.installs)) {
|
|
99
|
+
if (key === shimPath) continue;
|
|
100
|
+
try {
|
|
101
|
+
fs.lstatSync(key);
|
|
102
|
+
} catch {
|
|
103
|
+
delete manifest.installs[key];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
manifest.installs[shimPath] = {
|
|
108
|
+
shimKind: shimKind,
|
|
109
|
+
baselineTarget: relativeTarget,
|
|
110
|
+
baselineBinary: binPath,
|
|
111
|
+
version: wrapperVersion,
|
|
112
|
+
writtenAt: new Date().toISOString(),
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
116
|
+
const tmp = file + ".tmp-" + process.pid;
|
|
117
|
+
fs.writeFileSync(tmp, JSON.stringify(manifest, null, 2) + "\n");
|
|
118
|
+
fs.renameSync(tmp, file);
|
|
119
|
+
} catch (_) {
|
|
120
|
+
// Best-effort by design. Losing the manifest only disables background
|
|
121
|
+
// updates; failing the install here would be far worse.
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
53
125
|
// --- fast-shim rewrite (Unix only for now) ---
|
|
54
126
|
// On Windows npm generates `.cmd` and `.ps1` shims that hardcode
|
|
55
127
|
// `node "<wrapper>/bin/jelou"`; replacing the wrapper script doesn't
|
|
@@ -71,28 +143,51 @@ const relativeTarget = path.relative(wrapperBin, binPath);
|
|
|
71
143
|
try {
|
|
72
144
|
const stat = fs.lstatSync(shimPath);
|
|
73
145
|
if (stat.isSymbolicLink() && fs.readlinkSync(shimPath) === relativeTarget) {
|
|
146
|
+
// The shim is already right, but the manifest still has to be refreshed:
|
|
147
|
+
// relativeTarget is identical across versions, so this branch is the one
|
|
148
|
+
// taken on every ordinary upgrade.
|
|
149
|
+
recordManifest("symlink");
|
|
74
150
|
process.exit(0);
|
|
75
151
|
}
|
|
76
152
|
} catch (_) {
|
|
77
153
|
// shim not present yet — fine, we'll create it.
|
|
78
154
|
}
|
|
79
155
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
156
|
+
// Write through a tmp sibling + rename so the shim is never briefly absent.
|
|
157
|
+
// The old rmSync-then-symlinkSync left a window where `<wrapper>/bin/jelou`
|
|
158
|
+
// did not exist, and a concurrent `jelou` invocation got ENOENT. rename(2)
|
|
159
|
+
// is atomic, so a reader sees the old shim or the new one, never neither.
|
|
160
|
+
const tmpPath = shimPath + ".tmp-" + process.pid;
|
|
161
|
+
|
|
162
|
+
function swapIn(write) {
|
|
163
|
+
try {
|
|
164
|
+
fs.rmSync(tmpPath, { force: true });
|
|
165
|
+
} catch (_) {
|
|
166
|
+
// nothing to remove
|
|
167
|
+
}
|
|
168
|
+
write(tmpPath);
|
|
169
|
+
fs.renameSync(tmpPath, shimPath);
|
|
84
170
|
}
|
|
85
171
|
|
|
172
|
+
let shimKind;
|
|
86
173
|
try {
|
|
87
|
-
fs.symlinkSync(relativeTarget,
|
|
88
|
-
|
|
174
|
+
swapIn((p) => fs.symlinkSync(relativeTarget, p));
|
|
175
|
+
shimKind = "symlink";
|
|
89
176
|
} catch (err) {
|
|
90
177
|
// EPERM (Windows w/o developer mode), EXDEV (cross-device install),
|
|
91
178
|
// EROFS (read-only FS in some sandboxes). Fall back to a tiny shell
|
|
92
179
|
// wrapper. Adds ~1-3ms vs ~0ms for symlink, but still much better than
|
|
93
180
|
// the 20ms node-boot hop the wrapper script costs.
|
|
181
|
+
try {
|
|
182
|
+
fs.rmSync(tmpPath, { force: true });
|
|
183
|
+
} catch (_) {
|
|
184
|
+
// nothing to remove
|
|
185
|
+
}
|
|
94
186
|
const safeTarget = relativeTarget.replace(/(["\\$`])/g, "\\$1");
|
|
95
187
|
const shell = `#!/bin/sh\nexec "$(dirname "$0")/${safeTarget}" "$@"\n`;
|
|
96
|
-
fs.writeFileSync(
|
|
97
|
-
|
|
188
|
+
swapIn((p) => fs.writeFileSync(p, shell, { mode: 0o755 }));
|
|
189
|
+
shimKind = "shell";
|
|
98
190
|
}
|
|
191
|
+
|
|
192
|
+
recordManifest(shimKind);
|
|
193
|
+
process.exit(0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jelou/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.110.0",
|
|
4
4
|
"description": "Build AI agents on the Jelou platform — from your terminal or your AI editor.",
|
|
5
5
|
"author": "Jelou Inc. (https://jelou.ai)",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
"THIRD_PARTY_NOTICES.md"
|
|
24
24
|
],
|
|
25
25
|
"optionalDependencies": {
|
|
26
|
-
"@jelou/cli-darwin-arm64": "1.
|
|
27
|
-
"@jelou/cli-darwin-x64": "1.
|
|
28
|
-
"@jelou/cli-linux-x64": "1.
|
|
29
|
-
"@jelou/cli-linux-arm64": "1.
|
|
30
|
-
"@jelou/cli-win32-x64": "1.
|
|
26
|
+
"@jelou/cli-darwin-arm64": "1.110.0",
|
|
27
|
+
"@jelou/cli-darwin-x64": "1.110.0",
|
|
28
|
+
"@jelou/cli-linux-x64": "1.110.0",
|
|
29
|
+
"@jelou/cli-linux-arm64": "1.110.0",
|
|
30
|
+
"@jelou/cli-win32-x64": "1.110.0"
|
|
31
31
|
},
|
|
32
32
|
"keywords": [
|
|
33
33
|
"jelou",
|
|
@@ -58,45 +58,17 @@
|
|
|
58
58
|
"jelou": {
|
|
59
59
|
"minVersion": "1.100.2",
|
|
60
60
|
"release_notes": {
|
|
61
|
-
"version": "1.
|
|
62
|
-
"date": "2026-09-
|
|
63
|
-
"headline": "
|
|
61
|
+
"version": "1.110.0",
|
|
62
|
+
"date": "2026-09-03",
|
|
63
|
+
"headline": "`jelou logs chat` now rebuilds conversations that the server returns short or empty.",
|
|
64
64
|
"highlights": [
|
|
65
65
|
{
|
|
66
66
|
"type": "fixed",
|
|
67
|
-
"text": "
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
"type": "fixed",
|
|
71
|
-
"text": "Answering \"Exit\" at the update prompt now actually dismisses it. Nothing was being recorded, so the prompt came back on the very next command."
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
"type": "fixed",
|
|
75
|
-
"text": "Every failure path now exits with the code it reports. Commands that returned `error.code` 4 (re-auth) or 3 (not found) still exited 1, so agents branching on the exit code took the wrong path."
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
"type": "fixed",
|
|
79
|
-
"text": "`jelou push` now reports unresolved tool output-branch warnings in the `--json` envelope. They were printed for humans and dropped for everyone else."
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
"type": "fixed",
|
|
83
|
-
"text": "`jelou changelog` reads the shipped changelog files again — section parsing looked for a heading no file actually uses."
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
"type": "improved",
|
|
87
|
-
"text": "Cold start is down from 167ms to 49ms: command groups load on demand instead of all 37 up front, and the version check no longer blocks your command on a network round trip."
|
|
67
|
+
"text": "`jelou logs chat` no longer presents a trimmed conversation as the whole story. It re-reads the executions in range that the timeline failed to account for, so messages the server drops — or cannot serve from cold storage — still appear, and a new `sources` block says where each item came from."
|
|
88
68
|
},
|
|
89
69
|
{
|
|
90
70
|
"type": "improved",
|
|
91
|
-
"text": "
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
"type": "improved",
|
|
95
|
-
"text": "Skills no longer show agents examples that pass `--yes` on destructive commands."
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
"type": "heads_up",
|
|
99
|
-
"text": "Destructive commands (`jelou project delete`, the `voice` surface, `logout`, and functions removals) now fail loudly under `--agent` / `--no-input` when `--yes` is missing. They used to exit 0 having done nothing. Add `--yes` to any script that relied on the old behavior."
|
|
71
|
+
"text": "Reaching your project limit now shows the reason the platform gives, instead of a generic permission error."
|
|
100
72
|
}
|
|
101
73
|
]
|
|
102
74
|
}
|