@meshxdata/fops 0.1.44 → 0.1.45
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.md +185 -0
- package/package.json +1 -1
- package/src/commands/lifecycle.js +20 -0
- package/src/plugins/bundled/fops-plugin-azure/lib/azure-ops.js +29 -0
- package/src/plugins/bundled/fops-plugin-azure/lib/azure-results.js +73 -0
- package/src/plugins/bundled/fops-plugin-azure/lib/azure.js +1 -1
- package/src/plugins/bundled/fops-plugin-azure/lib/commands/test-cmds.js +50 -0
- package/src/plugins/bundled/fops-plugin-azure/lib/commands/vm-cmds.js +10 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,188 @@
|
|
|
1
|
+
## [0.1.45] - 2026-03-12
|
|
2
|
+
|
|
3
|
+
- bump fops to 0.1.44 (8c0ef5d)
|
|
4
|
+
- Mlflow and azure plugin fix (176881f)
|
|
5
|
+
- fix lifecycle (a2cb9e7)
|
|
6
|
+
- callback url for localhost (821fb94)
|
|
7
|
+
- disable 4 scaffolding plugin by default. (bfb2b76)
|
|
8
|
+
- jaccard improvements (b7494a0)
|
|
9
|
+
- refactor azure plugin (68dfef4)
|
|
10
|
+
- refactor azure plugin (b24a008)
|
|
11
|
+
- fix trino catalog missing (4928a55)
|
|
12
|
+
- v36 bump and changelog generation on openai (37a0440)
|
|
13
|
+
- v36 bump and changelog generation on openai (a3b02d9)
|
|
14
|
+
- bump (a990058)
|
|
15
|
+
- status bar fix and new plugin for ttyd (27dde1e)
|
|
16
|
+
- file demo and tray (1a3e704)
|
|
17
|
+
- electron app (59ad0bb)
|
|
18
|
+
- compose and fops file plugin (1cf0e81)
|
|
19
|
+
- bump (346ffc1)
|
|
20
|
+
- localhost replaced by 127.0.0.1 (82b9f30)
|
|
21
|
+
- .29 (587b0e1)
|
|
22
|
+
- improve up down and bootstrap script (b79ebaf)
|
|
23
|
+
- checksum (22c8086)
|
|
24
|
+
- checksum (96b434f)
|
|
25
|
+
- checksum (15ed3c0)
|
|
26
|
+
- checksum (8a6543a)
|
|
27
|
+
- bump embed trino linksg (8440504)
|
|
28
|
+
- bump data (765ffd9)
|
|
29
|
+
- bump (cb8b232)
|
|
30
|
+
- broken tests (c532229)
|
|
31
|
+
- release 0.1.18, preflight checks (d902249)
|
|
32
|
+
- fix compute display bug (d10f5d9)
|
|
33
|
+
- cleanup packer files (6330f18)
|
|
34
|
+
- plan mode (cb36a8a)
|
|
35
|
+
- bump to 0.1.16 - agent ui (41ac1a2)
|
|
36
|
+
- bump to 0.1.15 - agent ui (4ebe2e1)
|
|
37
|
+
- bump to 0.1.14 (6c3a7fa)
|
|
38
|
+
- bump to 0.1.13 (8db570f)
|
|
39
|
+
- release 0.1.12 (c1c79e5)
|
|
40
|
+
- bump (11aa3b0)
|
|
41
|
+
- git keep and bump tui (be1678e)
|
|
42
|
+
- skills, index, rrf, compacted context (100k > 10k) (7b2fffd)
|
|
43
|
+
- cloudflare and token consumption, graphs indexing (0ad9eec)
|
|
44
|
+
- bump storage default (22c83ba)
|
|
45
|
+
- storage fix (68a22a0)
|
|
46
|
+
- skills update (7f56500)
|
|
47
|
+
- v9 bump (3864446)
|
|
48
|
+
- bump (c95eedc)
|
|
49
|
+
- rrf (dbf8c95)
|
|
50
|
+
- feat: warning when running predictions (95e8c52)
|
|
51
|
+
- feat: support for local predictions (45cf26b)
|
|
52
|
+
- feat: wip support for predictions + mlflow (3457052)
|
|
53
|
+
- add Reciprocal Rank Fusion (RRF) to knowledge and skill retrieval (61549bc)
|
|
54
|
+
- validate CSV headers in compute_run readiness check (a8c7a43)
|
|
55
|
+
- fix corrupted Iceberg metadata: probe tables + force cleanup on re-apply (50578af)
|
|
56
|
+
- enforce: never use foundation_apply to fix broken products (2e049bf)
|
|
57
|
+
- update SKILL.md with complete tool reference for knowledge retrieval (30b1924)
|
|
58
|
+
- add storage read, input DP table probe, and compute_run improvements (34e6c4c)
|
|
59
|
+
- skills update (1220385)
|
|
60
|
+
- skills update (bb66958)
|
|
61
|
+
- some tui improvement andd tools apply overwrite (e90c35c)
|
|
62
|
+
- skills update (e9227a1)
|
|
63
|
+
- skills update (669c4b3)
|
|
64
|
+
- fix plugin pre-flight checks (f741743)
|
|
65
|
+
- increase agent context (6479aaa)
|
|
66
|
+
- skills and init sql fixes (5fce35e)
|
|
67
|
+
- checksum (3518b56)
|
|
68
|
+
- penging job limit (a139861)
|
|
69
|
+
- checksum (575d28c)
|
|
70
|
+
- bump (92049ba)
|
|
71
|
+
- fix bug per tab status (0a33657)
|
|
72
|
+
- fix bug per tab status (50457c6)
|
|
73
|
+
- checksumming (0ad842e)
|
|
74
|
+
- shot af mardkwon overlapping (51f63b9)
|
|
75
|
+
- add spark dockerfile for multiarch builds (95abbd1)
|
|
76
|
+
- fix plugin initialization (16b9782)
|
|
77
|
+
- split index.js (50902a2)
|
|
78
|
+
- cloudflare cidr (cc4e021)
|
|
79
|
+
- cloduflare restrictions (2f6ba2d)
|
|
80
|
+
- sequential start (86b496e)
|
|
81
|
+
- sequential start (4930fe1)
|
|
82
|
+
- sequential start (353f014)
|
|
83
|
+
- qa tests (2dc6a1a)
|
|
84
|
+
- bump sha for .85 (dc2edfe)
|
|
85
|
+
- preserve env on sudo (7831227)
|
|
86
|
+
- bump sha for .84 (6c052f9)
|
|
87
|
+
- non interactive for azure vms (0aa8a2f)
|
|
88
|
+
- keep .env if present (d072450)
|
|
89
|
+
- bump (7a8e732)
|
|
90
|
+
- ensure opa is on compose if not set (f4a5228)
|
|
91
|
+
- checksum bump (a2ccc20)
|
|
92
|
+
- netrc defensive checks (a0b0ccc)
|
|
93
|
+
- netrc defensive checks (ae37403)
|
|
94
|
+
- checksum (ec45d11)
|
|
95
|
+
- update sync and fix up (7f9af72)
|
|
96
|
+
- expand test for azure and add new per app tag support (388a168)
|
|
97
|
+
- checksum on update (44005fc)
|
|
98
|
+
- cleanup for later (15e5313)
|
|
99
|
+
- cleanup for later (11c9597)
|
|
100
|
+
- switch branch feature (822fecc)
|
|
101
|
+
- add pull (d1c19ab)
|
|
102
|
+
- Bump hono from 4.11.9 to 4.12.0 in /operator-cli (ad25144)
|
|
103
|
+
- tests (f180a9a)
|
|
104
|
+
- cleanup (39c49a3)
|
|
105
|
+
- registry (7b7126a)
|
|
106
|
+
- reconcile kafka (832d0db)
|
|
107
|
+
- gh login bug (025886c)
|
|
108
|
+
- cleanup (bb96cab)
|
|
109
|
+
- strip envs from process (2421180)
|
|
110
|
+
- force use of gh creds not tokens in envs var (fff7787)
|
|
111
|
+
- resolve import between npm installs and npm link (79522e1)
|
|
112
|
+
- fix gh scope and azure states (afd846c)
|
|
113
|
+
- refactoring (da50352)
|
|
114
|
+
- split fops repo (d447638)
|
|
115
|
+
- aks (b791f8f)
|
|
116
|
+
- refactor azure (67d3bad)
|
|
117
|
+
- wildcard (391f023)
|
|
118
|
+
- azure plugin (c074074)
|
|
119
|
+
- zap (d7e6e7f)
|
|
120
|
+
- fix knock (cf89c05)
|
|
121
|
+
- azure (4adec98)
|
|
122
|
+
- Bump tar from 7.5.7 to 7.5.9 in /operator-cli (e41e98e)
|
|
123
|
+
- azure stack index.js split (de12272)
|
|
124
|
+
- Bump ajv from 8.17.1 to 8.18.0 in /operator-cli (76da21f)
|
|
125
|
+
- packer (9665fbc)
|
|
126
|
+
- remove stack api (db0fd4d)
|
|
127
|
+
- packer cleanup (fe1bf14)
|
|
128
|
+
- force refresh token (3a3d7e2)
|
|
129
|
+
- provision shell (2ad505f)
|
|
130
|
+
- azure vm management (91dcb31)
|
|
131
|
+
- azure specific (2b0cca8)
|
|
132
|
+
- azure packer (12175b8)
|
|
133
|
+
- init hashed pwd (db8523c)
|
|
134
|
+
- packer (5b5c7c4)
|
|
135
|
+
- doctor for azure vm (ed524fa)
|
|
136
|
+
- packer and 1pwd (c6d053e)
|
|
137
|
+
- split big index.js (dc85a1b)
|
|
138
|
+
- kafka volume update (21815ec)
|
|
139
|
+
- fix openai azure tools confirmation and flow (0118cd1)
|
|
140
|
+
- nighly fixx, test fix (5e0d04f)
|
|
141
|
+
- open ai training (cdc494a)
|
|
142
|
+
- openai integration in azure (1ca1475)
|
|
143
|
+
- ci (672cea9)
|
|
144
|
+
- refresh ghcr creds (4220c48)
|
|
145
|
+
- cleaned up version (1a0074f)
|
|
146
|
+
- traefik on ghcr and templates (8e31a05)
|
|
147
|
+
- apply fcl (e78911f)
|
|
148
|
+
- demo landscape (dd205fe)
|
|
149
|
+
- smarter login and schema (1af514f)
|
|
150
|
+
- no down before up unless something broke (56b1132)
|
|
151
|
+
- dai, reconcile failed containers (12907fa)
|
|
152
|
+
- reconcile dead container (7da75e4)
|
|
153
|
+
- defensive around storage buckets dir (b98871d)
|
|
154
|
+
- defensive around storage buckets dir (e86e132)
|
|
155
|
+
- gear in for multiarch (bf3fa3e)
|
|
156
|
+
- up autofix (99c7f89)
|
|
157
|
+
- autofix stale containers on up (43c7d0f)
|
|
158
|
+
- shared sessions fix (5de1359)
|
|
159
|
+
- share sessions between ui and tui (8321391)
|
|
160
|
+
- fix chat view display details (e263996)
|
|
161
|
+
- fix chat view display details (9babdda)
|
|
162
|
+
- tui up fixes (86e9f17)
|
|
163
|
+
- fix commands init (442538b)
|
|
164
|
+
- enable k3s profile (b2dcfc8)
|
|
165
|
+
- test up till job creation (656d388)
|
|
166
|
+
- tui fixes (0599779)
|
|
167
|
+
- cleanup (27731f0)
|
|
168
|
+
- train (90bf559)
|
|
169
|
+
- training (f809bf6)
|
|
170
|
+
- training (ba2b836)
|
|
171
|
+
- training (6fc5267)
|
|
172
|
+
- training (4af8ac9)
|
|
173
|
+
- fix build script (bd82836)
|
|
174
|
+
- infra test (5b79815)
|
|
175
|
+
- infra test (3a0ac05)
|
|
176
|
+
- infra test (e5c67b5)
|
|
177
|
+
- tests (ae7b621)
|
|
178
|
+
- tests (c09ae6a)
|
|
179
|
+
- update tui (4784153)
|
|
180
|
+
- training (0a5a330)
|
|
181
|
+
- tui (df4dd4a)
|
|
182
|
+
- pkg builds (4dc9993)
|
|
183
|
+
- also source env for creds (9a17d8f)
|
|
184
|
+
- fcl support (e8a5743)
|
|
185
|
+
|
|
1
186
|
# Changelog
|
|
2
187
|
|
|
3
188
|
All notable changes to @meshxdata/fops (Foundation Operator CLI) are documented here.
|
package/package.json
CHANGED
|
@@ -159,6 +159,26 @@ export function registerLifecycleCommands(program, registry) {
|
|
|
159
159
|
await dockerCompose(root, args);
|
|
160
160
|
});
|
|
161
161
|
|
|
162
|
+
program
|
|
163
|
+
.command("restart")
|
|
164
|
+
.description("Restart Foundation services (all or specific)")
|
|
165
|
+
.argument("[services...]", "Services to restart (e.g. backend, watcher)")
|
|
166
|
+
.action(async (services) => {
|
|
167
|
+
const root = requireRoot(program);
|
|
168
|
+
const serviceNames = (services || []).filter(Boolean).flatMap((s) => {
|
|
169
|
+
const sub = COMPONENT_SUBMODULES[s];
|
|
170
|
+
if (sub) return sub.restart;
|
|
171
|
+
return [resolveServiceName(root, s)];
|
|
172
|
+
});
|
|
173
|
+
if (serviceNames.length) {
|
|
174
|
+
console.log(chalk.cyan(` Restarting ${serviceNames.join(", ")}...`));
|
|
175
|
+
await dockerCompose(root, ["restart", ...serviceNames]);
|
|
176
|
+
} else {
|
|
177
|
+
console.log(chalk.cyan(" Restarting all services..."));
|
|
178
|
+
await dockerCompose(root, ["restart"]);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
162
182
|
program
|
|
163
183
|
.command("bake")
|
|
164
184
|
.description("Build and push multi-arch base container images (node, etc.)")
|
|
@@ -2136,6 +2136,35 @@ export async function azureLogs(service, opts = {}) {
|
|
|
2136
2136
|
], { stdio: "inherit", reject: false });
|
|
2137
2137
|
}
|
|
2138
2138
|
|
|
2139
|
+
// ── restart ─────────────────────────────────────────────────────────────────
|
|
2140
|
+
|
|
2141
|
+
export async function azureRestart(service, opts = {}) {
|
|
2142
|
+
const state = requireVmState(opts.vmName);
|
|
2143
|
+
const ip = state.publicIp;
|
|
2144
|
+
if (!ip) { console.error(chalk.red("\n No IP. Is the VM running?\n")); process.exit(1); }
|
|
2145
|
+
|
|
2146
|
+
await knockForVm(state);
|
|
2147
|
+
|
|
2148
|
+
const { execa } = await import("execa");
|
|
2149
|
+
const adminUser = DEFAULTS.adminUser;
|
|
2150
|
+
|
|
2151
|
+
const svcArg = service ? (service.startsWith("foundation-") ? service : `foundation-${service}`) : "";
|
|
2152
|
+
const label = svcArg || "all services";
|
|
2153
|
+
console.log(chalk.cyan(` Restarting ${label} on ${state.vmName || ip}...`));
|
|
2154
|
+
|
|
2155
|
+
const { exitCode } = await execa("ssh", [
|
|
2156
|
+
"-o", "StrictHostKeyChecking=no",
|
|
2157
|
+
`${adminUser}@${ip}`,
|
|
2158
|
+
`cd /opt/foundation-compose && sudo docker compose restart ${svcArg}`,
|
|
2159
|
+
], { stdio: "inherit", reject: false });
|
|
2160
|
+
|
|
2161
|
+
if (exitCode === 0) {
|
|
2162
|
+
console.log(chalk.green(` ✓ ${label} restarted`));
|
|
2163
|
+
} else {
|
|
2164
|
+
console.error(chalk.red(` ✗ restart failed (exit ${exitCode})`));
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2139
2168
|
// ── grant-admin ─────────────────────────────────────────────────────────────
|
|
2140
2169
|
|
|
2141
2170
|
export async function azureGrantAdmin(opts = {}) {
|
|
@@ -235,6 +235,79 @@ export async function resultsPush(target, qaResult, opts = {}) {
|
|
|
235
235
|
return { blob, account: store.account };
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
+
// ── Remove ──────────────────────────────────────────────────────────────────
|
|
239
|
+
|
|
240
|
+
export async function resultsRemove(target, opts = {}) {
|
|
241
|
+
const execa = await lazyExeca();
|
|
242
|
+
await ensureAzCli(execa);
|
|
243
|
+
await ensureAzAuth(execa, { subscription: opts.subscription });
|
|
244
|
+
|
|
245
|
+
// 1. Clear local state
|
|
246
|
+
const state = readState();
|
|
247
|
+
const vm = state.azure?.vms?.[target];
|
|
248
|
+
if (vm?.qa) {
|
|
249
|
+
delete vm.qa;
|
|
250
|
+
saveState(state);
|
|
251
|
+
console.log(OK(` ✓ Local QA state cleared for "${target}"`));
|
|
252
|
+
} else {
|
|
253
|
+
console.log(DIM(` No local QA state found for "${target}"`));
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// 2. Delete blobs from storage
|
|
257
|
+
const store = getResultsConfig();
|
|
258
|
+
if (!store?.account) {
|
|
259
|
+
console.log(DIM(" No results storage configured — skipping blob deletion."));
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const prefix = `${BLOB_PREFIX}/${target}/`;
|
|
264
|
+
let blobs;
|
|
265
|
+
try {
|
|
266
|
+
const { stdout } = await execa("az", [
|
|
267
|
+
"storage", "blob", "list",
|
|
268
|
+
"--account-name", store.account,
|
|
269
|
+
"--container-name", CONTAINER_NAME,
|
|
270
|
+
"--prefix", prefix,
|
|
271
|
+
"--query", "[].name",
|
|
272
|
+
"--output", "json",
|
|
273
|
+
...AUTH,
|
|
274
|
+
...subArgs(opts.subscription),
|
|
275
|
+
], { timeout: 30000 });
|
|
276
|
+
blobs = JSON.parse(stdout || "[]");
|
|
277
|
+
} catch (err) {
|
|
278
|
+
console.log(WARN(` ⚠ Could not list blobs: ${err.message}`));
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (blobs.length === 0) {
|
|
283
|
+
console.log(DIM(` No stored results found in blob storage for "${target}"`));
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
console.log(chalk.cyan(`\n Deleting ${blobs.length} result(s) from ${store.account}/${CONTAINER_NAME}/${prefix}…\n`));
|
|
288
|
+
|
|
289
|
+
let deleted = 0;
|
|
290
|
+
for (const blobName of blobs) {
|
|
291
|
+
try {
|
|
292
|
+
await execa("az", [
|
|
293
|
+
"storage", "blob", "delete",
|
|
294
|
+
"--account-name", store.account,
|
|
295
|
+
"--container-name", CONTAINER_NAME,
|
|
296
|
+
"--name", blobName,
|
|
297
|
+
...AUTH,
|
|
298
|
+
"--output", "none",
|
|
299
|
+
...subArgs(opts.subscription),
|
|
300
|
+
], { timeout: 15000 });
|
|
301
|
+
console.log(` ${DIM(`✗ ${blobName}`)}`);
|
|
302
|
+
deleted++;
|
|
303
|
+
} catch (err) {
|
|
304
|
+
console.log(WARN(` ⚠ Failed to delete ${blobName}: ${err.message}`));
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
console.log(OK(`\n ✓ Removed ${deleted}/${blobs.length} result(s) for "${target}"\n`));
|
|
309
|
+
}
|
|
310
|
+
|
|
238
311
|
// ── List ────────────────────────────────────────────────────────────────────
|
|
239
312
|
|
|
240
313
|
export async function resultsList(opts = {}) {
|
|
@@ -48,7 +48,7 @@ export {
|
|
|
48
48
|
export {
|
|
49
49
|
azureStatus, azureTrinoStatus, azureSsh, azureSshWhitelistMe, azurePortForward, azureSshAdminAdd, azureVmCheck, azureAgent, azureOpenAiDebugVm,
|
|
50
50
|
azureDeploy, azurePull, azureDeployVersion, azureRunUp, azureConfig, azureConfigVersions, azureUpdate,
|
|
51
|
-
azureLogs, azureGrantAdmin, azureContext,
|
|
51
|
+
azureLogs, azureRestart, azureGrantAdmin, azureContext,
|
|
52
52
|
azureList, azureApply,
|
|
53
53
|
azureKnock, azureKnockClose, azureKnockDisable, azureKnockVerify, azureKnockFix,
|
|
54
54
|
} from "./azure-ops.js";
|
|
@@ -56,6 +56,39 @@ export function registerTestCommands(azure) {
|
|
|
56
56
|
});
|
|
57
57
|
let { bearerToken, qaUser, qaPass, useTokenMode } = auth;
|
|
58
58
|
|
|
59
|
+
// Fetch CF Access service token (needed to bypass Cloudflare Access)
|
|
60
|
+
// Priority: local .env file → process.env → remote VM .env
|
|
61
|
+
let cfAccessClientId = "";
|
|
62
|
+
let cfAccessClientSecret = "";
|
|
63
|
+
const localEnvPath = path.join(root, ".env");
|
|
64
|
+
try {
|
|
65
|
+
const localEnv = await fsp.readFile(localEnvPath, "utf8");
|
|
66
|
+
for (const line of localEnv.split("\n")) {
|
|
67
|
+
const m = line.match(/^CF_ACCESS_CLIENT_(ID|SECRET)=(.+)$/);
|
|
68
|
+
if (m?.[1] === "ID") cfAccessClientId = m[2].trim().replace(/^["']|["']$/g, "");
|
|
69
|
+
if (m?.[1] === "SECRET") cfAccessClientSecret = m[2].trim().replace(/^["']|["']$/g, "");
|
|
70
|
+
}
|
|
71
|
+
} catch { /* no local .env */ }
|
|
72
|
+
if (!cfAccessClientId) {
|
|
73
|
+
cfAccessClientId = process.env.CF_ACCESS_CLIENT_ID || "";
|
|
74
|
+
cfAccessClientSecret = process.env.CF_ACCESS_CLIENT_SECRET || "";
|
|
75
|
+
}
|
|
76
|
+
if (!cfAccessClientId && ip) {
|
|
77
|
+
try {
|
|
78
|
+
const sshUser = state?.adminUser || "azureuser";
|
|
79
|
+
const { stdout: cfOut } = await sshCmd(execa, ip, sshUser,
|
|
80
|
+
"grep -E '^CF_ACCESS_CLIENT_(ID|SECRET)=' /opt/foundation-compose/.env",
|
|
81
|
+
10_000,
|
|
82
|
+
);
|
|
83
|
+
for (const line of (cfOut || "").split("\n")) {
|
|
84
|
+
const m = line.match(/^CF_ACCESS_CLIENT_(ID|SECRET)=(.+)$/);
|
|
85
|
+
if (m?.[1] === "ID") cfAccessClientId = m[2].trim();
|
|
86
|
+
if (m?.[1] === "SECRET") cfAccessClientSecret = m[2].trim();
|
|
87
|
+
}
|
|
88
|
+
if (cfAccessClientId) console.log(chalk.green(" ✓ Got CF Access service token from VM"));
|
|
89
|
+
} catch { /* optional — tests still run without it */ }
|
|
90
|
+
}
|
|
91
|
+
|
|
59
92
|
if (!bearerToken && !qaUser) {
|
|
60
93
|
console.error(chalk.red("\n No credentials found (local or remote)."));
|
|
61
94
|
console.error(chalk.dim(" Set BEARER_TOKEN or QA_USERNAME/QA_PASSWORD, or ensure the VM has Auth0 configured in .env\n"));
|
|
@@ -94,6 +127,10 @@ export function registerTestCommands(azure) {
|
|
|
94
127
|
envContent = setVar(envContent, "BEARER_TOKEN", bearerToken);
|
|
95
128
|
envContent = setVar(envContent, "TOKEN_AUTH0", bearerToken);
|
|
96
129
|
}
|
|
130
|
+
if (cfAccessClientId) {
|
|
131
|
+
envContent = setVar(envContent, "CF_ACCESS_CLIENT_ID", cfAccessClientId);
|
|
132
|
+
envContent = setVar(envContent, "CF_ACCESS_CLIENT_SECRET", cfAccessClientSecret);
|
|
133
|
+
}
|
|
97
134
|
|
|
98
135
|
await fsp.writeFile(envPath, envContent);
|
|
99
136
|
console.log(chalk.green(` ✓ Configured QA .env → ${apiUrl}`));
|
|
@@ -155,6 +192,10 @@ export function registerTestCommands(azure) {
|
|
|
155
192
|
testEnv.BEARER_TOKEN = bearerToken;
|
|
156
193
|
testEnv.TOKEN_AUTH0 = bearerToken;
|
|
157
194
|
}
|
|
195
|
+
if (cfAccessClientId) {
|
|
196
|
+
testEnv.CF_ACCESS_CLIENT_ID = cfAccessClientId;
|
|
197
|
+
testEnv.CF_ACCESS_CLIENT_SECRET = cfAccessClientSecret;
|
|
198
|
+
}
|
|
158
199
|
|
|
159
200
|
const startMs = Date.now();
|
|
160
201
|
const proc = execa(
|
|
@@ -245,6 +286,15 @@ export function registerTestCommands(azure) {
|
|
|
245
286
|
await resultsCompare({ target, last: parseInt(opts.last) });
|
|
246
287
|
});
|
|
247
288
|
|
|
289
|
+
test
|
|
290
|
+
.command("rm <target>")
|
|
291
|
+
.description("Remove all stored test results for a VM (local state + blob storage)")
|
|
292
|
+
.option("--profile <subscription>", "Azure subscription name or ID")
|
|
293
|
+
.action(async (target, opts) => {
|
|
294
|
+
const { resultsRemove } = await import("../azure-results.js");
|
|
295
|
+
await resultsRemove(target, { subscription: opts.profile });
|
|
296
|
+
});
|
|
297
|
+
|
|
248
298
|
test
|
|
249
299
|
.command("push [target]")
|
|
250
300
|
.description("Push local QA results to blob storage (default: all VMs with results)")
|
|
@@ -875,6 +875,16 @@ export function registerVmCommands(azure, api, registry) {
|
|
|
875
875
|
await azureLogs(service, { vmName: opts.vmName || name });
|
|
876
876
|
});
|
|
877
877
|
|
|
878
|
+
// ── restart ─────────────────────────────────────────────────────────────────
|
|
879
|
+
azure
|
|
880
|
+
.command("restart [name] [service]")
|
|
881
|
+
.description("Restart Foundation services on the VM (all or specific)")
|
|
882
|
+
.option("--vm-name <name>", "Target VM (default: active VM)")
|
|
883
|
+
.action(async (name, service, opts) => {
|
|
884
|
+
const { azureRestart } = await import("../azure.js");
|
|
885
|
+
await azureRestart(service, { vmName: opts.vmName || name });
|
|
886
|
+
});
|
|
887
|
+
|
|
878
888
|
// ── context ───────────────────────────────────────────────────────────────
|
|
879
889
|
azure
|
|
880
890
|
.command("context [name]")
|