@integrity-labs/agt-cli 0.27.158 → 0.27.160

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.
@@ -2,15 +2,19 @@ import {
2
2
  CHANNEL_REGISTRY,
3
3
  DEFAULT_MODELS,
4
4
  OAUTH_PROVIDERS,
5
+ coerceEnvValue,
5
6
  formatForOpenClawCli,
6
7
  getChannel,
8
+ getFlagDefinition,
7
9
  getFramework,
8
10
  isParseError,
11
+ listFlagDefinitions,
12
+ normalizeFlagValue,
9
13
  parseDeliveryTarget,
10
14
  registerFramework,
11
15
  resolveAvatarEnvUrl,
12
16
  wrapScheduledTaskPrompt
13
- } from "./chunk-5E5B4T7K.js";
17
+ } from "./chunk-BC26YO7P.js";
14
18
 
15
19
  // ../../packages/core/dist/integrations/registry.js
16
20
  var INTEGRATION_REGISTRY = [
@@ -5642,14 +5646,14 @@ ${sections}`
5642
5646
  const augDir = join4(homeDir, ".augmented");
5643
5647
  const agents = /* @__PURE__ */ new Set();
5644
5648
  try {
5645
- const { readdirSync: readdirSync2, statSync } = await import("fs");
5649
+ const { readdirSync: readdirSync2, statSync: statSync2 } = await import("fs");
5646
5650
  const entries = readdirSync2(augDir);
5647
5651
  for (const entry of entries) {
5648
5652
  if (entry.startsWith("_") || entry.startsWith("."))
5649
5653
  continue;
5650
5654
  const agentRoot = join4(augDir, entry);
5651
5655
  try {
5652
- if (!statSync(agentRoot).isDirectory())
5656
+ if (!statSync2(agentRoot).isDirectory())
5653
5657
  continue;
5654
5658
  } catch {
5655
5659
  continue;
@@ -7342,6 +7346,200 @@ async function getHostId() {
7342
7346
  return hostId;
7343
7347
  }
7344
7348
 
7349
+ // src/lib/atomic-write.ts
7350
+ import { closeSync, fsyncSync, openSync, writeSync, renameSync as renameSync4, mkdirSync as mkdirSync6 } from "fs";
7351
+ import { dirname as dirname5 } from "path";
7352
+ function atomicWriteFileSync(path, data) {
7353
+ const dirPath = dirname5(path);
7354
+ const tmpPath = `${path}.tmp.${process.pid}.${Math.random().toString(36).slice(2, 8)}`;
7355
+ try {
7356
+ mkdirSync6(dirPath, { recursive: true });
7357
+ } catch {
7358
+ }
7359
+ const fd = openSync(tmpPath, "w", 420);
7360
+ try {
7361
+ writeSync(fd, data);
7362
+ try {
7363
+ fsyncSync(fd);
7364
+ } catch {
7365
+ }
7366
+ } finally {
7367
+ closeSync(fd);
7368
+ }
7369
+ renameSync4(tmpPath, path);
7370
+ try {
7371
+ const dirFd = openSync(dirPath, "r");
7372
+ try {
7373
+ fsyncSync(dirFd);
7374
+ } finally {
7375
+ closeSync(dirFd);
7376
+ }
7377
+ } catch {
7378
+ }
7379
+ }
7380
+
7381
+ // src/lib/feature-flags-host.ts
7382
+ import { existsSync as existsSync7, readFileSync as readFileSync7, statSync } from "fs";
7383
+ import { join as join7 } from "path";
7384
+ function defaultFlagsCachePath(configDir) {
7385
+ return join7(configDir, "flags-cache.json");
7386
+ }
7387
+ function readFlagsCache(path) {
7388
+ try {
7389
+ if (!existsSync7(path)) return null;
7390
+ const parsed = JSON.parse(readFileSync7(path, "utf8"));
7391
+ if (!parsed || typeof parsed !== "object") return null;
7392
+ const obj = parsed;
7393
+ const flags = obj["flags"];
7394
+ if (!flags || typeof flags !== "object") return null;
7395
+ return {
7396
+ schema_version: typeof obj["schema_version"] === "string" ? obj["schema_version"] : "",
7397
+ updated_at: typeof obj["updated_at"] === "string" ? obj["updated_at"] : "",
7398
+ flags: { ...flags }
7399
+ };
7400
+ } catch {
7401
+ return null;
7402
+ }
7403
+ }
7404
+ function writeFlagsCache(path, file) {
7405
+ atomicWriteFileSync(path, `${JSON.stringify(file, null, 2)}
7406
+ `);
7407
+ }
7408
+ function flagsCacheAgeSeconds(cache, path, now = /* @__PURE__ */ new Date()) {
7409
+ const fromRecorded = Date.parse(cache.updated_at);
7410
+ if (!Number.isNaN(fromRecorded)) {
7411
+ return Math.max(0, (now.getTime() - fromRecorded) / 1e3);
7412
+ }
7413
+ try {
7414
+ return Math.max(0, (now.getTime() - statSync(path).mtimeMs) / 1e3);
7415
+ } catch {
7416
+ return null;
7417
+ }
7418
+ }
7419
+ function resolveFlagFromLayers(definition, heartbeatFlags, env) {
7420
+ const envValue = definition.envVar ? coerceEnvValue(definition, env[definition.envVar]) : void 0;
7421
+ const hbValue = heartbeatFlags ? normalizeFlagValue(definition, heartbeatFlags[definition.key]) : void 0;
7422
+ if (envValue !== void 0) {
7423
+ return {
7424
+ key: definition.key,
7425
+ value: envValue,
7426
+ source: "env",
7427
+ envVar: definition.envVar,
7428
+ envMasksHeartbeat: hbValue !== void 0 && hbValue !== envValue
7429
+ };
7430
+ }
7431
+ if (hbValue !== void 0) {
7432
+ return { key: definition.key, value: hbValue, source: "heartbeat-cache" };
7433
+ }
7434
+ return { key: definition.key, value: definition.defaultValue, source: "default" };
7435
+ }
7436
+ function resolveAllFlags(heartbeatFlags, env = process.env) {
7437
+ return listFlagDefinitions().map(
7438
+ (definition) => resolveFlagFromLayers(definition, heartbeatFlags, env)
7439
+ );
7440
+ }
7441
+ var HostFlagStore = class {
7442
+ heartbeatFlags = {};
7443
+ cachePath;
7444
+ log;
7445
+ env;
7446
+ initialised = false;
7447
+ constructor(opts) {
7448
+ this.cachePath = opts.cachePath;
7449
+ this.log = opts.log ?? (() => {
7450
+ });
7451
+ this.env = opts.env ?? process.env;
7452
+ }
7453
+ /**
7454
+ * Boot-time hydrate from the last-known-good cache. Cached values are used
7455
+ * only until the first successful heartbeat; the cache age is logged so a
7456
+ * stale `flags-cache.json` is visible (ADR-0022 §5 restart-with-stale-cache).
7457
+ */
7458
+ init(now = /* @__PURE__ */ new Date()) {
7459
+ if (this.initialised) return;
7460
+ this.initialised = true;
7461
+ const cached = readFlagsCache(this.cachePath);
7462
+ if (!cached) {
7463
+ this.log("[flags] no last-known-good cache on disk; using compiled defaults until first heartbeat");
7464
+ return;
7465
+ }
7466
+ this.heartbeatFlags = { ...cached.flags };
7467
+ const ageSeconds = flagsCacheAgeSeconds(cached, this.cachePath, now);
7468
+ const age = ageSeconds === null ? "unknown" : `${Math.round(ageSeconds)}s`;
7469
+ const schema = cached.schema_version || "unknown";
7470
+ this.log(
7471
+ `[flags] loaded last-known-good cache (age: ${age}, schema: ${schema}); using cached values until first heartbeat`
7472
+ );
7473
+ }
7474
+ /**
7475
+ * Merge a heartbeat flag map: log per-flag transitions and env-masking warns,
7476
+ * replace the in-memory map (full map; unknown keys kept), and persist it.
7477
+ * A missing/non-object map is a no-op so an older API that omits the field
7478
+ * doesn't blow away a good cache.
7479
+ */
7480
+ applyHeartbeat(map, schemaVersion) {
7481
+ if (!map || typeof map !== "object") return;
7482
+ const previous = this.heartbeatFlags;
7483
+ for (const definition of listFlagDefinitions()) {
7484
+ const before = normalizeFlagValue(definition, previous[definition.key]);
7485
+ const after = normalizeFlagValue(definition, map[definition.key]);
7486
+ if (after !== void 0 && after !== before) {
7487
+ this.log(
7488
+ `[flags] ${definition.key}: ${before ?? "(default)"} -> ${after} (source: heartbeat)`
7489
+ );
7490
+ }
7491
+ if (definition.envVar) {
7492
+ const envValue = coerceEnvValue(definition, this.env[definition.envVar]);
7493
+ if (envValue !== void 0 && after !== void 0 && envValue !== after) {
7494
+ this.log(
7495
+ `[flags] WARN env override ${definition.envVar}=${envValue} is masking heartbeat value ${after} for '${definition.key}' (env wins until unset)`
7496
+ );
7497
+ }
7498
+ }
7499
+ }
7500
+ this.heartbeatFlags = { ...map };
7501
+ try {
7502
+ writeFlagsCache(this.cachePath, {
7503
+ schema_version: schemaVersion ?? "",
7504
+ updated_at: (/* @__PURE__ */ new Date()).toISOString(),
7505
+ flags: this.heartbeatFlags
7506
+ });
7507
+ } catch (err) {
7508
+ this.log(`[flags] cache write failed: ${err.message}`);
7509
+ }
7510
+ }
7511
+ /** Resolve one flag, or `undefined` if the key isn't registered. */
7512
+ resolve(key) {
7513
+ const definition = getFlagDefinition(key);
7514
+ if (!definition) return void 0;
7515
+ return resolveFlagFromLayers(definition, this.heartbeatFlags, this.env);
7516
+ }
7517
+ resolveAll() {
7518
+ return resolveAllFlags(this.heartbeatFlags, this.env);
7519
+ }
7520
+ /**
7521
+ * Typed boolean accessor. Falls back to the registry default for the key
7522
+ * (and to `false` for an unknown/non-boolean key) so a caller can read a
7523
+ * gate without null-checking.
7524
+ */
7525
+ getBoolean(key) {
7526
+ const definition = getFlagDefinition(key);
7527
+ const resolved = this.resolve(key);
7528
+ if (resolved && typeof resolved.value === "boolean") return resolved.value;
7529
+ return definition?.flagType === "boolean" ? definition.defaultValue : false;
7530
+ }
7531
+ /**
7532
+ * Typed string accessor for enum flags. Falls back to the registry default
7533
+ * (and to `''` for an unknown/non-enum key).
7534
+ */
7535
+ getString(key) {
7536
+ const definition = getFlagDefinition(key);
7537
+ const resolved = this.resolve(key);
7538
+ if (resolved && typeof resolved.value === "string") return resolved.value;
7539
+ return definition?.flagType === "enum" ? definition.defaultValue : "";
7540
+ }
7541
+ };
7542
+
7345
7543
  // ../../packages/core/dist/provisioning/provisioner.js
7346
7544
  import { createHash } from "crypto";
7347
7545
  function sha256(content) {
@@ -7363,26 +7561,26 @@ function provision(input, frameworkId = "openclaw") {
7363
7561
 
7364
7562
  // src/commands/manager.ts
7365
7563
  import chalk3 from "chalk";
7366
- import { existsSync as existsSync8, realpathSync } from "fs";
7367
- import { join as join8 } from "path";
7564
+ import { existsSync as existsSync9, realpathSync } from "fs";
7565
+ import { join as join9 } from "path";
7368
7566
  import { homedir as homedir6, userInfo } from "os";
7369
7567
  import { spawn as spawn3 } from "child_process";
7370
7568
 
7371
7569
  // src/lib/watchdog.ts
7372
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync7, unlinkSync as unlinkSync4, existsSync as existsSync7, mkdirSync as mkdirSync6, openSync, closeSync, chmodSync as chmodSync6 } from "fs";
7373
- import { join as join7 } from "path";
7570
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, unlinkSync as unlinkSync4, existsSync as existsSync8, mkdirSync as mkdirSync7, openSync as openSync2, closeSync as closeSync2, chmodSync as chmodSync6 } from "fs";
7571
+ import { join as join8 } from "path";
7374
7572
  import { spawn as spawn2, execFileSync } from "child_process";
7375
- var DEFAULT_CONFIG_DIR = join7(process.env["HOME"] ?? "/tmp", ".augmented");
7573
+ var DEFAULT_CONFIG_DIR = join8(process.env["HOME"] ?? "/tmp", ".augmented");
7376
7574
  function getManagerPaths(configDir) {
7377
7575
  return {
7378
- pidFile: join7(configDir, "manager.pid"),
7379
- stateFile: join7(configDir, "manager-state.json"),
7380
- logFile: join7(configDir, "manager.log")
7576
+ pidFile: join8(configDir, "manager.pid"),
7577
+ stateFile: join8(configDir, "manager-state.json"),
7578
+ logFile: join8(configDir, "manager.log")
7381
7579
  };
7382
7580
  }
7383
7581
  function ensureDir2(configDir) {
7384
- if (!existsSync7(configDir)) {
7385
- mkdirSync6(configDir, { recursive: true });
7582
+ if (!existsSync8(configDir)) {
7583
+ mkdirSync7(configDir, { recursive: true });
7386
7584
  }
7387
7585
  }
7388
7586
  function writePidFile(configDir, pid) {
@@ -7391,7 +7589,7 @@ function writePidFile(configDir, pid) {
7391
7589
  }
7392
7590
  function readPidFile(configDir) {
7393
7591
  try {
7394
- const raw = readFileSync7(getManagerPaths(configDir).pidFile, "utf-8").trim();
7592
+ const raw = readFileSync8(getManagerPaths(configDir).pidFile, "utf-8").trim();
7395
7593
  const pid = parseInt(raw, 10);
7396
7594
  return isNaN(pid) ? null : pid;
7397
7595
  } catch {
@@ -7429,7 +7627,7 @@ function defaultPgrep() {
7429
7627
  }
7430
7628
  function readStateFile(configDir) {
7431
7629
  try {
7432
- const raw = readFileSync7(getManagerPaths(configDir).stateFile, "utf-8");
7630
+ const raw = readFileSync8(getManagerPaths(configDir).stateFile, "utf-8");
7433
7631
  return JSON.parse(raw);
7434
7632
  } catch {
7435
7633
  return null;
@@ -7461,7 +7659,7 @@ function startWatchdog(opts) {
7461
7659
  if (opts.detached) {
7462
7660
  ensureDir2(configDir);
7463
7661
  const { logFile } = getManagerPaths(configDir);
7464
- const logFd = openSync(logFile, "a", 384);
7662
+ const logFd = openSync2(logFile, "a", 384);
7465
7663
  try {
7466
7664
  chmodSync6(logFile, 384);
7467
7665
  } catch {
@@ -7477,7 +7675,7 @@ function startWatchdog(opts) {
7477
7675
  }
7478
7676
  );
7479
7677
  child.unref();
7480
- closeSync(logFd);
7678
+ closeSync2(logFd);
7481
7679
  if (!child.pid) {
7482
7680
  throw new Error("Failed to spawn detached manager process");
7483
7681
  }
@@ -7485,7 +7683,7 @@ function startWatchdog(opts) {
7485
7683
  const deadline = Date.now() + 5e3;
7486
7684
  const sleepBuf = new Int32Array(new SharedArrayBuffer(4));
7487
7685
  while (Date.now() < deadline) {
7488
- if (existsSync7(pidFile)) {
7686
+ if (existsSync8(pidFile)) {
7489
7687
  return { pid: child.pid };
7490
7688
  }
7491
7689
  if (child.exitCode !== null) {
@@ -7613,7 +7811,7 @@ function managerStartCommand(opts) {
7613
7811
  process.exitCode = 1;
7614
7812
  return;
7615
7813
  }
7616
- const configDir = opts.configDir ?? join8(homedir6(), ".augmented");
7814
+ const configDir = opts.configDir ?? join9(homedir6(), ".augmented");
7617
7815
  if (opts.supervise) {
7618
7816
  if (json) {
7619
7817
  jsonOutput({ ok: false, error: "--supervise is not supported with --json" });
@@ -7709,7 +7907,7 @@ function runSupervisorLoop(intervalSec, configDir) {
7709
7907
  }
7710
7908
  async function managerStopCommand(opts = {}) {
7711
7909
  const json = isJsonMode();
7712
- const configDir = opts.configDir ?? join8(homedir6(), ".augmented");
7910
+ const configDir = opts.configDir ?? join9(homedir6(), ".augmented");
7713
7911
  try {
7714
7912
  const result = await stopWatchdog(configDir);
7715
7913
  if (!result.stopped && !result.pid) {
@@ -7737,7 +7935,7 @@ async function managerStopCommand(opts = {}) {
7737
7935
  }
7738
7936
  function managerStatusCommand(opts = {}) {
7739
7937
  const json = isJsonMode();
7740
- const configDir = opts.configDir ?? join8(homedir6(), ".augmented");
7938
+ const configDir = opts.configDir ?? join9(homedir6(), ".augmented");
7741
7939
  const status = getManagerStatus(configDir);
7742
7940
  if (!status) {
7743
7941
  if (json) {
@@ -7809,7 +8007,7 @@ function resolveStableAgtBin(rawPath) {
7809
8007
  if (!prefix || !formula) return rawPath;
7810
8008
  const candidates = [`${prefix}/bin/${formula}`, `${prefix}/bin/agt`];
7811
8009
  for (const candidate of candidates) {
7812
- if (!existsSync8(candidate)) continue;
8010
+ if (!existsSync9(candidate)) continue;
7813
8011
  try {
7814
8012
  realpathSync(candidate);
7815
8013
  return candidate;
@@ -7829,7 +8027,7 @@ async function managerInstallCommand(opts = {}) {
7829
8027
  process.exitCode = 1;
7830
8028
  return;
7831
8029
  }
7832
- const configDir = opts.configDir ?? join8(homedir6(), ".augmented");
8030
+ const configDir = opts.configDir ?? join9(homedir6(), ".augmented");
7833
8031
  const rawAgtBin = process.argv[1];
7834
8032
  if (!rawAgtBin) {
7835
8033
  const msg = "Could not resolve the agt binary path from argv. Re-run via the installed `agt` command.";
@@ -7842,7 +8040,7 @@ async function managerInstallCommand(opts = {}) {
7842
8040
  if (process.platform === "darwin") {
7843
8041
  const home = homedir6();
7844
8042
  const protectedRoots = ["Documents", "Downloads", "Desktop", "Movies", "Music", "Pictures"];
7845
- const offending = protectedRoots.map((r) => join8(home, r)).find((p) => agtBin === p || agtBin.startsWith(`${p}/`));
8043
+ const offending = protectedRoots.map((r) => join9(home, r)).find((p) => agtBin === p || agtBin.startsWith(`${p}/`));
7846
8044
  if (offending) {
7847
8045
  const msg = `agt binary at ${agtBin} sits inside a macOS TCC-protected folder (${offending}). launchd-spawned processes cannot read files there and the manager would EPERM on startup. Either install agt globally (\`npm install -g @integrity-labs/agt-cli\`) or copy the dist outside protected folders before running this command.`;
7848
8046
  if (json) jsonOutput({ ok: false, error: msg });
@@ -7910,7 +8108,7 @@ async function managerInstallSystemUnitCommand(opts = {}) {
7910
8108
  return;
7911
8109
  }
7912
8110
  const user = opts.user ?? "root";
7913
- const configDir = opts.configDir ?? (user === "root" ? "/root/.augmented" : join8("/home", user, ".augmented"));
8111
+ const configDir = opts.configDir ?? (user === "root" ? "/root/.augmented" : join9("/home", user, ".augmented"));
7914
8112
  const rawAgtBin = process.argv[1];
7915
8113
  if (!rawAgtBin) {
7916
8114
  const msg = "Could not resolve the agt binary path from argv. Re-run via the installed `agt` command.";
@@ -8005,6 +8203,13 @@ export {
8005
8203
  warn,
8006
8204
  info,
8007
8205
  table,
8206
+ atomicWriteFileSync,
8207
+ defaultFlagsCachePath,
8208
+ readFlagsCache,
8209
+ flagsCacheAgeSeconds,
8210
+ resolveFlagFromLayers,
8211
+ resolveAllFlags,
8212
+ HostFlagStore,
8008
8213
  provision,
8009
8214
  getManagerPaths,
8010
8215
  startWatchdog,
@@ -8017,4 +8222,4 @@ export {
8017
8222
  managerInstallSystemUnitCommand,
8018
8223
  managerUninstallSystemUnitCommand
8019
8224
  };
8020
- //# sourceMappingURL=chunk-ELEMDMTQ.js.map
8225
+ //# sourceMappingURL=chunk-O24XVAYZ.js.map