@cmetech/otto 1.1.0 → 1.1.1
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/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/otto/commands/release-notes/_data.js +11 -0
- package/dist/update-cmd.d.ts +19 -0
- package/dist/update-cmd.js +177 -6
- package/package.json +6 -6
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +3 -3
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/package.json +2 -2
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/otto/commands/release-notes/_data.ts +11 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
48d229fb6702d2a2
|
|
@@ -4,6 +4,17 @@
|
|
|
4
4
|
// To add or correct release notes, edit CHANGELOG.md and rebuild. Editing this
|
|
5
5
|
// file directly will be clobbered on the next build.
|
|
6
6
|
export const RELEASE_NOTES = [
|
|
7
|
+
{
|
|
8
|
+
version: '1.1.1',
|
|
9
|
+
date: '2026-05-29',
|
|
10
|
+
headline: 'Windows `otto update` no longer emits EPERM cleanup warnings or leaves orphan `.otto-*` staging dirs.',
|
|
11
|
+
added: [
|
|
12
|
+
'`update-status.json` written to `~/.otto/agent/` on every `otto update` — tracks `startedAt`, `completedAt`, `fromVersion`, `toVersion`, and `exitCode`. The next `otto update` prints "Last update: vX.Y.Z → vA.B.C at … (✓ success / ✗ exit N)" before checking the registry, so you can see whether a previous background update finished.',
|
|
13
|
+
],
|
|
14
|
+
fixed: [
|
|
15
|
+
'`otto update` on Windows would log `EPERM: operation not permitted, unlink` warnings against `duckdb.dll`, `sharp.dll`, and `otto_engine.win32-x64.node` because the running otto.exe still held DLL handles. The install still succeeded but left orphan `.otto-RouGtD54`-style staging directories under `%APPDATA%\\npm\\node_modules\\@cmetech\\`. `otto update` now spawns a detached PowerShell bootstrap in a visible "OTTO Updater" console window that waits for the parent otto.exe to exit (max 30s), runs the install with locks released, sweeps the orphan staging dirs, and writes a completion status to `~/.otto/agent/update-status.json` that the next `otto update` surfaces. macOS / Linux behavior unchanged — POSIX inode semantics handle live-process replacement without the lock issue.',
|
|
16
|
+
],
|
|
17
|
+
},
|
|
7
18
|
{
|
|
8
19
|
version: '1.1.0',
|
|
9
20
|
date: '2026-05-29',
|
package/dist/update-cmd.d.ts
CHANGED
|
@@ -2,5 +2,24 @@ interface RunUpdateOptions {
|
|
|
2
2
|
agentDir?: string;
|
|
3
3
|
skillsDir?: string;
|
|
4
4
|
}
|
|
5
|
+
/**
|
|
6
|
+
* Build the PowerShell bootstrap that runs the install in a detached, visible
|
|
7
|
+
* console window. Exported for tests. The script:
|
|
8
|
+
* 1. Writes an initial status file at `statusPath`.
|
|
9
|
+
* 2. Waits up to 30s for the parent otto.exe (parentPid) to exit so its
|
|
10
|
+
* DLL handles release.
|
|
11
|
+
* 3. Runs the install command (`npm install -g …` or `bun add -g …`).
|
|
12
|
+
* 4. Sweeps any orphan `.otto-*` staging dirs npm left behind.
|
|
13
|
+
* 5. Updates the status file with completion details.
|
|
14
|
+
* 6. Prints a clear "Done" message and waits for a keypress.
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildWindowsBootstrapScript(args: {
|
|
17
|
+
parentPid: number;
|
|
18
|
+
installCmd: string;
|
|
19
|
+
statusPath: string;
|
|
20
|
+
current: string;
|
|
21
|
+
latest: string;
|
|
22
|
+
startedAt: string;
|
|
23
|
+
}): string;
|
|
5
24
|
export declare function runUpdate(options?: RunUpdateOptions): Promise<void>;
|
|
6
25
|
export {};
|
package/dist/update-cmd.js
CHANGED
|
@@ -1,15 +1,177 @@
|
|
|
1
|
-
import { execSync } from 'node:child_process';
|
|
1
|
+
import { execSync, spawn } from 'node:child_process';
|
|
2
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
2
5
|
import { agentDir as defaultAgentDir } from './app-paths.js';
|
|
3
6
|
import { initResources } from './resource-loader.js';
|
|
4
7
|
import { compareSemver, fetchLatestVersionFromRegistry, resolveInstallCommand } from './update-check.js';
|
|
5
8
|
const NPM_PACKAGE = '@cmetech/otto';
|
|
9
|
+
function getStatusPath(agentDir) {
|
|
10
|
+
return join(agentDir, 'update-status.json');
|
|
11
|
+
}
|
|
12
|
+
function maybeShowPriorStatus(agentDir) {
|
|
13
|
+
const statusPath = getStatusPath(agentDir);
|
|
14
|
+
if (!existsSync(statusPath))
|
|
15
|
+
return;
|
|
16
|
+
try {
|
|
17
|
+
const status = JSON.parse(readFileSync(statusPath, 'utf-8'));
|
|
18
|
+
if (status.completedAt) {
|
|
19
|
+
const dim = '\x1b[2m';
|
|
20
|
+
const reset = '\x1b[0m';
|
|
21
|
+
const outcome = status.exitCode === 0 ? '✓ success' : `✗ exit ${status.exitCode}`;
|
|
22
|
+
process.stdout.write(`${dim}Last update: v${status.fromVersion} → v${status.toVersion} at ${status.completedAt} (${outcome})${reset}\n`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// Ignore parse errors — file may be partial or corrupt.
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build the PowerShell bootstrap that runs the install in a detached, visible
|
|
31
|
+
* console window. Exported for tests. The script:
|
|
32
|
+
* 1. Writes an initial status file at `statusPath`.
|
|
33
|
+
* 2. Waits up to 30s for the parent otto.exe (parentPid) to exit so its
|
|
34
|
+
* DLL handles release.
|
|
35
|
+
* 3. Runs the install command (`npm install -g …` or `bun add -g …`).
|
|
36
|
+
* 4. Sweeps any orphan `.otto-*` staging dirs npm left behind.
|
|
37
|
+
* 5. Updates the status file with completion details.
|
|
38
|
+
* 6. Prints a clear "Done" message and waits for a keypress.
|
|
39
|
+
*/
|
|
40
|
+
export function buildWindowsBootstrapScript(args) {
|
|
41
|
+
// PowerShell single-quoted strings are literal — backslashes and $ are not
|
|
42
|
+
// interpreted. Path values flow straight through.
|
|
43
|
+
const psQuote = (value) => `'${value.replace(/'/g, "''")}'`;
|
|
44
|
+
const status = psQuote(args.statusPath);
|
|
45
|
+
const current = psQuote(args.current);
|
|
46
|
+
const latest = psQuote(args.latest);
|
|
47
|
+
const startedAt = psQuote(args.startedAt);
|
|
48
|
+
const installCmd = args.installCmd; // run as-is — must be a valid PowerShell command line
|
|
49
|
+
return `# OTTO update bootstrap — auto-generated by otto update on Windows
|
|
50
|
+
$ErrorActionPreference = 'Continue'
|
|
51
|
+
$Host.UI.RawUI.WindowTitle = 'OTTO Updater'
|
|
52
|
+
|
|
53
|
+
Write-Host 'OTTO Updater — please do not close this window' -ForegroundColor Cyan
|
|
54
|
+
Write-Host '─────────────────────────────────────────────────'
|
|
55
|
+
Write-Host ''
|
|
56
|
+
|
|
57
|
+
# Write initial status
|
|
58
|
+
$statusPath = ${status}
|
|
59
|
+
$statusDir = Split-Path -Parent $statusPath
|
|
60
|
+
if ($statusDir -and -not (Test-Path $statusDir)) {
|
|
61
|
+
New-Item -ItemType Directory -Path $statusDir -Force | Out-Null
|
|
62
|
+
}
|
|
63
|
+
@{
|
|
64
|
+
startedAt = ${startedAt}
|
|
65
|
+
fromVersion = ${current}
|
|
66
|
+
toVersion = ${latest}
|
|
67
|
+
} | ConvertTo-Json | Set-Content -Path $statusPath -Encoding UTF8
|
|
68
|
+
|
|
69
|
+
# Wait for parent otto.exe (pid ${args.parentPid}) to exit, max 30s
|
|
70
|
+
Write-Host -NoNewline 'Waiting for OTTO to exit...'
|
|
71
|
+
$deadline = (Get-Date).AddSeconds(30)
|
|
72
|
+
while ((Get-Process -Id ${args.parentPid} -ErrorAction SilentlyContinue) -and ((Get-Date) -lt $deadline)) {
|
|
73
|
+
Start-Sleep -Milliseconds 300
|
|
74
|
+
}
|
|
75
|
+
if (Get-Process -Id ${args.parentPid} -ErrorAction SilentlyContinue) {
|
|
76
|
+
Write-Host ' timeout!' -ForegroundColor Yellow
|
|
77
|
+
Write-Host 'OTTO did not exit in 30s. To finish manually, run:' -ForegroundColor Yellow
|
|
78
|
+
Write-Host (' ' + ${psQuote(installCmd)})
|
|
79
|
+
Write-Host ''
|
|
80
|
+
Write-Host 'Press any key to close this window.'
|
|
81
|
+
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
|
|
82
|
+
exit 1
|
|
83
|
+
}
|
|
84
|
+
Write-Host ' done.'
|
|
85
|
+
Write-Host ''
|
|
86
|
+
|
|
87
|
+
# Run the install
|
|
88
|
+
Write-Host ('Running: ' + ${psQuote(installCmd)}) -ForegroundColor Cyan
|
|
89
|
+
Write-Host ''
|
|
90
|
+
${installCmd}
|
|
91
|
+
$exitCode = $LASTEXITCODE
|
|
92
|
+
|
|
93
|
+
# Sweep orphan .otto-* staging dirs npm couldn't clean up
|
|
94
|
+
$stagingRoot = Join-Path $env:APPDATA 'npm\\node_modules\\@cmetech'
|
|
95
|
+
if (Test-Path $stagingRoot) {
|
|
96
|
+
Get-ChildItem -Path $stagingRoot -Directory -Filter '.otto-*' -ErrorAction SilentlyContinue |
|
|
97
|
+
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# Write final status
|
|
101
|
+
@{
|
|
102
|
+
startedAt = ${startedAt}
|
|
103
|
+
completedAt = (Get-Date -Format 'o')
|
|
104
|
+
fromVersion = ${current}
|
|
105
|
+
toVersion = ${latest}
|
|
106
|
+
exitCode = $exitCode
|
|
107
|
+
} | ConvertTo-Json | Set-Content -Path $statusPath -Encoding UTF8
|
|
108
|
+
|
|
109
|
+
Write-Host ''
|
|
110
|
+
if ($exitCode -eq 0) {
|
|
111
|
+
Write-Host ('Done. OTTO v' + ${latest} + ' installed.') -ForegroundColor Green
|
|
112
|
+
Write-Host 'Open any terminal and run otto to use the new version.'
|
|
113
|
+
} else {
|
|
114
|
+
Write-Host ('Install failed with exit code ' + $exitCode) -ForegroundColor Red
|
|
115
|
+
Write-Host ('Try manually: ' + ${psQuote(installCmd)})
|
|
116
|
+
}
|
|
117
|
+
Write-Host ''
|
|
118
|
+
Write-Host 'Press any key to close this window.'
|
|
119
|
+
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
|
|
120
|
+
exit $exitCode
|
|
121
|
+
`;
|
|
122
|
+
}
|
|
123
|
+
function runWindowsDetachedUpdate(current, latest, installCmd, agentDir) {
|
|
124
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'otto-update-'));
|
|
125
|
+
const scriptPath = join(tempDir, 'update.ps1');
|
|
126
|
+
const statusPath = getStatusPath(agentDir);
|
|
127
|
+
const startedAt = new Date().toISOString();
|
|
128
|
+
if (!existsSync(agentDir)) {
|
|
129
|
+
mkdirSync(agentDir, { recursive: true });
|
|
130
|
+
}
|
|
131
|
+
const script = buildWindowsBootstrapScript({
|
|
132
|
+
parentPid: process.pid,
|
|
133
|
+
installCmd,
|
|
134
|
+
statusPath,
|
|
135
|
+
current,
|
|
136
|
+
latest,
|
|
137
|
+
startedAt,
|
|
138
|
+
});
|
|
139
|
+
writeFileSync(scriptPath, script, 'utf-8');
|
|
140
|
+
const bold = '\x1b[1m';
|
|
141
|
+
const dim = '\x1b[2m';
|
|
142
|
+
const reset = '\x1b[0m';
|
|
143
|
+
process.stdout.write(`${dim}Updating:${reset} v${current} → ${bold}v${latest}${reset}\n\n`);
|
|
144
|
+
process.stdout.write('Update is running in a new window — Windows cannot replace files while OTTO is open.\n');
|
|
145
|
+
process.stdout.write(`When the update window shows ${bold}"Done."${reset} run \`otto\` in any terminal to use v${latest}.\n\n`);
|
|
146
|
+
// `cmd.exe /c start "Title" powershell.exe -File <script>`
|
|
147
|
+
// Node quotes args that contain spaces, so `start OTTO Updater` becomes
|
|
148
|
+
// `start "OTTO Updater"`, which CMD's start builtin treats as the window
|
|
149
|
+
// title (longstanding CMD quirk).
|
|
150
|
+
const child = spawn('cmd.exe', [
|
|
151
|
+
'/c',
|
|
152
|
+
'start',
|
|
153
|
+
'OTTO Updater',
|
|
154
|
+
'powershell.exe',
|
|
155
|
+
'-NoProfile',
|
|
156
|
+
'-ExecutionPolicy',
|
|
157
|
+
'Bypass',
|
|
158
|
+
'-File',
|
|
159
|
+
scriptPath,
|
|
160
|
+
], { detached: true, stdio: 'ignore', windowsHide: false });
|
|
161
|
+
child.unref();
|
|
162
|
+
// We MUST exit so the bootstrap's pid-wait loop unblocks and DLL handles
|
|
163
|
+
// release. Anything after this point is unreachable.
|
|
164
|
+
process.exit(0);
|
|
165
|
+
}
|
|
6
166
|
export async function runUpdate(options = {}) {
|
|
7
167
|
const current = process.env.OTTO_VERSION || '0.0.0';
|
|
168
|
+
const agentDir = options.agentDir ?? defaultAgentDir;
|
|
8
169
|
const bold = '\x1b[1m';
|
|
9
170
|
const dim = '\x1b[2m';
|
|
10
171
|
const green = '\x1b[32m';
|
|
11
172
|
const yellow = '\x1b[33m';
|
|
12
173
|
const reset = '\x1b[0m';
|
|
174
|
+
maybeShowPriorStatus(agentDir);
|
|
13
175
|
process.stdout.write(`${dim}Current version:${reset} v${current}\n`);
|
|
14
176
|
process.stdout.write(`${dim}Checking npm registry...${reset}\n`);
|
|
15
177
|
const latest = await fetchLatestVersionFromRegistry();
|
|
@@ -20,15 +182,24 @@ export async function runUpdate(options = {}) {
|
|
|
20
182
|
process.stdout.write(`${dim}Latest version:${reset} v${latest}\n`);
|
|
21
183
|
if (compareSemver(latest, current) <= 0) {
|
|
22
184
|
process.stdout.write(`${green}Already up to date.${reset}\n`);
|
|
23
|
-
initResources(
|
|
185
|
+
initResources(agentDir, options.skillsDir);
|
|
24
186
|
return;
|
|
25
187
|
}
|
|
26
|
-
process.stdout.write(`${dim}Updating:${reset} v${current} → ${bold}v${latest}${reset}\n`);
|
|
27
188
|
const installCmd = resolveInstallCommand(`${NPM_PACKAGE}@latest`);
|
|
189
|
+
// On Windows, run install in a detached, visible window. The current
|
|
190
|
+
// process holds locks on duckdb.dll, sharp.dll, otto_engine.win32-x64.node,
|
|
191
|
+
// and others — npm install would log EPERM warnings and leave orphan
|
|
192
|
+
// .otto-* staging dirs (issue surfaced by a v1.0.7 → v1.1.0 update on
|
|
193
|
+
// Windows). The bootstrap waits for this process to exit, runs npm install
|
|
194
|
+
// cleanly, sweeps the orphans, and reports completion via a status file
|
|
195
|
+
// that the next `otto update` invocation surfaces.
|
|
196
|
+
if (process.platform === 'win32') {
|
|
197
|
+
runWindowsDetachedUpdate(current, latest, installCmd, agentDir);
|
|
198
|
+
// unreachable
|
|
199
|
+
}
|
|
200
|
+
process.stdout.write(`${dim}Updating:${reset} v${current} → ${bold}v${latest}${reset}\n`);
|
|
28
201
|
try {
|
|
29
|
-
execSync(installCmd, {
|
|
30
|
-
stdio: 'inherit',
|
|
31
|
-
});
|
|
202
|
+
execSync(installCmd, { stdio: 'inherit' });
|
|
32
203
|
process.stdout.write(`\n${green}${bold}Updated to v${latest}${reset}\n`);
|
|
33
204
|
}
|
|
34
205
|
catch {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmetech/otto",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Terminal-based developer chat assistant. Permanent hard fork of gsd-pi with LangFlow flow triggers, a flow builder, and optional gateway routing for compliance environments.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -183,11 +183,11 @@
|
|
|
183
183
|
"@anthropic-ai/claude-agent-sdk": "0.2.83",
|
|
184
184
|
"fsevents": "~2.3.3",
|
|
185
185
|
"koffi": "^2.9.0",
|
|
186
|
-
"@cmetech/otto-engine-darwin-arm64": "1.1.
|
|
187
|
-
"@cmetech/otto-engine-darwin-x64": "1.1.
|
|
188
|
-
"@cmetech/otto-engine-linux-arm64-gnu": "1.1.
|
|
189
|
-
"@cmetech/otto-engine-linux-x64-gnu": "1.1.
|
|
190
|
-
"@cmetech/otto-engine-win32-x64-msvc": "1.1.
|
|
186
|
+
"@cmetech/otto-engine-darwin-arm64": "1.1.1",
|
|
187
|
+
"@cmetech/otto-engine-darwin-x64": "1.1.1",
|
|
188
|
+
"@cmetech/otto-engine-linux-arm64-gnu": "1.1.1",
|
|
189
|
+
"@cmetech/otto-engine-linux-x64-gnu": "1.1.1",
|
|
190
|
+
"@cmetech/otto-engine-win32-x64-msvc": "1.1.1"
|
|
191
191
|
},
|
|
192
192
|
"overrides": {
|
|
193
193
|
"gaxios": "7.1.4",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@otto-build/daemon",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "OTTO daemon — background process for project monitoring and Discord integration",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@anthropic-ai/sdk": "^0.52.0",
|
|
32
|
-
"@otto-build/contracts": "^1.1.
|
|
33
|
-
"@otto-build/rpc-client": "^1.1.
|
|
32
|
+
"@otto-build/contracts": "^1.1.1",
|
|
33
|
+
"@otto-build/rpc-client": "^1.1.1",
|
|
34
34
|
"discord.js": "^14.25.1",
|
|
35
35
|
"yaml": "^2.8.0",
|
|
36
36
|
"zod": "^3.24.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@otto-build/mcp-server",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "MCP server exposing OTTO orchestration tools for compatible clients",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"otto": {
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"test": "npm run build:test && node --test dist/mcp-server.test.js dist/remote-questions.test.js"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@otto-build/contracts": "^1.1.
|
|
38
|
-
"@otto-build/rpc-client": "^1.1.
|
|
37
|
+
"@otto-build/contracts": "^1.1.1",
|
|
38
|
+
"@otto-build/rpc-client": "^1.1.1",
|
|
39
39
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
40
40
|
"zod": "^4.0.0"
|
|
41
41
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@otto/pi-coding-agent",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Coding agent CLI (vendored from pi-mono)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"otto": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"copy-assets": "node scripts/copy-assets.cjs"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@otto-build/contracts": "^1.1.
|
|
31
|
+
"@otto-build/contracts": "^1.1.1",
|
|
32
32
|
"@mariozechner/jiti": "^2.6.2",
|
|
33
33
|
"@silvia-odwyer/photon-node": "^0.3.4",
|
|
34
34
|
"chalk": "^5.5.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@otto-build/rpc-client",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Standalone RPC client SDK for OTTO — zero internal dependencies",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"otto": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"test": "node --test dist/rpc-client.test.js"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@otto-build/contracts": "^1.1.
|
|
37
|
+
"@otto-build/contracts": "^1.1.1"
|
|
38
38
|
},
|
|
39
39
|
"engines": {
|
|
40
40
|
"node": ">=22.0.0"
|
package/pkg/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loop24/client",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"piConfig": {
|
|
5
5
|
"_comment": "AUTO-SYNCED from root package.json by scripts/sync-piconfig.mjs (runs on prebuild). Do not edit this block directly — edit root package.json and re-run `npm run build` or `npm run sync-piconfig`.",
|
|
6
6
|
"name": "otto",
|
|
@@ -15,6 +15,17 @@ export interface ReleaseNote {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export const RELEASE_NOTES: ReleaseNote[] = [
|
|
18
|
+
{
|
|
19
|
+
version: '1.1.1',
|
|
20
|
+
date: '2026-05-29',
|
|
21
|
+
headline: 'Windows `otto update` no longer emits EPERM cleanup warnings or leaves orphan `.otto-*` staging dirs.',
|
|
22
|
+
added: [
|
|
23
|
+
'`update-status.json` written to `~/.otto/agent/` on every `otto update` — tracks `startedAt`, `completedAt`, `fromVersion`, `toVersion`, and `exitCode`. The next `otto update` prints "Last update: vX.Y.Z → vA.B.C at … (✓ success / ✗ exit N)" before checking the registry, so you can see whether a previous background update finished.',
|
|
24
|
+
],
|
|
25
|
+
fixed: [
|
|
26
|
+
'`otto update` on Windows would log `EPERM: operation not permitted, unlink` warnings against `duckdb.dll`, `sharp.dll`, and `otto_engine.win32-x64.node` because the running otto.exe still held DLL handles. The install still succeeded but left orphan `.otto-RouGtD54`-style staging directories under `%APPDATA%\\npm\\node_modules\\@cmetech\\`. `otto update` now spawns a detached PowerShell bootstrap in a visible "OTTO Updater" console window that waits for the parent otto.exe to exit (max 30s), runs the install with locks released, sweeps the orphan staging dirs, and writes a completion status to `~/.otto/agent/update-status.json` that the next `otto update` surfaces. macOS / Linux behavior unchanged — POSIX inode semantics handle live-process replacement without the lock issue.',
|
|
27
|
+
],
|
|
28
|
+
},
|
|
18
29
|
{
|
|
19
30
|
version: '1.1.0',
|
|
20
31
|
date: '2026-05-29',
|