@ibm/ixora 0.1.3 → 0.1.5
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/{chunk-4XGJZZ73.js → chunk-K2GF2QLM.js} +8 -2
- package/dist/{chunk-VCQRSQ4F.js → chunk-KFC4SP2O.js} +47 -18
- package/dist/index.js +36 -11
- package/dist/{restart-7ECL2NPC.js → restart-VIVFUUQG.js} +2 -2
- package/dist/{systems-KIQ3KFX3.js → systems-JHJ3CQRN.js} +1 -1
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
IXORA_DIR,
|
|
7
7
|
SYSTEMS_CONFIG,
|
|
8
8
|
readSystems
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-KFC4SP2O.js";
|
|
10
10
|
|
|
11
11
|
// src/lib/compose.ts
|
|
12
12
|
import { execa as execa2 } from "execa";
|
|
@@ -250,6 +250,7 @@ function section(title) {
|
|
|
250
250
|
|
|
251
251
|
// src/lib/compose.ts
|
|
252
252
|
async function runCompose(composeCmd, args, options = {}) {
|
|
253
|
+
const { throwOnError, ...execaOpts } = options;
|
|
253
254
|
const [bin, subArgs] = getComposeParts(composeCmd);
|
|
254
255
|
const fullArgs = [
|
|
255
256
|
...subArgs,
|
|
@@ -264,7 +265,7 @@ async function runCompose(composeCmd, args, options = {}) {
|
|
|
264
265
|
try {
|
|
265
266
|
const result = await execa2(bin, fullArgs, {
|
|
266
267
|
stdio: "inherit",
|
|
267
|
-
...
|
|
268
|
+
...execaOpts
|
|
268
269
|
});
|
|
269
270
|
return {
|
|
270
271
|
stdout: String(result.stdout ?? ""),
|
|
@@ -273,6 +274,11 @@ async function runCompose(composeCmd, args, options = {}) {
|
|
|
273
274
|
};
|
|
274
275
|
} catch (err) {
|
|
275
276
|
const exitCode = err && typeof err === "object" && "exitCode" in err ? err.exitCode : 1;
|
|
277
|
+
if (throwOnError) {
|
|
278
|
+
throw new Error(
|
|
279
|
+
`Compose command failed (exit ${exitCode}): ${args.join(" ")}`
|
|
280
|
+
);
|
|
281
|
+
}
|
|
276
282
|
error(`Command failed: ${composeCmd} ${args.join(" ")}`);
|
|
277
283
|
console.log(` Check ${bold("ixora logs")} for details.`);
|
|
278
284
|
process.exit(exitCode);
|
|
@@ -2,18 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
// src/lib/systems.ts
|
|
4
4
|
import {
|
|
5
|
-
readFileSync as
|
|
5
|
+
readFileSync as readFileSync3,
|
|
6
6
|
writeFileSync as writeFileSync2,
|
|
7
7
|
existsSync as existsSync2,
|
|
8
8
|
mkdirSync as mkdirSync2,
|
|
9
9
|
chmodSync as chmodSync2
|
|
10
10
|
} from "fs";
|
|
11
|
-
import { dirname as
|
|
11
|
+
import { dirname as dirname3 } from "path";
|
|
12
12
|
|
|
13
13
|
// src/lib/constants.ts
|
|
14
|
+
import { readFileSync } from "fs";
|
|
14
15
|
import { homedir } from "os";
|
|
15
|
-
import { join } from "path";
|
|
16
|
-
|
|
16
|
+
import { dirname, join } from "path";
|
|
17
|
+
import { fileURLToPath } from "url";
|
|
18
|
+
function readCliVersion() {
|
|
19
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
for (let i = 0; i < 5; i++) {
|
|
21
|
+
try {
|
|
22
|
+
const pkg = JSON.parse(
|
|
23
|
+
readFileSync(join(dir, "package.json"), "utf8")
|
|
24
|
+
);
|
|
25
|
+
if (pkg.name === "@ibm/ixora" && pkg.version) return pkg.version;
|
|
26
|
+
} catch {
|
|
27
|
+
}
|
|
28
|
+
const parent = dirname(dir);
|
|
29
|
+
if (parent === dir) break;
|
|
30
|
+
dir = parent;
|
|
31
|
+
}
|
|
32
|
+
return "unknown";
|
|
33
|
+
}
|
|
34
|
+
var SCRIPT_VERSION = readCliVersion();
|
|
17
35
|
var HEALTH_TIMEOUT = 30;
|
|
18
36
|
var IXORA_DIR = join(homedir(), ".ixora");
|
|
19
37
|
var COMPOSE_FILE = join(IXORA_DIR, "docker-compose.yml");
|
|
@@ -112,19 +130,19 @@ var AGENT_PRESETS = {
|
|
|
112
130
|
|
|
113
131
|
// src/lib/env.ts
|
|
114
132
|
import {
|
|
115
|
-
readFileSync,
|
|
133
|
+
readFileSync as readFileSync2,
|
|
116
134
|
writeFileSync,
|
|
117
135
|
existsSync,
|
|
118
136
|
mkdirSync,
|
|
119
137
|
chmodSync
|
|
120
138
|
} from "fs";
|
|
121
|
-
import { dirname } from "path";
|
|
139
|
+
import { dirname as dirname2 } from "path";
|
|
122
140
|
function sqEscape(value) {
|
|
123
141
|
return value.replace(/'/g, "'\\''");
|
|
124
142
|
}
|
|
125
143
|
function envGet(key, envFile = ENV_FILE) {
|
|
126
144
|
if (!existsSync(envFile)) return "";
|
|
127
|
-
const content =
|
|
145
|
+
const content = readFileSync2(envFile, "utf-8");
|
|
128
146
|
for (const line of content.split("\n")) {
|
|
129
147
|
if (line.startsWith(`${key}=`)) {
|
|
130
148
|
let val = line.slice(key.length + 1);
|
|
@@ -147,21 +165,28 @@ var KNOWN_KEYS = [
|
|
|
147
165
|
"DB2_PORT",
|
|
148
166
|
"IXORA_PROFILE",
|
|
149
167
|
"IXORA_VERSION",
|
|
168
|
+
"IXORA_PREVIOUS_VERSION",
|
|
150
169
|
"IXORA_AGENT_MODEL",
|
|
151
170
|
"IXORA_TEAM_MODEL"
|
|
152
171
|
];
|
|
153
172
|
function writeEnvFile(config, envFile = ENV_FILE) {
|
|
154
|
-
mkdirSync(
|
|
173
|
+
mkdirSync(dirname2(envFile), { recursive: true });
|
|
155
174
|
let extra = "";
|
|
175
|
+
let prevVersionLine = "";
|
|
156
176
|
if (existsSync(envFile)) {
|
|
157
|
-
const existing =
|
|
158
|
-
const
|
|
177
|
+
const existing = readFileSync2(envFile, "utf-8");
|
|
178
|
+
const lines = existing.split("\n");
|
|
179
|
+
const extraLines = lines.filter((line) => {
|
|
159
180
|
const trimmed = line.trim();
|
|
160
181
|
if (!trimmed || trimmed.startsWith("#")) return false;
|
|
161
182
|
const lineKey = trimmed.split("=")[0];
|
|
162
183
|
return !KNOWN_KEYS.includes(lineKey);
|
|
163
184
|
});
|
|
164
185
|
extra = extraLines.join("\n");
|
|
186
|
+
const pvLine = lines.find(
|
|
187
|
+
(l) => l.startsWith("IXORA_PREVIOUS_VERSION=")
|
|
188
|
+
);
|
|
189
|
+
if (pvLine) prevVersionLine = pvLine;
|
|
165
190
|
}
|
|
166
191
|
let content = `# Model provider
|
|
167
192
|
IXORA_AGENT_MODEL='${sqEscape(config.agentModel)}'
|
|
@@ -186,6 +211,10 @@ DB2_PORT='${sqEscape(config.db2Port)}'
|
|
|
186
211
|
IXORA_PROFILE='${sqEscape(config.profile)}'
|
|
187
212
|
IXORA_VERSION='${sqEscape(config.version)}'
|
|
188
213
|
`;
|
|
214
|
+
if (prevVersionLine) {
|
|
215
|
+
content += `${prevVersionLine}
|
|
216
|
+
`;
|
|
217
|
+
}
|
|
189
218
|
if (extra) {
|
|
190
219
|
content += `
|
|
191
220
|
# Preserved user settings
|
|
@@ -198,7 +227,7 @@ ${extra}
|
|
|
198
227
|
function updateEnvKey(key, value, envFile = ENV_FILE) {
|
|
199
228
|
const escaped = sqEscape(value);
|
|
200
229
|
if (existsSync(envFile)) {
|
|
201
|
-
const content =
|
|
230
|
+
const content = readFileSync2(envFile, "utf-8");
|
|
202
231
|
const lines = content.split("\n");
|
|
203
232
|
let found = false;
|
|
204
233
|
const updated = lines.map((line) => {
|
|
@@ -211,7 +240,7 @@ function updateEnvKey(key, value, envFile = ENV_FILE) {
|
|
|
211
240
|
if (found) {
|
|
212
241
|
writeFileSync(envFile, updated.join("\n"), "utf-8");
|
|
213
242
|
} else {
|
|
214
|
-
const existing =
|
|
243
|
+
const existing = readFileSync2(envFile, "utf-8");
|
|
215
244
|
const suffix = existing.endsWith("\n") ? "" : "\n";
|
|
216
245
|
writeFileSync(
|
|
217
246
|
envFile,
|
|
@@ -221,7 +250,7 @@ function updateEnvKey(key, value, envFile = ENV_FILE) {
|
|
|
221
250
|
);
|
|
222
251
|
}
|
|
223
252
|
} else {
|
|
224
|
-
mkdirSync(
|
|
253
|
+
mkdirSync(dirname2(envFile), { recursive: true });
|
|
225
254
|
writeFileSync(envFile, `${key}='${escaped}'
|
|
226
255
|
`, "utf-8");
|
|
227
256
|
}
|
|
@@ -231,7 +260,7 @@ function updateEnvKey(key, value, envFile = ENV_FILE) {
|
|
|
231
260
|
// src/lib/systems.ts
|
|
232
261
|
function readSystems(configFile = SYSTEMS_CONFIG) {
|
|
233
262
|
if (!existsSync2(configFile)) return [];
|
|
234
|
-
const content =
|
|
263
|
+
const content = readFileSync3(configFile, "utf-8");
|
|
235
264
|
const systems = [];
|
|
236
265
|
let current = null;
|
|
237
266
|
for (const line of content.split("\n")) {
|
|
@@ -297,7 +326,7 @@ function addSystem(system, envFile = ENV_FILE, configFile = SYSTEMS_CONFIG) {
|
|
|
297
326
|
profile: ${profile}
|
|
298
327
|
agents: [${agentsList}]
|
|
299
328
|
`;
|
|
300
|
-
mkdirSync2(
|
|
329
|
+
mkdirSync2(dirname3(configFile), { recursive: true });
|
|
301
330
|
if (!existsSync2(configFile) || systemCount(configFile) === 0) {
|
|
302
331
|
const content = `# yaml-language-server: $schema=
|
|
303
332
|
# Ixora Systems Configuration
|
|
@@ -307,7 +336,7 @@ systems:
|
|
|
307
336
|
${entry}`;
|
|
308
337
|
writeFileSync2(configFile, content, "utf-8");
|
|
309
338
|
} else {
|
|
310
|
-
const existing =
|
|
339
|
+
const existing = readFileSync3(configFile, "utf-8");
|
|
311
340
|
writeFileSync2(configFile, `${existing}${entry}`, "utf-8");
|
|
312
341
|
}
|
|
313
342
|
chmodSync2(configFile, 384);
|
|
@@ -319,7 +348,7 @@ function removeSystem(id, envFile = ENV_FILE, configFile = SYSTEMS_CONFIG) {
|
|
|
319
348
|
if (!systemIdExists(id, configFile)) {
|
|
320
349
|
throw new Error(`System '${id}' not found`);
|
|
321
350
|
}
|
|
322
|
-
const content =
|
|
351
|
+
const content = readFileSync3(configFile, "utf-8");
|
|
323
352
|
const lines = content.split("\n");
|
|
324
353
|
const output = [];
|
|
325
354
|
let skip = false;
|
|
@@ -339,7 +368,7 @@ function removeSystem(id, envFile = ENV_FILE, configFile = SYSTEMS_CONFIG) {
|
|
|
339
368
|
chmodSync2(configFile, 384);
|
|
340
369
|
if (existsSync2(envFile)) {
|
|
341
370
|
const idUpper = id.toUpperCase().replace(/-/g, "_");
|
|
342
|
-
const envContent =
|
|
371
|
+
const envContent = readFileSync3(envFile, "utf-8");
|
|
343
372
|
const filtered = envContent.split("\n").filter((line) => !line.startsWith(`SYSTEM_${idUpper}_`)).join("\n");
|
|
344
373
|
writeFileSync2(envFile, filtered, "utf-8");
|
|
345
374
|
chmodSync2(envFile, 384);
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
waitForHealthy,
|
|
23
23
|
warn,
|
|
24
24
|
writeComposeFile
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-K2GF2QLM.js";
|
|
26
26
|
import {
|
|
27
27
|
COMPOSE_FILE,
|
|
28
28
|
ENV_FILE,
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
systemIdExists,
|
|
40
40
|
updateEnvKey,
|
|
41
41
|
writeEnvFile
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-KFC4SP2O.js";
|
|
43
43
|
|
|
44
44
|
// src/cli.ts
|
|
45
45
|
import { Command } from "commander";
|
|
@@ -297,6 +297,12 @@ function normalizeVersion(version) {
|
|
|
297
297
|
}
|
|
298
298
|
|
|
299
299
|
// src/commands/upgrade.ts
|
|
300
|
+
function rollback(previousVersion) {
|
|
301
|
+
warn("Rolling back to previous version...");
|
|
302
|
+
updateEnvKey("IXORA_VERSION", previousVersion);
|
|
303
|
+
writeComposeFile();
|
|
304
|
+
info(`Reverted IXORA_VERSION to ${previousVersion}`);
|
|
305
|
+
}
|
|
300
306
|
async function cmdUpgrade(opts) {
|
|
301
307
|
try {
|
|
302
308
|
requireInstalled();
|
|
@@ -335,7 +341,8 @@ async function cmdUpgrade(opts) {
|
|
|
335
341
|
}))
|
|
336
342
|
});
|
|
337
343
|
}
|
|
338
|
-
info(`Upgrading ixora: ${previousVersion}
|
|
344
|
+
info(`Upgrading ixora: ${previousVersion} -> ${targetVersion}`);
|
|
345
|
+
updateEnvKey("IXORA_PREVIOUS_VERSION", previousVersion);
|
|
339
346
|
info("Stopping services...");
|
|
340
347
|
await runCompose(composeCmd, ["down", "--remove-orphans"]);
|
|
341
348
|
updateEnvKey("IXORA_VERSION", targetVersion);
|
|
@@ -350,13 +357,31 @@ async function cmdUpgrade(opts) {
|
|
|
350
357
|
info(`Setting profile: ${opts.profile}`);
|
|
351
358
|
updateEnvKey("IXORA_PROFILE", opts.profile);
|
|
352
359
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
360
|
+
try {
|
|
361
|
+
if (opts.pull !== false) {
|
|
362
|
+
info("Pulling images...");
|
|
363
|
+
await runCompose(composeCmd, ["pull"], { throwOnError: true });
|
|
364
|
+
}
|
|
365
|
+
info("Starting services...");
|
|
366
|
+
await runCompose(composeCmd, ["up", "-d"], { throwOnError: true });
|
|
367
|
+
const healthy = await waitForHealthy(composeCmd);
|
|
368
|
+
if (!healthy) {
|
|
369
|
+
throw new Error(
|
|
370
|
+
"Services did not become healthy after upgrade"
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
} catch (err) {
|
|
374
|
+
rollback(previousVersion);
|
|
375
|
+
try {
|
|
376
|
+
await runCompose(composeCmd, ["down", "--remove-orphans"]);
|
|
377
|
+
} catch {
|
|
378
|
+
}
|
|
379
|
+
error(err.message);
|
|
380
|
+
info(
|
|
381
|
+
`Run ${bold("ixora logs")} to investigate, then retry with ${bold(`ixora upgrade ${targetVersion}`)}`
|
|
382
|
+
);
|
|
383
|
+
process.exit(1);
|
|
356
384
|
}
|
|
357
|
-
info("Restarting services...");
|
|
358
|
-
await runCompose(composeCmd, ["up", "-d"]);
|
|
359
|
-
await waitForHealthy(composeCmd);
|
|
360
385
|
const profile = envGet("IXORA_PROFILE") || "full";
|
|
361
386
|
console.log();
|
|
362
387
|
success("Upgrade complete!");
|
|
@@ -703,7 +728,7 @@ async function cmdInstall(opts) {
|
|
|
703
728
|
writeEnvFile(envConfig);
|
|
704
729
|
success("Wrote .env");
|
|
705
730
|
if (systemIdExists("default")) {
|
|
706
|
-
const { removeSystem: removeSystem2 } = await import("./systems-
|
|
731
|
+
const { removeSystem: removeSystem2 } = await import("./systems-JHJ3CQRN.js");
|
|
707
732
|
removeSystem2("default");
|
|
708
733
|
}
|
|
709
734
|
addSystem({
|
|
@@ -931,7 +956,7 @@ async function cmdSystemAdd() {
|
|
|
931
956
|
default: true
|
|
932
957
|
});
|
|
933
958
|
if (shouldRestart) {
|
|
934
|
-
const { cmdRestart: cmdRestart2 } = await import("./restart-
|
|
959
|
+
const { cmdRestart: cmdRestart2 } = await import("./restart-VIVFUUQG.js");
|
|
935
960
|
await cmdRestart2({});
|
|
936
961
|
} else {
|
|
937
962
|
console.log(` Restart to apply: ${bold("ixora restart")}`);
|