ideawave 0.0.107 → 0.0.109
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 +2 -1
- package/bin/ideawave.mjs +55 -16
- package/bin/launcher-core.mjs +72 -5
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -16,4 +16,5 @@ bunx ideawave@latest
|
|
|
16
16
|
Keep the TUI running, open [ideawave.app](https://ideawave.app), and start
|
|
17
17
|
working with your agent directly on the board.
|
|
18
18
|
|
|
19
|
-
Requires Node.js 22 or newer.
|
|
19
|
+
Requires Node.js 22 or newer, or Bun 1.2.16 or newer (no Node needed).
|
|
20
|
+
Available for macOS, Linux, and Windows.
|
package/bin/ideawave.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { accessSync, constants, readFileSync } from "node:fs";
|
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
|
-
import {
|
|
7
|
+
import { corruptedHostLockEvidence, detectLauncherRuntime, isPathInside } from "./launcher-core.mjs";
|
|
8
8
|
import { detectLinuxLibc, resolveHostTarget } from "./platform.mjs";
|
|
9
9
|
|
|
10
10
|
const require = createRequire(import.meta.url);
|
|
@@ -25,6 +25,40 @@ function readManifest(filename, label) {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
function missingHostError(target, version) {
|
|
29
|
+
const base = `IdeaWave's ${target.key} host package is missing (expected ${target.packageName}@${version}).`;
|
|
30
|
+
const reinstall =
|
|
31
|
+
`Reinstall with optional dependencies enabled, for example \`npm install ideawave@${version} --include=optional\`.`;
|
|
32
|
+
if (path.basename(path.resolve(packageRoot, "..")) !== "node_modules") {
|
|
33
|
+
return `${base} ${reinstall}`;
|
|
34
|
+
}
|
|
35
|
+
const treeRoot = path.resolve(packageRoot, "..", "..");
|
|
36
|
+
let lockRaw;
|
|
37
|
+
try {
|
|
38
|
+
lockRaw = readFileSync(path.join(treeRoot, "package-lock.json"), "utf8");
|
|
39
|
+
} catch {
|
|
40
|
+
return `${base} ${reinstall}`;
|
|
41
|
+
}
|
|
42
|
+
if (!corruptedHostLockEvidence(lockRaw, target.packageName)) {
|
|
43
|
+
return `${base} ${reinstall}`;
|
|
44
|
+
}
|
|
45
|
+
if (treeRoot.split(path.sep).includes("_npx")) {
|
|
46
|
+
const removeExample = process.platform === "win32"
|
|
47
|
+
? `\`rmdir /s /q "${treeRoot}"\``
|
|
48
|
+
: `\`rm -rf "${treeRoot}"\``;
|
|
49
|
+
return (
|
|
50
|
+
`${base} A known npm bug (https://github.com/npm/cli/issues/4828) corrupted this package-runner cache entry ` +
|
|
51
|
+
`while updating IdeaWave: its lockfile resolved IdeaWave's host for a different platform. ` +
|
|
52
|
+
`Delete the cache entry with ${removeExample}, then run \`npx ideawave\` again.`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
return (
|
|
56
|
+
`${base} A known npm bug (https://github.com/npm/cli/issues/4828) left this installation's package-lock.json ` +
|
|
57
|
+
`resolved for a different platform. Delete node_modules and package-lock.json in ${treeRoot}, ` +
|
|
58
|
+
`then reinstall with \`npm install ideawave@${version} --include=optional\`.`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
28
62
|
function resolveDistribution() {
|
|
29
63
|
const manifest = readManifest(path.join(packageRoot, "package.json"), "IdeaWave launcher");
|
|
30
64
|
if (manifest.name !== "ideawave" || typeof manifest.version !== "string" || !manifest.version) {
|
|
@@ -51,10 +85,7 @@ function resolveDistribution() {
|
|
|
51
85
|
try {
|
|
52
86
|
hostManifestPath = require.resolve(`${target.packageName}/package.json`);
|
|
53
87
|
} catch {
|
|
54
|
-
throw new Error(
|
|
55
|
-
`IdeaWave's ${target.key} host package is missing (expected ${target.packageName}@${manifest.version}). ` +
|
|
56
|
-
`Reinstall with optional dependencies enabled, for example \`npm install ideawave@${manifest.version} --include=optional\`.`,
|
|
57
|
-
);
|
|
88
|
+
throw new Error(missingHostError(target, manifest.version));
|
|
58
89
|
}
|
|
59
90
|
const hostManifest = readManifest(hostManifestPath, `IdeaWave ${target.key} host`);
|
|
60
91
|
if (hostManifest.name !== target.packageName) {
|
|
@@ -103,23 +134,31 @@ function resolveDistribution() {
|
|
|
103
134
|
};
|
|
104
135
|
}
|
|
105
136
|
|
|
106
|
-
const
|
|
107
|
-
if (
|
|
108
|
-
fail(
|
|
137
|
+
const runtime = detectLauncherRuntime();
|
|
138
|
+
if (runtime.error) {
|
|
139
|
+
fail(runtime.error);
|
|
109
140
|
} else {
|
|
110
141
|
try {
|
|
111
142
|
const distribution = resolveDistribution();
|
|
143
|
+
// Start from a copy so stale launcher-contract values and a leaked
|
|
144
|
+
// BUN_BE_BUN (which would make the compiled host act as the bun CLI
|
|
145
|
+
// instead of IdeaWave) never reach the host or its children.
|
|
146
|
+
const env = { ...process.env };
|
|
147
|
+
delete env.BUN_BE_BUN;
|
|
148
|
+
delete env.IDEAWAVE_LAUNCHER_NODE_PATH;
|
|
149
|
+
delete env.IDEAWAVE_LAUNCHER_NODE_VERSION;
|
|
150
|
+
env.IDEAWAVE_DISTRIBUTION_MODE = "standalone";
|
|
151
|
+
env.IDEAWAVE_LAUNCHER_RUNTIME = runtime.kind;
|
|
152
|
+
if (runtime.kind === "node") {
|
|
153
|
+
env.IDEAWAVE_LAUNCHER_NODE_PATH = process.execPath;
|
|
154
|
+
env.IDEAWAVE_LAUNCHER_NODE_VERSION = process.version;
|
|
155
|
+
}
|
|
156
|
+
env.IDEAWAVE_PLAYWRIGHT_CORE_PATH = distribution.playwrightRoot;
|
|
157
|
+
env.IDEAWAVE_PRODUCT_VERSION = distribution.manifest.version;
|
|
112
158
|
const child = spawn(distribution.executable, process.argv.slice(2), {
|
|
113
159
|
cwd: process.cwd(),
|
|
114
160
|
stdio: "inherit",
|
|
115
|
-
env
|
|
116
|
-
...process.env,
|
|
117
|
-
IDEAWAVE_DISTRIBUTION_MODE: "standalone",
|
|
118
|
-
IDEAWAVE_LAUNCHER_NODE_PATH: process.execPath,
|
|
119
|
-
IDEAWAVE_LAUNCHER_NODE_VERSION: process.version,
|
|
120
|
-
IDEAWAVE_PLAYWRIGHT_CORE_PATH: distribution.playwrightRoot,
|
|
121
|
-
IDEAWAVE_PRODUCT_VERSION: distribution.manifest.version,
|
|
122
|
-
},
|
|
161
|
+
env,
|
|
123
162
|
});
|
|
124
163
|
|
|
125
164
|
const signalHandlers = new Map();
|
package/bin/launcher-core.mjs
CHANGED
|
@@ -1,32 +1,99 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
|
|
3
3
|
export const MINIMUM_NODE_MAJOR = 22;
|
|
4
|
+
// BUN_BE_BUN self-execution of the compiled host exists since Bun 1.2.16;
|
|
5
|
+
// older Bun launchers predate the runtime contract the host relies on.
|
|
6
|
+
export const MINIMUM_BUN_VERSION = "1.2.16";
|
|
4
7
|
|
|
5
8
|
export function parseNodeMajor(version) {
|
|
6
9
|
const match = /^v?(\d+)(?:\.|$)/.exec(String(version));
|
|
7
10
|
return match ? Number(match[1]) : null;
|
|
8
11
|
}
|
|
9
12
|
|
|
13
|
+
export function parseBunVersion(version) {
|
|
14
|
+
const match = /^(\d+)\.(\d+)\.(\d+)/.exec(String(version));
|
|
15
|
+
return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function bunVersionAtLeast(version, minimum) {
|
|
19
|
+
const actual = parseBunVersion(version);
|
|
20
|
+
const required = parseBunVersion(minimum);
|
|
21
|
+
if (!actual || !required) return false;
|
|
22
|
+
for (let index = 0; index < 3; index += 1) {
|
|
23
|
+
if (actual[index] !== required[index]) return actual[index] > required[index];
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
|
|
10
28
|
/**
|
|
29
|
+
* Identify the JavaScript runtime executing the launcher. Supported launch
|
|
30
|
+
* paths are Node.js 22+ (`npx ideawave`, or `bunx ideawave` with Node
|
|
31
|
+
* installed) and Bun 1.2.16+ (`bunx ideawave` on a Bun-only machine, or
|
|
32
|
+
* `bunx --bun ideawave`). Anything else yields a `kind: null` error result.
|
|
33
|
+
*
|
|
11
34
|
* @param {{ nodeVersion?: string, bunVersion?: string | null, runtimeName?: string } | undefined} options
|
|
35
|
+
* @returns {{ kind: "node" | "bun" | null, version: string, error: string | null }}
|
|
12
36
|
*/
|
|
13
|
-
export function
|
|
37
|
+
export function detectLauncherRuntime(options = {}) {
|
|
14
38
|
const {
|
|
15
39
|
nodeVersion = process.version,
|
|
16
40
|
bunVersion = process.versions?.bun,
|
|
17
41
|
runtimeName = process.release?.name,
|
|
18
42
|
} = options;
|
|
19
43
|
if (bunVersion) {
|
|
20
|
-
|
|
44
|
+
if (!bunVersionAtLeast(bunVersion, MINIMUM_BUN_VERSION)) {
|
|
45
|
+
return {
|
|
46
|
+
kind: null,
|
|
47
|
+
version: String(bunVersion),
|
|
48
|
+
error:
|
|
49
|
+
`IdeaWave requires Bun ${MINIMUM_BUN_VERSION} or newer when launched with Bun; this launcher is using ${bunVersion}. ` +
|
|
50
|
+
"Run `bun upgrade`, or use `npx ideawave` with Node.js 22 or newer.",
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return { kind: "bun", version: String(bunVersion), error: null };
|
|
21
54
|
}
|
|
22
55
|
if (runtimeName !== "node") {
|
|
23
|
-
return
|
|
56
|
+
return {
|
|
57
|
+
kind: null,
|
|
58
|
+
version: "",
|
|
59
|
+
error:
|
|
60
|
+
`IdeaWave's launcher requires Node.js ${MINIMUM_NODE_MAJOR} or newer or Bun ${MINIMUM_BUN_VERSION} or newer; ` +
|
|
61
|
+
`detected ${runtimeName || "an unknown runtime"}.`,
|
|
62
|
+
};
|
|
24
63
|
}
|
|
25
64
|
const major = parseNodeMajor(nodeVersion);
|
|
26
65
|
if (major === null || major < MINIMUM_NODE_MAJOR) {
|
|
27
|
-
return
|
|
66
|
+
return {
|
|
67
|
+
kind: null,
|
|
68
|
+
version: String(nodeVersion ?? ""),
|
|
69
|
+
error:
|
|
70
|
+
`IdeaWave requires Node.js ${MINIMUM_NODE_MAJOR} or newer; this launcher is using ${nodeVersion || "an unknown version"}. ` +
|
|
71
|
+
"Upgrade Node.js, or launch with Bun 1.2.16 or newer via `bunx ideawave`.",
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return { kind: "node", version: String(nodeVersion), error: null };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* npm's arborist can update an existing install (notably an `_npx` cache
|
|
79
|
+
* entry) while keeping a package-lock that resolved IdeaWave's platform host
|
|
80
|
+
* for a different machine, so the matching host is silently never installed
|
|
81
|
+
* (https://github.com/npm/cli/issues/4828). A lockfile that lists host
|
|
82
|
+
* packages but not the required one is direct evidence of that corruption.
|
|
83
|
+
*
|
|
84
|
+
* @param {string} lockRaw
|
|
85
|
+
* @param {string} packageName
|
|
86
|
+
*/
|
|
87
|
+
export function corruptedHostLockEvidence(lockRaw, packageName) {
|
|
88
|
+
try {
|
|
89
|
+
const lock = JSON.parse(lockRaw);
|
|
90
|
+
const packages = lock && typeof lock === "object" ? lock.packages : null;
|
|
91
|
+
if (!packages || typeof packages !== "object") return false;
|
|
92
|
+
const hosts = Object.keys(packages).filter((key) => key.startsWith("node_modules/ideawave-host-"));
|
|
93
|
+
return hosts.length > 0 && !hosts.includes(`node_modules/${packageName}`);
|
|
94
|
+
} catch {
|
|
95
|
+
return false;
|
|
28
96
|
}
|
|
29
|
-
return null;
|
|
30
97
|
}
|
|
31
98
|
|
|
32
99
|
export function isPathInside(root, candidate) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ideawave",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.109",
|
|
4
4
|
"description": "IdeaWave local agent host and terminal UI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -38,12 +38,12 @@
|
|
|
38
38
|
"playwright-core": "1.62.1"
|
|
39
39
|
},
|
|
40
40
|
"optionalDependencies": {
|
|
41
|
-
"ideawave-host-darwin-arm64": "0.0.
|
|
42
|
-
"ideawave-host-darwin-x64": "0.0.
|
|
43
|
-
"ideawave-host-linux-arm64": "0.0.
|
|
44
|
-
"ideawave-host-linux-arm64-musl": "0.0.
|
|
45
|
-
"ideawave-host-linux-x64": "0.0.
|
|
46
|
-
"ideawave-host-linux-x64-musl": "0.0.
|
|
47
|
-
"ideawave-host-windows": "0.0.
|
|
41
|
+
"ideawave-host-darwin-arm64": "0.0.109",
|
|
42
|
+
"ideawave-host-darwin-x64": "0.0.109",
|
|
43
|
+
"ideawave-host-linux-arm64": "0.0.109",
|
|
44
|
+
"ideawave-host-linux-arm64-musl": "0.0.109",
|
|
45
|
+
"ideawave-host-linux-x64": "0.0.109",
|
|
46
|
+
"ideawave-host-linux-x64-musl": "0.0.109",
|
|
47
|
+
"ideawave-host-windows": "0.0.109"
|
|
48
48
|
}
|
|
49
49
|
}
|