@ouro.bot/cli 0.1.0-alpha.110 → 0.1.0-alpha.112
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/changelog.json
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.112",
|
|
6
|
+
"changes": [
|
|
7
|
+
"`ouro up` no longer prints the 'ouro updated to X (was Y)' message twice when the update flow re-execs from a newly installed version."
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"version": "0.1.0-alpha.111",
|
|
12
|
+
"changes": [
|
|
13
|
+
"The PATH installer now repairs a stale ~/.local/bin/ouro launcher in place instead of deleting it, so a shadowing old wrapper can no longer cause the wrong CLI version to load and produce backwards 'ouro updated to X (was Y)' messages."
|
|
14
|
+
]
|
|
15
|
+
},
|
|
4
16
|
{
|
|
5
17
|
"version": "0.1.0-alpha.110",
|
|
6
18
|
"changes": [
|
|
@@ -1484,9 +1484,9 @@ async function performSystemSetup(deps) {
|
|
|
1484
1484
|
if (deps.installOuroCommand) {
|
|
1485
1485
|
try {
|
|
1486
1486
|
const installResult = deps.installOuroCommand();
|
|
1487
|
-
/* v8 ignore next --
|
|
1488
|
-
if (installResult.
|
|
1489
|
-
deps.writeStdout("
|
|
1487
|
+
/* v8 ignore next -- old-launcher repair hint: fires when stale ~/.local/bin/ouro is fixed @preserve */
|
|
1488
|
+
if (installResult.repairedOldLauncher) {
|
|
1489
|
+
deps.writeStdout("repaired stale ouro launcher at ~/.local/bin/ouro");
|
|
1490
1490
|
}
|
|
1491
1491
|
}
|
|
1492
1492
|
catch (error) {
|
|
@@ -1884,9 +1884,12 @@ async function runOuroCli(args, deps = createDefaultOuroCliDeps()) {
|
|
|
1884
1884
|
// hooks overwrite it. This detects when npx downloaded a newer CLI.
|
|
1885
1885
|
const previousCliVersion = readFirstBundleMetaVersion(bundlesRoot);
|
|
1886
1886
|
const updateSummary = await (0, update_hooks_1.applyPendingUpdates)(bundlesRoot, currentVersion);
|
|
1887
|
-
// Notify about CLI binary update (npx downloaded a new version)
|
|
1887
|
+
// Notify about CLI binary update (npx downloaded a new version).
|
|
1888
|
+
// Skip when the symlink already points to the running version — that
|
|
1889
|
+
// means path 1 (checkForCliUpdate + reExecFromNewVersion) already
|
|
1890
|
+
// printed the update message before re-exec.
|
|
1888
1891
|
/* v8 ignore start -- CLI update detection: tested via daemon-cli-version-detect.test.ts @preserve */
|
|
1889
|
-
if (previousCliVersion && previousCliVersion !== currentVersion) {
|
|
1892
|
+
if (previousCliVersion && previousCliVersion !== currentVersion && linkedVersionBeforeUp !== currentVersion) {
|
|
1890
1893
|
deps.writeStdout(`ouro updated to ${currentVersion} (was ${previousCliVersion})`);
|
|
1891
1894
|
const changelogCommand = (0, ouro_version_manager_1.buildChangelogCommand)(previousCliVersion, currentVersion);
|
|
1892
1895
|
/* v8 ignore next -- buildChangelogCommand is non-null when previous/current runtime versions differ @preserve */
|
|
@@ -71,29 +71,15 @@ function buildPathExportLine(binDir, shell) {
|
|
|
71
71
|
}
|
|
72
72
|
return `\n# Added by ouro\nexport PATH="${binDir}:$PATH"\n`;
|
|
73
73
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
while (i < lines.length) {
|
|
83
|
-
// Detect "# Added by ouro" followed by a PATH export containing the old binDir
|
|
84
|
-
if (lines[i].trim() === "# Added by ouro" && i + 1 < lines.length && lines[i + 1].includes(oldBinDir)) {
|
|
85
|
-
// Skip both lines (comment + export)
|
|
86
|
-
i += 2;
|
|
87
|
-
// Also skip trailing blank line if present
|
|
88
|
-
/* v8 ignore next -- edge: trailing blank line presence varies @preserve */
|
|
89
|
-
if (i < lines.length && lines[i].trim() === "")
|
|
90
|
-
i++;
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
result.push(lines[i]);
|
|
94
|
-
i++;
|
|
74
|
+
function isWrapperCurrent(scriptPath, existsSync, readFileSync) {
|
|
75
|
+
if (!existsSync(scriptPath))
|
|
76
|
+
return false;
|
|
77
|
+
try {
|
|
78
|
+
return readFileSync(scriptPath, "utf-8") === WRAPPER_SCRIPT;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return false;
|
|
95
82
|
}
|
|
96
|
-
return result.join("\n");
|
|
97
83
|
}
|
|
98
84
|
function installOuroCommand(deps = {}) {
|
|
99
85
|
/* v8 ignore start -- dep defaults: only used in real runtime, tests always inject @preserve */
|
|
@@ -105,9 +91,6 @@ function installOuroCommand(deps = {}) {
|
|
|
105
91
|
const readFileSync = deps.readFileSync ?? ((p, enc) => fs.readFileSync(p, enc));
|
|
106
92
|
const appendFileSync = deps.appendFileSync ?? fs.appendFileSync;
|
|
107
93
|
const chmodSync = deps.chmodSync ?? fs.chmodSync;
|
|
108
|
-
const unlinkSync = deps.unlinkSync ?? fs.unlinkSync;
|
|
109
|
-
const rmdirSync = deps.rmdirSync ?? fs.rmdirSync;
|
|
110
|
-
const readdirSync = deps.readdirSync ?? ((p) => fs.readdirSync(p).map(String));
|
|
111
94
|
const envPath = deps.envPath ?? process.env.PATH ?? "";
|
|
112
95
|
const shell = deps.shell ?? process.env.SHELL;
|
|
113
96
|
/* v8 ignore stop */
|
|
@@ -118,7 +101,7 @@ function installOuroCommand(deps = {}) {
|
|
|
118
101
|
message: "skipped ouro PATH install on Windows",
|
|
119
102
|
meta: { platform },
|
|
120
103
|
});
|
|
121
|
-
return { installed: false, scriptPath: null, pathReady: false, shellProfileUpdated: null, skippedReason: "windows",
|
|
104
|
+
return { installed: false, scriptPath: null, pathReady: false, shellProfileUpdated: null, skippedReason: "windows", repairedOldLauncher: false };
|
|
122
105
|
}
|
|
123
106
|
// Ensure ~/.ouro-cli/ directory layout exists
|
|
124
107
|
if (deps.ensureCliLayout) {
|
|
@@ -126,85 +109,47 @@ function installOuroCommand(deps = {}) {
|
|
|
126
109
|
}
|
|
127
110
|
const binDir = path.join(homeDir, ".ouro-cli", "bin");
|
|
128
111
|
const scriptPath = path.join(binDir, "ouro");
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
112
|
+
const oldScriptPath = path.join(homeDir, ".local", "bin", "ouro");
|
|
113
|
+
const modernCurrent = isWrapperCurrent(scriptPath, existsSync, readFileSync);
|
|
114
|
+
const oldExists = existsSync(oldScriptPath);
|
|
115
|
+
const oldCurrent = oldExists && isWrapperCurrent(oldScriptPath, existsSync, readFileSync);
|
|
116
|
+
// ── Repair old ~/.local/bin/ouro launcher ──
|
|
117
|
+
// If the old launcher exists with stale content it can shadow the modern
|
|
118
|
+
// path and cause the wrong CLI version to run. Overwrite it with the
|
|
119
|
+
// current wrapper so both paths resolve to ~/.ouro-cli/CurrentVersion.
|
|
120
|
+
let repairedOldLauncher = false;
|
|
121
|
+
if (oldExists && !oldCurrent) {
|
|
134
122
|
(0, runtime_1.emitNervesEvent)({
|
|
135
123
|
component: "daemon",
|
|
136
|
-
event: "daemon.
|
|
137
|
-
message: "
|
|
124
|
+
event: "daemon.ouro_path_repair_old",
|
|
125
|
+
message: "repairing stale old launcher at ~/.local/bin/ouro",
|
|
138
126
|
meta: { oldScriptPath },
|
|
139
127
|
});
|
|
140
128
|
try {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if (existsSync(oldBinDir)) {
|
|
145
|
-
try {
|
|
146
|
-
const remaining = readdirSync(oldBinDir);
|
|
147
|
-
if (remaining.length === 0) {
|
|
148
|
-
rmdirSync(oldBinDir);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
catch {
|
|
152
|
-
// Best effort cleanup
|
|
153
|
-
}
|
|
154
|
-
}
|
|
129
|
+
writeFileSync(oldScriptPath, WRAPPER_SCRIPT, { mode: 0o755 });
|
|
130
|
+
chmodSync(oldScriptPath, 0o755);
|
|
131
|
+
repairedOldLauncher = true;
|
|
155
132
|
}
|
|
156
133
|
catch {
|
|
157
|
-
// Best effort
|
|
134
|
+
// Best effort — old launcher repair failure must not block modern install
|
|
158
135
|
}
|
|
159
|
-
// Remove old PATH entry from shell profile
|
|
160
|
-
const profilePath = detectShellProfile(homeDir, shell);
|
|
161
|
-
/* v8 ignore start -- profile cleanup: only fires during migration from old layout @preserve */
|
|
162
|
-
if (profilePath) {
|
|
163
|
-
try {
|
|
164
|
-
const profileContent = readFileSync(profilePath, "utf-8");
|
|
165
|
-
if (profileContent.includes(oldBinDir)) {
|
|
166
|
-
const cleaned = removeOldPathBlock(profileContent, oldBinDir);
|
|
167
|
-
writeFileSync(profilePath, cleaned);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
catch {
|
|
171
|
-
// Best effort profile cleanup
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
/* v8 ignore stop */
|
|
175
136
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
event: "daemon.ouro_path_install_start",
|
|
179
|
-
message: "installing ouro command to PATH",
|
|
180
|
-
meta: { scriptPath, binDir },
|
|
181
|
-
});
|
|
182
|
-
// If ouro already exists, check content and repair if stale
|
|
183
|
-
if (existsSync(scriptPath)) {
|
|
184
|
-
let existingContent = "";
|
|
185
|
-
try {
|
|
186
|
-
existingContent = readFileSync(scriptPath, "utf-8");
|
|
187
|
-
}
|
|
188
|
-
catch {
|
|
189
|
-
// Can't read — treat as stale, will overwrite below
|
|
190
|
-
}
|
|
191
|
-
if (existingContent === WRAPPER_SCRIPT) {
|
|
192
|
-
(0, runtime_1.emitNervesEvent)({
|
|
193
|
-
component: "daemon",
|
|
194
|
-
event: "daemon.ouro_path_install_skip",
|
|
195
|
-
message: "ouro command already installed",
|
|
196
|
-
meta: { scriptPath },
|
|
197
|
-
});
|
|
198
|
-
return { installed: false, scriptPath, pathReady: isBinDirInPath(binDir, envPath), shellProfileUpdated: null, skippedReason: "already-installed", migratedFromOldPath };
|
|
199
|
-
}
|
|
200
|
-
// Content is stale — repair by overwriting
|
|
137
|
+
// ── Fast-path: modern wrapper already current ──
|
|
138
|
+
if (modernCurrent) {
|
|
201
139
|
(0, runtime_1.emitNervesEvent)({
|
|
202
140
|
component: "daemon",
|
|
203
|
-
event: "daemon.
|
|
204
|
-
message: "
|
|
141
|
+
event: "daemon.ouro_path_install_skip",
|
|
142
|
+
message: "ouro command already installed",
|
|
205
143
|
meta: { scriptPath },
|
|
206
144
|
});
|
|
145
|
+
return { installed: false, scriptPath, pathReady: isBinDirInPath(binDir, envPath), shellProfileUpdated: null, skippedReason: "already-installed", repairedOldLauncher };
|
|
207
146
|
}
|
|
147
|
+
(0, runtime_1.emitNervesEvent)({
|
|
148
|
+
component: "daemon",
|
|
149
|
+
event: "daemon.ouro_path_install_start",
|
|
150
|
+
message: existsSync(scriptPath) ? "repairing stale ouro wrapper script" : "installing ouro command to PATH",
|
|
151
|
+
meta: { scriptPath, binDir },
|
|
152
|
+
});
|
|
208
153
|
try {
|
|
209
154
|
mkdirSync(binDir, { recursive: true });
|
|
210
155
|
writeFileSync(scriptPath, WRAPPER_SCRIPT, { mode: 0o755 });
|
|
@@ -218,7 +163,7 @@ function installOuroCommand(deps = {}) {
|
|
|
218
163
|
message: "failed to install ouro command",
|
|
219
164
|
meta: { error: error instanceof Error ? error.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(error) },
|
|
220
165
|
});
|
|
221
|
-
return { installed: false, scriptPath: null, pathReady: false, shellProfileUpdated: null, skippedReason: error instanceof Error ? error.message : /* v8 ignore next -- defensive @preserve */ String(error),
|
|
166
|
+
return { installed: false, scriptPath: null, pathReady: false, shellProfileUpdated: null, skippedReason: error instanceof Error ? error.message : /* v8 ignore next -- defensive @preserve */ String(error), repairedOldLauncher };
|
|
222
167
|
}
|
|
223
168
|
// Check if ~/.ouro-cli/bin is already in PATH
|
|
224
169
|
let shellProfileUpdated = null;
|
|
@@ -256,5 +201,5 @@ function installOuroCommand(deps = {}) {
|
|
|
256
201
|
message: "ouro command installed",
|
|
257
202
|
meta: { scriptPath, pathReady, shellProfileUpdated },
|
|
258
203
|
});
|
|
259
|
-
return { installed: true, scriptPath, pathReady, shellProfileUpdated,
|
|
204
|
+
return { installed: true, scriptPath, pathReady, shellProfileUpdated, repairedOldLauncher };
|
|
260
205
|
}
|