microfox 1.1.7 → 1.2.0

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @microfox/cli
2
2
 
3
+ ## 1.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - f81596c: grouped deployments of project
8
+
3
9
  ## 1.1.7
4
10
 
5
11
  ### Patch Changes
package/dist/cli.js CHANGED
@@ -30813,14 +30813,14 @@ var require_path_arg = __commonJS({
30813
30813
  var require_find_made = __commonJS({
30814
30814
  "../../node_modules/mkdirp/lib/find-made.js"(exports2, module2) {
30815
30815
  "use strict";
30816
- var { dirname: dirname2 } = require("path");
30816
+ var { dirname: dirname3 } = require("path");
30817
30817
  var findMade = (opts, parent2, path18 = void 0) => {
30818
30818
  if (path18 === parent2)
30819
30819
  return Promise.resolve();
30820
30820
  return opts.statAsync(parent2).then(
30821
30821
  (st) => st.isDirectory() ? path18 : void 0,
30822
30822
  // will fail later
30823
- (er) => er.code === "ENOENT" ? findMade(opts, dirname2(parent2), parent2) : void 0
30823
+ (er) => er.code === "ENOENT" ? findMade(opts, dirname3(parent2), parent2) : void 0
30824
30824
  );
30825
30825
  };
30826
30826
  var findMadeSync = (opts, parent2, path18 = void 0) => {
@@ -30829,7 +30829,7 @@ var require_find_made = __commonJS({
30829
30829
  try {
30830
30830
  return opts.statSync(parent2).isDirectory() ? path18 : void 0;
30831
30831
  } catch (er) {
30832
- return er.code === "ENOENT" ? findMadeSync(opts, dirname2(parent2), parent2) : void 0;
30832
+ return er.code === "ENOENT" ? findMadeSync(opts, dirname3(parent2), parent2) : void 0;
30833
30833
  }
30834
30834
  };
30835
30835
  module2.exports = { findMade, findMadeSync };
@@ -30840,10 +30840,10 @@ var require_find_made = __commonJS({
30840
30840
  var require_mkdirp_manual = __commonJS({
30841
30841
  "../../node_modules/mkdirp/lib/mkdirp-manual.js"(exports2, module2) {
30842
30842
  "use strict";
30843
- var { dirname: dirname2 } = require("path");
30843
+ var { dirname: dirname3 } = require("path");
30844
30844
  var mkdirpManual = (path18, opts, made) => {
30845
30845
  opts.recursive = false;
30846
- const parent2 = dirname2(path18);
30846
+ const parent2 = dirname3(path18);
30847
30847
  if (parent2 === path18) {
30848
30848
  return opts.mkdirAsync(path18, opts).catch((er) => {
30849
30849
  if (er.code !== "EISDIR")
@@ -30866,7 +30866,7 @@ var require_mkdirp_manual = __commonJS({
30866
30866
  });
30867
30867
  };
30868
30868
  var mkdirpManualSync = (path18, opts, made) => {
30869
- const parent2 = dirname2(path18);
30869
+ const parent2 = dirname3(path18);
30870
30870
  opts.recursive = false;
30871
30871
  if (parent2 === path18) {
30872
30872
  try {
@@ -30902,12 +30902,12 @@ var require_mkdirp_manual = __commonJS({
30902
30902
  var require_mkdirp_native = __commonJS({
30903
30903
  "../../node_modules/mkdirp/lib/mkdirp-native.js"(exports2, module2) {
30904
30904
  "use strict";
30905
- var { dirname: dirname2 } = require("path");
30905
+ var { dirname: dirname3 } = require("path");
30906
30906
  var { findMade, findMadeSync } = require_find_made();
30907
30907
  var { mkdirpManual, mkdirpManualSync } = require_mkdirp_manual();
30908
30908
  var mkdirpNative = (path18, opts) => {
30909
30909
  opts.recursive = true;
30910
- const parent2 = dirname2(path18);
30910
+ const parent2 = dirname3(path18);
30911
30911
  if (parent2 === path18)
30912
30912
  return opts.mkdirAsync(path18, opts);
30913
30913
  return findMade(opts, path18).then((made) => opts.mkdirAsync(path18, opts).then(() => made).catch((er) => {
@@ -30919,7 +30919,7 @@ var require_mkdirp_native = __commonJS({
30919
30919
  };
30920
30920
  var mkdirpNativeSync = (path18, opts) => {
30921
30921
  opts.recursive = true;
30922
- const parent2 = dirname2(path18);
30922
+ const parent2 = dirname3(path18);
30923
30923
  if (parent2 === path18)
30924
30924
  return opts.mkdirSync(path18, opts);
30925
30925
  const made = findMadeSync(opts, path18);
@@ -31021,7 +31021,7 @@ var require_chownr = __commonJS({
31021
31021
  } : (path19, uid, gid) => lchownSync(path19, uid, gid);
31022
31022
  var nodeVersion = process.version;
31023
31023
  var readdir2 = (path19, options, cb) => fs12.readdir(path19, options, cb);
31024
- var readdirSync3 = (path19, options) => fs12.readdirSync(path19, options);
31024
+ var readdirSync4 = (path19, options) => fs12.readdirSync(path19, options);
31025
31025
  if (/^v4\./.test(nodeVersion))
31026
31026
  readdir2 = (path19, options, cb) => fs12.readdir(path19, cb);
31027
31027
  var chown = (cpath, uid, gid, cb) => {
@@ -31092,7 +31092,7 @@ var require_chownr = __commonJS({
31092
31092
  var chownrSync = (p, uid, gid) => {
31093
31093
  let children;
31094
31094
  try {
31095
- children = readdirSync3(p, { withFileTypes: true });
31095
+ children = readdirSync4(p, { withFileTypes: true });
31096
31096
  } catch (er) {
31097
31097
  if (er.code === "ENOENT")
31098
31098
  return;
@@ -110117,21 +110117,98 @@ function getLatestDeploymentId(cwd, n = 1) {
110117
110117
  const sorted = [...records].sort((a, b) => b.timestamp - a.timestamp);
110118
110118
  return sorted.slice(0, n).map((r) => r.deploymentId);
110119
110119
  }
110120
+ function getDeploymentsPathAtRoot(serverlessRoot) {
110121
+ return path8.join(serverlessRoot, DEPLOYMENTS_FILE);
110122
+ }
110123
+ function saveDeploymentRecordToRoot(serverlessRoot, deploymentId, group) {
110124
+ const filePath = getDeploymentsPathAtRoot(serverlessRoot);
110125
+ const records = getDeploymentRecordsFromRoot(serverlessRoot);
110126
+ const newRecord = {
110127
+ deploymentId,
110128
+ timestamp: Date.now(),
110129
+ date: (/* @__PURE__ */ new Date()).toISOString(),
110130
+ ...group != null && group !== "" ? { group } : {}
110131
+ };
110132
+ records.push(newRecord);
110133
+ fs4.writeFileSync(filePath, JSON.stringify(records, null, 2));
110134
+ }
110135
+ function getDeploymentRecordsFromRoot(serverlessRoot) {
110136
+ const filePath = getDeploymentsPathAtRoot(serverlessRoot);
110137
+ if (!fs4.existsSync(filePath)) {
110138
+ return [];
110139
+ }
110140
+ try {
110141
+ const content = fs4.readFileSync(filePath, "utf-8");
110142
+ return JSON.parse(content);
110143
+ } catch (e) {
110144
+ return [];
110145
+ }
110146
+ }
110147
+ function getLatestDeploymentIdFromRoot(serverlessRoot, n = 1, group) {
110148
+ let records = getDeploymentRecordsFromRoot(serverlessRoot);
110149
+ if (group != null && group !== "") {
110150
+ records = records.filter((r) => {
110151
+ var _a4;
110152
+ return ((_a4 = r.group) != null ? _a4 : "") === group;
110153
+ });
110154
+ }
110155
+ if (records.length === 0) {
110156
+ return [];
110157
+ }
110158
+ const sorted = [...records].sort((a, b) => b.timestamp - a.timestamp);
110159
+ return sorted.slice(0, n).map((r) => r.deploymentId);
110160
+ }
110120
110161
  function findServerlessWorkersDir(startDir) {
110121
110162
  const resolvedStart = path8.resolve(startDir);
110163
+ const looksLikeServerlessWorkersDir = (dir2) => {
110164
+ if (!fs4.existsSync(dir2)) return false;
110165
+ try {
110166
+ if (!fs4.statSync(dir2).isDirectory()) return false;
110167
+ } catch (e) {
110168
+ return false;
110169
+ }
110170
+ if (fs4.existsSync(path8.join(dir2, "serverless.yml"))) return true;
110171
+ try {
110172
+ const entries = fs4.readdirSync(dir2, { withFileTypes: true });
110173
+ for (const e of entries) {
110174
+ if (e.isDirectory() && !e.name.startsWith(".")) {
110175
+ if (fs4.existsSync(path8.join(dir2, e.name, "serverless.yml"))) {
110176
+ return true;
110177
+ }
110178
+ }
110179
+ }
110180
+ } catch (e) {
110181
+ }
110182
+ return false;
110183
+ };
110122
110184
  const serverlessDirInCurrent = path8.join(resolvedStart, DEPLOYMENTS_DIR);
110123
- const configPathInCurrent = path8.join(serverlessDirInCurrent, "microfox.json");
110124
- if (fs4.existsSync(serverlessDirInCurrent) && fs4.existsSync(configPathInCurrent)) {
110185
+ if (looksLikeServerlessWorkersDir(serverlessDirInCurrent)) {
110125
110186
  return serverlessDirInCurrent;
110126
110187
  }
110127
110188
  const parentDir = path8.dirname(resolvedStart);
110128
110189
  const serverlessDirInParent = path8.join(parentDir, DEPLOYMENTS_DIR);
110129
- const configPathInParent = path8.join(serverlessDirInParent, "microfox.json");
110130
- if (fs4.existsSync(serverlessDirInParent) && fs4.existsSync(configPathInParent)) {
110190
+ if (looksLikeServerlessWorkersDir(serverlessDirInParent)) {
110131
110191
  return serverlessDirInParent;
110132
110192
  }
110133
110193
  return null;
110134
110194
  }
110195
+ function getPerGroupNames(serverlessRoot) {
110196
+ const rootServerlessYml = path8.join(serverlessRoot, "serverless.yml");
110197
+ if (fs4.existsSync(rootServerlessYml)) {
110198
+ return null;
110199
+ }
110200
+ const entries = fs4.readdirSync(serverlessRoot, { withFileTypes: true });
110201
+ const groups = [];
110202
+ for (const e of entries) {
110203
+ if (e.isDirectory() && !e.name.startsWith(".")) {
110204
+ const groupServerlessYml = path8.join(serverlessRoot, e.name, "serverless.yml");
110205
+ if (fs4.existsSync(groupServerlessYml)) {
110206
+ groups.push(e.name);
110207
+ }
110208
+ }
110209
+ }
110210
+ return groups.length > 0 ? groups : null;
110211
+ }
110135
110212
 
110136
110213
  // src/commands/push.ts
110137
110214
  var FormData3 = require_form_data();
@@ -110198,18 +110275,28 @@ async function createZipArchive(sourceDir, ignorePatterns) {
110198
110275
  await finalizePromise;
110199
110276
  return zipPath;
110200
110277
  }
110201
- async function pushAction() {
110202
- var _a4, _b3, _c2, _d2, _e2;
110278
+ async function pushAction(groupname, skipGroup) {
110279
+ var _a4, _b3;
110203
110280
  let cwd = process.cwd();
110204
110281
  const serverlessDir = findServerlessWorkersDir(cwd);
110205
110282
  if (serverlessDir) {
110206
110283
  cwd = serverlessDir;
110207
110284
  process.chdir(cwd);
110208
110285
  }
110209
- const microfoxConfigPath = path9.join(cwd, "microfox.json");
110286
+ let microfoxConfigPath = path9.join(cwd, "microfox.json");
110210
110287
  if (!fs5.existsSync(microfoxConfigPath)) {
110211
- console.error(source_default.red("\u274C Error: `microfox.json` not found in the current directory."));
110212
- console.log(source_default.yellow("This command must be run from the root of an agent project."));
110288
+ const parentConfigPath = path9.join(path9.dirname(cwd), "microfox.json");
110289
+ if (fs5.existsSync(parentConfigPath)) {
110290
+ try {
110291
+ fs5.copyFileSync(parentConfigPath, microfoxConfigPath);
110292
+ } catch (e) {
110293
+ }
110294
+ microfoxConfigPath = fs5.existsSync(microfoxConfigPath) ? microfoxConfigPath : parentConfigPath;
110295
+ }
110296
+ }
110297
+ if (!fs5.existsSync(microfoxConfigPath)) {
110298
+ console.error(source_default.red("\u274C Error: `microfox.json` not found in the current directory or its parent."));
110299
+ console.log(source_default.yellow("Run this command from the root of an agent project, or from its `.serverless-workers` directory."));
110213
110300
  process.exit(1);
110214
110301
  }
110215
110302
  console.log(source_default.cyan("\u{1F680} Pushing your agent to Microfox..."));
@@ -110221,54 +110308,92 @@ async function pushAction() {
110221
110308
  const isV2 = typeof apiVersion === "string" ? apiVersion.toLowerCase() === "v2" : false;
110222
110309
  try {
110223
110310
  if (isV2) {
110224
- const ignorePatterns = ["node_modules/**", ".git/**", ...deploymentConfig.ignorePatterns || microfoxConfig.ignorePatterns || []];
110225
- console.log(source_default.blue("\u{1F4E6} Bundling your agent as a ZIP archive..."));
110226
- const zipPath = await createZipArchive(cwd, ignorePatterns);
110227
- console.log(source_default.blue("\u{1F69A} Uploading archive to Microfox..."));
110228
- const form = new FormData3();
110229
- form.append("archive", fs5.createReadStream(zipPath), {
110230
- filename: "archive.zip",
110231
- contentType: "application/zip"
110232
- });
110233
- if (microfoxConfig.publish) {
110234
- form.append("publish", JSON.stringify(microfoxConfig.publish));
110235
- }
110236
110311
  const projectId = microfoxConfig.projectId || process.env.PROJECT_ID;
110237
110312
  if (!projectId) {
110238
110313
  console.error(source_default.red("\u274C Error: `projectId` is required. Add `projectId` to your microfox.json."));
110239
110314
  process.exit(1);
110240
110315
  }
110241
- const headers = {
110242
- ...form.getHeaders(),
110243
- "x-project-id": projectId
110244
- };
110245
- const response = await axios_default.post(
110246
- API_ENDPOINT_MAPPER({ mode: apiMode, version: "v2", port: apiLocalPort }),
110247
- form,
110248
- {
110249
- headers,
110250
- maxBodyLength: Infinity,
110251
- maxContentLength: Infinity
110316
+ const perGroupNames = getPerGroupNames(cwd);
110317
+ const skipSet = skipGroup ? new Set(skipGroup.split(",").map((g) => g.trim()).filter(Boolean)) : null;
110318
+ let groupsToPush;
110319
+ if (perGroupNames !== null) {
110320
+ groupsToPush = groupname ? perGroupNames.includes(groupname) ? [groupname] : [] : perGroupNames.filter((g) => !(skipSet == null ? void 0 : skipSet.has(g)));
110321
+ if (groupsToPush.length === 0) {
110322
+ if (groupname) {
110323
+ console.error(source_default.red(`\u274C No such group: ${groupname}. Available: ${perGroupNames.join(", ")}`));
110324
+ } else {
110325
+ console.error(source_default.red("\u274C No groups to push (all skipped or none match)."));
110326
+ }
110327
+ process.exit(1);
110252
110328
  }
110253
- );
110254
- if (response.status >= 200 && response.status < 300) {
110255
- console.log(source_default.green("\u2705 Deployment request accepted!"));
110256
- if ((_a4 = response.data) == null ? void 0 : _a4.deploymentId) {
110257
- const deploymentId = response.data.deploymentId;
110258
- console.log(source_default.green(` Deployment ID: ${deploymentId}`));
110259
- saveDeploymentRecord(cwd, deploymentId);
110260
- } else if ((_b3 = response.data) == null ? void 0 : _b3.runId) {
110261
- const runId = response.data.runId;
110262
- console.log(source_default.green(` Run ID: ${runId}`));
110263
- saveDeploymentRecord(cwd, runId);
110329
+ } else {
110330
+ groupsToPush = [];
110331
+ }
110332
+ const ignorePatterns = ["node_modules/**", ".git/**", ...deploymentConfig.ignorePatterns || microfoxConfig.ignorePatterns || []];
110333
+ const serverlessRoot = cwd;
110334
+ const doOnePush = async (archiveCwd, group) => {
110335
+ var _a5, _b4, _c2;
110336
+ console.log(source_default.blue(group ? `\u{1F4E6} Bundling group "${group}" as a ZIP archive...` : "\u{1F4E6} Bundling your agent as a ZIP archive..."));
110337
+ const zipPath = await createZipArchive(archiveCwd, ignorePatterns);
110338
+ console.log(source_default.blue(group ? `\u{1F69A} Uploading archive for group "${group}" to Microfox...` : "\u{1F69A} Uploading archive to Microfox..."));
110339
+ const form = new FormData3();
110340
+ form.append("archive", fs5.createReadStream(zipPath), {
110341
+ filename: "archive.zip",
110342
+ contentType: "application/zip"
110343
+ });
110344
+ const publish = microfoxConfig.publish ? { ...microfoxConfig.publish, ...group ? { group } : {} } : group ? { group } : void 0;
110345
+ if (publish) {
110346
+ form.append("publish", JSON.stringify(publish));
110347
+ }
110348
+ const headers = {
110349
+ ...form.getHeaders(),
110350
+ "x-project-id": projectId,
110351
+ ...group ? { "x-deployment-group": group } : {}
110352
+ };
110353
+ const response = await axios_default.post(
110354
+ API_ENDPOINT_MAPPER({ mode: apiMode, version: "v2", port: apiLocalPort }),
110355
+ form,
110356
+ {
110357
+ headers,
110358
+ maxBodyLength: Infinity,
110359
+ maxContentLength: Infinity
110360
+ }
110361
+ );
110362
+ if (response.status >= 200 && response.status < 300) {
110363
+ console.log(source_default.green(group ? `\u2705 Deployment request accepted for group "${group}"!` : "\u2705 Deployment request accepted!"));
110364
+ if ((_a5 = response.data) == null ? void 0 : _a5.deploymentId) {
110365
+ const deploymentId = response.data.deploymentId;
110366
+ console.log(source_default.green(` Deployment ID: ${deploymentId}`));
110367
+ if (group != null && group !== "") {
110368
+ saveDeploymentRecordToRoot(serverlessRoot, deploymentId, group);
110369
+ } else {
110370
+ saveDeploymentRecord(archiveCwd, deploymentId);
110371
+ }
110372
+ } else if ((_b4 = response.data) == null ? void 0 : _b4.runId) {
110373
+ const runId = response.data.runId;
110374
+ console.log(source_default.green(` Run ID: ${runId}`));
110375
+ if (group != null && group !== "") {
110376
+ saveDeploymentRecordToRoot(serverlessRoot, runId, group);
110377
+ } else {
110378
+ saveDeploymentRecord(archiveCwd, runId);
110379
+ }
110380
+ }
110381
+ if ((_c2 = response.data) == null ? void 0 : _c2.message) {
110382
+ console.log(source_default.green(` Message: ${response.data.message}`));
110383
+ }
110384
+ } else {
110385
+ console.error(source_default.red(`\u274C Deployment failed with status: ${response.status}`));
110386
+ console.error(response.data);
110387
+ throw new Error(`Deployment failed: ${response.status}`);
110264
110388
  }
110265
- if ((_c2 = response.data) == null ? void 0 : _c2.message) {
110266
- console.log(source_default.green(` Message: ${response.data.message}`));
110389
+ };
110390
+ if (groupsToPush.length > 0) {
110391
+ for (const group of groupsToPush) {
110392
+ const groupDir = path9.join(cwd, group);
110393
+ await doOnePush(groupDir, group);
110267
110394
  }
110268
110395
  } else {
110269
- console.error(source_default.red(`\u274C Deployment failed with status: ${response.status}`));
110270
- console.error(response.data);
110271
- process.exit(1);
110396
+ await doOnePush(cwd);
110272
110397
  }
110273
110398
  } else {
110274
110399
  let agentApiKey;
@@ -110312,12 +110437,12 @@ async function pushAction() {
110312
110437
  );
110313
110438
  if (response.status >= 200 && response.status < 300) {
110314
110439
  console.log(source_default.green("\u2705 Deployment successful!"));
110315
- if ((_d2 = response.data) == null ? void 0 : _d2.runId) {
110440
+ if ((_a4 = response.data) == null ? void 0 : _a4.runId) {
110316
110441
  const runId = response.data.runId;
110317
110442
  console.log(source_default.green(` Run ID: ${runId}`));
110318
110443
  saveDeploymentRecord(cwd, runId);
110319
110444
  }
110320
- if ((_e2 = response.data) == null ? void 0 : _e2.message) {
110445
+ if ((_b3 = response.data) == null ? void 0 : _b3.message) {
110321
110446
  console.log(source_default.green(` Message: ${response.data.message}`));
110322
110447
  }
110323
110448
  } else {
@@ -110337,9 +110462,9 @@ async function pushAction() {
110337
110462
  process.exit(1);
110338
110463
  }
110339
110464
  }
110340
- var pushCommand = new Command("push").description("Deploy your agent to the Microfox platform").action(async () => {
110465
+ var pushCommand = new Command("push").description("Deploy your agent to the Microfox platform").argument("[groupname]", "Deploy only this group (when using per-group layout, e.g. core, default, workflows)").option("--skip-group <groups>", 'Comma-separated list of groups to skip (e.g. "core,workflows")').action(async (groupname, options = {}) => {
110341
110466
  try {
110342
- await pushAction();
110467
+ await pushAction(groupname, options.skipGroup);
110343
110468
  } catch (error2) {
110344
110469
  console.error(source_default.red("\u274C Error:"), error2 instanceof Error ? error2.message : String(error2));
110345
110470
  process.exit(1);
@@ -110419,7 +110544,7 @@ async function fetchV2Deployment(deploymentId, cfg) {
110419
110544
  return axios_default.get(url2, { headers: { "x-project-id": projectId } });
110420
110545
  }
110421
110546
  async function statusAction(idArg, options) {
110422
- var _a4;
110547
+ var _a4, _b3;
110423
110548
  let cwd = process.cwd();
110424
110549
  const serverlessDir = findServerlessWorkersDir(cwd);
110425
110550
  if (serverlessDir) {
@@ -110430,22 +110555,30 @@ async function statusAction(idArg, options) {
110430
110555
  const apiVersion = deploymentConfig.apiVersion || cfg.apiVersion || cfg.API_VERSION;
110431
110556
  const isV2 = ((_a4 = apiVersion == null ? void 0 : apiVersion.toLowerCase) == null ? void 0 : _a4.call(apiVersion)) === "v2";
110432
110557
  let idsToProcess = [];
110558
+ let latestRecords = null;
110433
110559
  if (idArg === "latest" || !idArg) {
110434
110560
  const n = (options == null ? void 0 : options.number) || 1;
110435
- const latestIds = getLatestDeploymentId(cwd, n);
110436
- if (latestIds.length === 0) {
110561
+ if (serverlessDir) {
110562
+ const records = getDeploymentRecordsFromRoot(serverlessDir);
110563
+ const sorted = [...records].sort((a, b) => b.timestamp - a.timestamp);
110564
+ latestRecords = sorted.slice(0, n);
110565
+ idsToProcess = latestRecords.map((r) => r.deploymentId);
110566
+ } else {
110567
+ idsToProcess = getLatestDeploymentId(cwd, n);
110568
+ }
110569
+ if (idsToProcess.length === 0) {
110437
110570
  console.error(source_default.red("\u274C Error: No deployment records found. Run `npx microfox push` first."));
110438
110571
  process.exit(1);
110439
110572
  }
110440
- idsToProcess = latestIds;
110441
110573
  } else {
110442
110574
  idsToProcess = [idArg];
110443
110575
  }
110444
110576
  if (idsToProcess.length > 1) {
110445
110577
  for (let i = 0; i < idsToProcess.length; i++) {
110446
110578
  const id = idsToProcess[i];
110579
+ const groupLabel = ((_b3 = latestRecords == null ? void 0 : latestRecords[i]) == null ? void 0 : _b3.group) ? ` (group: ${latestRecords[i].group})` : "";
110447
110580
  console.log(source_default.cyan(`
110448
- [${i + 1}/${idsToProcess.length}] Deployment: ${id}`));
110581
+ [${i + 1}/${idsToProcess.length}] Deployment: ${id}${groupLabel}`));
110449
110582
  console.log(source_default.gray("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
110450
110583
  await processSingleStatus(id, cwd, cfg, isV2);
110451
110584
  if (i < idsToProcess.length - 1) {
@@ -110483,6 +110616,9 @@ async function processSingleStatus(idArg, cwd, cfg, isV2) {
110483
110616
  console.log(source_default.gray("----------------------------------------"));
110484
110617
  console.log(`${source_default.bold("Deployment ID:")} ${dep._id || deploymentId}`);
110485
110618
  console.log(`${source_default.bold("Project ID:")} ${dep.projectId || "N/A"}`);
110619
+ if (dep.group != null && dep.group !== "") {
110620
+ console.log(`${source_default.bold("Group:")} ${dep.group}`);
110621
+ }
110486
110622
  console.log(`${source_default.bold("Status:")} ${source_default.green(dep.status)}`);
110487
110623
  if ((_a4 = dep.error) == null ? void 0 : _a4.message) console.log(`${source_default.bold("Error:")} ${dep.error.message}`);
110488
110624
  const start = ((_c2 = (_b3 = dep.metrics) == null ? void 0 : _b3.timing) == null ? void 0 : _c2.startTime) ? new Date(dep.metrics.timing.startTime).toLocaleString() : "N/A";
@@ -110515,7 +110651,7 @@ async function logsAction(idArg, options = {}) {
110515
110651
  let idsToProcess = [];
110516
110652
  if (idArg === "latest" || !idArg) {
110517
110653
  const n = (options == null ? void 0 : options.number) || 1;
110518
- const latestIds = getLatestDeploymentId(cwd, n);
110654
+ const latestIds = serverlessDir ? getLatestDeploymentIdFromRoot(serverlessDir, n) : getLatestDeploymentId(cwd, n);
110519
110655
  if (latestIds.length === 0) {
110520
110656
  console.error(source_default.red("\u274C Error: No deployment records found. Run `npx microfox push` first."));
110521
110657
  process.exit(1);
@@ -111507,7 +111643,7 @@ var kickstartCommand = new Command("kickstart").description("Kickstart a new Mic
111507
111643
  });
111508
111644
 
111509
111645
  // package.json
111510
- var version = "1.1.7";
111646
+ var version = "1.2.0";
111511
111647
 
111512
111648
  // src/commands/track.ts
111513
111649
  var track = new Command("track").description("Run tracker scripts locally.").option("--file <path>", "Run a single tracker file instead of all.").action(async (options) => {