@integrity-labs/agt-cli 0.27.134 → 0.27.136

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.
@@ -9,7 +9,65 @@ import {
9
9
  parseDeliveryTarget,
10
10
  registerFramework,
11
11
  wrapScheduledTaskPrompt
12
- } from "./chunk-4I2QOVP5.js";
12
+ } from "./chunk-HDWKI7W3.js";
13
+
14
+ // ../../packages/core/dist/provisioning/provisioner.js
15
+ import { createHash } from "crypto";
16
+ function sha256(content) {
17
+ return createHash("sha256").update(content, "utf8").digest("hex");
18
+ }
19
+ function provision(input, frameworkId = "openclaw") {
20
+ const adapter = getFramework(frameworkId);
21
+ const artifacts = adapter.buildArtifacts(input);
22
+ const charterHash = sha256(input.charterContent);
23
+ const toolsHash = sha256(input.toolsContent);
24
+ const teamDir = `.augmented/${input.agent.code_name}`;
25
+ return {
26
+ teamDir,
27
+ artifacts,
28
+ charterHash,
29
+ toolsHash
30
+ };
31
+ }
32
+
33
+ // ../../packages/core/dist/provisioning/hook-env.js
34
+ function augmentedHookPath(currentPath) {
35
+ const extras = [
36
+ "/home/linuxbrew/.linuxbrew/bin",
37
+ "/opt/homebrew/bin",
38
+ "/usr/local/bin",
39
+ "/usr/bin",
40
+ "/bin"
41
+ ];
42
+ const seen = /* @__PURE__ */ new Set();
43
+ const parts = [];
44
+ const push = (p) => {
45
+ if (!p || seen.has(p))
46
+ return;
47
+ seen.add(p);
48
+ parts.push(p);
49
+ };
50
+ for (const p of (currentPath ?? "").split(":"))
51
+ push(p);
52
+ for (const p of extras)
53
+ push(p);
54
+ return parts.join(":");
55
+ }
56
+ function extractCommandNotFound(stderr) {
57
+ if (!stderr)
58
+ return null;
59
+ const SAFE_CMD = /^[A-Za-z][A-Za-z0-9._-]{0,63}$/;
60
+ for (const line of stderr.split(/\r?\n/)) {
61
+ const m = line.match(/^(?:bash|sh): (?:line \d+: )?([^:\s]+): command not found$/);
62
+ if (m?.[1]) {
63
+ const rawCmd = m[1].trim();
64
+ const cmd = rawCmd.split("/").pop() ?? rawCmd;
65
+ if (SAFE_CMD.test(cmd))
66
+ return cmd;
67
+ }
68
+ }
69
+ return null;
70
+ }
13
71
 
14
72
  // ../../packages/core/dist/integrations/registry.js
15
73
  var INTEGRATION_REGISTRY = [
@@ -421,52 +479,370 @@ function getIntegration(id) {
421
479
  return integrationMap.get(id);
422
480
  }
423
481
 
424
- // ../../packages/core/dist/provisioning/hook-env.js
425
- function augmentedHookPath(currentPath) {
426
- const extras = [
427
- "/home/linuxbrew/.linuxbrew/bin",
428
- "/opt/homebrew/bin",
429
- "/usr/local/bin",
430
- "/usr/bin",
431
- "/bin"
432
- ];
433
- const seen = /* @__PURE__ */ new Set();
434
- const parts = [];
435
- const push = (p) => {
436
- if (!p || seen.has(p))
437
- return;
438
- seen.add(p);
439
- parts.push(p);
440
- };
441
- for (const p of (currentPath ?? "").split(":"))
442
- push(p);
443
- for (const p of extras)
444
- push(p);
445
- return parts.join(":");
482
+ // ../../packages/core/dist/provisioning/env-integrations-file.js
483
+ function shellQuote(value) {
484
+ return `'${value.replace(/'/g, `'\\''`)}'`;
446
485
  }
447
- function extractCommandNotFound(stderr) {
448
- if (!stderr)
449
- return null;
450
- const SAFE_CMD = /^[A-Za-z][A-Za-z0-9._-]{0,63}$/;
451
- for (const line of stderr.split(/\r?\n/)) {
452
- const m = line.match(/^(?:bash|sh): (?:line \d+: )?([^:\s]+): command not found$/);
453
- if (m?.[1]) {
454
- const rawCmd = m[1].trim();
455
- const cmd = rawCmd.split("/").pop() ?? rawCmd;
456
- if (SAFE_CMD.test(cmd))
457
- return cmd;
486
+ var CHANNEL_SECRET_ENV_KEYS = [
487
+ "SLACK_BOT_TOKEN",
488
+ "SLACK_APP_TOKEN",
489
+ "TELEGRAM_BOT_TOKEN",
490
+ "MSTEAMS_CLIENT_SECRET"
491
+ ];
492
+ var MCP_SERVER_SECRET_ENV_KEYS = [
493
+ "COMPOSIO_API_KEY",
494
+ "PIPEDREAM_CLIENT_SECRET"
495
+ ];
496
+ var PRESERVED_ENV_KEYS = [
497
+ ...CHANNEL_SECRET_ENV_KEYS,
498
+ ...MCP_SERVER_SECRET_ENV_KEYS
499
+ ];
500
+ var HEADER = "# Augmented integrations \u2014 auto-generated, do not edit";
501
+ function parseEnvFileEntries(content) {
502
+ const out = /* @__PURE__ */ new Map();
503
+ for (const line of content.split("\n")) {
504
+ if (!line || line.startsWith("#") || !line.includes("="))
505
+ continue;
506
+ const eqIdx = line.indexOf("=");
507
+ out.set(line.slice(0, eqIdx), line.slice(eqIdx + 1));
508
+ }
509
+ return out;
510
+ }
511
+ function renderEnvIntegrations(entries) {
512
+ const lines = [HEADER];
513
+ for (const [key, rendered] of entries)
514
+ lines.push(`${key}=${rendered}`);
515
+ return lines.join("\n") + "\n";
516
+ }
517
+ function mergeEnvIntegrationsContent(existing, args) {
518
+ const current = existing === null ? /* @__PURE__ */ new Map() : parseEnvFileEntries(existing);
519
+ let next;
520
+ if (args.mode === "upsert") {
521
+ next = new Map(current);
522
+ for (const [key, raw] of Object.entries(args.updates)) {
523
+ if (raw === null)
524
+ next.delete(key);
525
+ else
526
+ next.set(key, shellQuote(raw));
527
+ }
528
+ } else {
529
+ next = /* @__PURE__ */ new Map();
530
+ for (const [key, raw] of Object.entries(args.updates)) {
531
+ if (raw !== null)
532
+ next.set(key, shellQuote(raw));
533
+ }
534
+ const preserve = args.preserveKeys ?? PRESERVED_ENV_KEYS;
535
+ for (const key of preserve) {
536
+ if (key in args.updates)
537
+ continue;
538
+ if (!next.has(key) && current.has(key)) {
539
+ next.set(key, current.get(key));
540
+ }
541
+ }
542
+ }
543
+ return renderEnvIntegrations(next);
544
+ }
545
+
546
+ // ../../packages/core/dist/provisioning/mcp-config-guards.js
547
+ import { chmodSync, existsSync, readFileSync, renameSync, writeFileSync, unlinkSync } from "fs";
548
+
549
+ // ../../packages/core/dist/provisioning/mcp-secret-lint.js
550
+ var LITERAL_SECRET_PATTERNS = [
551
+ // Slack bot token — `xoxb-<workspace>-<...>`
552
+ { name: "slack_bot_token", re: /^xoxb-/ },
553
+ // Slack app-level token (Socket Mode) — `xapp-<...>`
554
+ { name: "slack_app_token", re: /^xapp-/ },
555
+ // AGT host API key — `tlk_<...>` (see claudecode-plugin-augmented README).
556
+ { name: "agt_host_api_key", re: /^tlk_/ },
557
+ // Composio / generic api-key prefix — `ak_<...>`
558
+ { name: "composio_api_key", re: /^ak_/ },
559
+ // Telegram bot token — `<bot id>:AA<...>` (BotFather format). ENG-5901
560
+ // PR 4: the original `\d{10}:AAE` (from the issue AC) was too narrow —
561
+ // live tokens on agt-aws-1 carry `AA` + a varying third character
562
+ // (don/scout/stirling all had AA-not-E tokens the lint and migration
563
+ // missed). Bot ids are 8–12 digits; the token part always starts `AA`.
564
+ { name: "telegram_bot_token", re: /^\d{8,12}:AA[A-Za-z0-9_-]/ },
565
+ // ENG-5901 extension beyond the original AC's five patterns: a literal
566
+ // JWT (`eyJ...`) is the shape of a leaked AGT_API_KEY, which the
567
+ // value-prefix patterns above would otherwise miss. Header values often
568
+ // carry it behind `Bearer ` (or a copy-pasted `Authorization: Bearer `),
569
+ // so those prefixes are optionally consumed (CodeRabbit #1731).
570
+ // Templates (`Bearer ${AGT_API_KEY}`) and concrete non-secret values
571
+ // (UUIDs, hosts) never put `eyJ` after the prefix, so this stays
572
+ // false-positive-safe inside .mcp.json.
573
+ { name: "jwt_agt_api_key", re: /^(?:authorization:\s*)?(?:bearer\s+)?eyJ[A-Za-z0-9_-]+\./i }
574
+ ];
575
+ function matchLiteralSecret(value) {
576
+ for (const { name, re } of LITERAL_SECRET_PATTERNS) {
577
+ if (re.test(value))
578
+ return name;
579
+ }
580
+ return null;
581
+ }
582
+ function scanRecord(server, record, location, findings) {
583
+ if (!record)
584
+ return;
585
+ for (const [field, value] of Object.entries(record)) {
586
+ if (typeof value !== "string")
587
+ continue;
588
+ const pattern = matchLiteralSecret(value);
589
+ if (pattern)
590
+ findings.push({ server, field, location, pattern });
591
+ }
592
+ }
593
+ function scanConfigForLiteralSecrets(config) {
594
+ const findings = [];
595
+ if (typeof config !== "object" || config === null)
596
+ return findings;
597
+ const servers = config.mcpServers;
598
+ if (typeof servers !== "object" || servers === null)
599
+ return findings;
600
+ for (const [server, raw] of Object.entries(servers)) {
601
+ if (typeof raw !== "object" || raw === null)
602
+ continue;
603
+ const entry = raw;
604
+ scanRecord(server, entry.env, "env", findings);
605
+ scanRecord(server, entry.headers, "header", findings);
606
+ }
607
+ return findings;
608
+ }
609
+ function formatLiteralSecretRejection(f) {
610
+ return `[mcp-write] [literal-secret-rejected] field=${f.field} server=${f.server} location=${f.location} pattern=${f.pattern}`;
611
+ }
612
+
613
+ // ../../packages/core/dist/provisioning/mcp-config-guards.js
614
+ var MCP_FILE_MODE = 384;
615
+ var lastRejectionFingerprintByPath = /* @__PURE__ */ new Map();
616
+ var REQUIRED_ENV_RULES_BY_SERVER = {
617
+ "cloud-broker": [
618
+ { key: "AGT_HOST", mustBeConcrete: false },
619
+ { key: "AGT_API_KEY", mustBeConcrete: false },
620
+ // ENG-4744: this is the bug shape — writer used to omit this
621
+ // entirely, or render it as a literal `${AGT_AGENT_ID}` instead
622
+ // of the agent's real UUID. The broker has no way to substitute
623
+ // it post-spawn, so a placeholder here = silently broken agent.
624
+ { key: "AGT_AGENT_ID", mustBeConcrete: true }
625
+ ]
626
+ };
627
+ var PLACEHOLDER_RE = /\$\{[^}]+\}/;
628
+ function validateRenderedMcpConfig(config) {
629
+ const errors = [];
630
+ if (typeof config !== "object" || config === null || Array.isArray(config)) {
631
+ return {
632
+ ok: false,
633
+ errors: [
634
+ {
635
+ kind: "invalid_json_shape",
636
+ server: "*",
637
+ message: "config root must be a non-null object"
638
+ }
639
+ ]
640
+ };
641
+ }
642
+ const root = config;
643
+ if (root.mcpServers === void 0) {
644
+ return { ok: true };
645
+ }
646
+ if (typeof root.mcpServers !== "object" || root.mcpServers === null) {
647
+ return {
648
+ ok: false,
649
+ errors: [
650
+ {
651
+ kind: "invalid_json_shape",
652
+ server: "*",
653
+ message: "mcpServers must be an object"
654
+ }
655
+ ]
656
+ };
657
+ }
658
+ if (Array.isArray(root.mcpServers)) {
659
+ return {
660
+ ok: false,
661
+ errors: [
662
+ {
663
+ kind: "invalid_json_shape",
664
+ server: "*",
665
+ message: "mcpServers must be an object"
666
+ }
667
+ ]
668
+ };
669
+ }
670
+ for (const [serverKey, raw] of Object.entries(root.mcpServers)) {
671
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
672
+ errors.push({
673
+ kind: "invalid_json_shape",
674
+ server: serverKey,
675
+ message: `entry must be an object`
676
+ });
677
+ continue;
678
+ }
679
+ const entry = raw;
680
+ const entryRecord = entry;
681
+ if (typeof entryRecord["url"] === "string") {
682
+ const type = entryRecord["type"];
683
+ if (type !== "http" && type !== "sse") {
684
+ errors.push({
685
+ kind: "remote_mcp_missing_type",
686
+ server: serverKey,
687
+ message: `url-based entry must include \`type: "http"\` or \`type: "sse"\` (Claude Code MCP schema requires it)`
688
+ });
689
+ }
690
+ }
691
+ const rules = REQUIRED_ENV_RULES_BY_SERVER[serverKey];
692
+ if (rules) {
693
+ const env = entry.env ?? {};
694
+ for (const rule of rules) {
695
+ const value = env[rule.key];
696
+ if (typeof value !== "string" || value.length === 0) {
697
+ errors.push({
698
+ kind: "missing_required_env",
699
+ server: serverKey,
700
+ message: `missing required env key: ${rule.key}`
701
+ });
702
+ continue;
703
+ }
704
+ if (rule.mustBeConcrete && PLACEHOLDER_RE.test(value)) {
705
+ errors.push({
706
+ kind: "unexpanded_placeholder",
707
+ server: serverKey,
708
+ message: `env.${rule.key} contains an unexpanded \${...} placeholder; expected a concrete value`
709
+ });
710
+ }
711
+ }
712
+ }
713
+ }
714
+ return errors.length === 0 ? { ok: true } : { ok: false, errors };
715
+ }
716
+ function formatValidationErrors(errors) {
717
+ return errors.map((e) => `${e.server}:${e.kind}=${e.message}`).join("; ");
718
+ }
719
+ function safeWriteJsonAtomic(path, content, opts = {}) {
720
+ const keepBackup = opts.keepBackup !== false;
721
+ const rename = opts.renamer ?? renameSync;
722
+ const tmpPath = `${path}.new`;
723
+ const bakPath = `${path}.bak`;
724
+ let movedOriginalToBackup = false;
725
+ try {
726
+ writeFileSync(tmpPath, content);
727
+ if (opts.mode !== void 0) {
728
+ chmodSync(tmpPath, opts.mode);
729
+ }
730
+ } catch (err) {
731
+ try {
732
+ if (existsSync(tmpPath))
733
+ unlinkSync(tmpPath);
734
+ } catch {
735
+ }
736
+ throw err;
737
+ }
738
+ try {
739
+ if (keepBackup && existsSync(path)) {
740
+ rename(path, bakPath);
741
+ movedOriginalToBackup = true;
742
+ }
743
+ rename(tmpPath, path);
744
+ } catch (err) {
745
+ try {
746
+ if (existsSync(tmpPath))
747
+ unlinkSync(tmpPath);
748
+ } catch {
749
+ }
750
+ if (movedOriginalToBackup && !existsSync(path) && existsSync(bakPath)) {
751
+ try {
752
+ renameSync(bakPath, path);
753
+ } catch {
754
+ }
755
+ }
756
+ throw err;
757
+ }
758
+ }
759
+ function safeWriteMcpJson(path, config) {
760
+ const validation = validateRenderedMcpConfig(config);
761
+ if (!validation.ok) {
762
+ return { written: false, errors: validation.errors };
763
+ }
764
+ const secretFindings = scanConfigForLiteralSecrets(config);
765
+ if (secretFindings.length > 0) {
766
+ const fingerprint = secretFindings.map((f) => `${f.server}.${f.field}.${f.location}`).sort().join("|");
767
+ if (lastRejectionFingerprintByPath.get(path) !== fingerprint) {
768
+ lastRejectionFingerprintByPath.set(path, fingerprint);
769
+ for (const f of secretFindings) {
770
+ process.stderr.write(`${formatLiteralSecretRejection(f)}
771
+ `);
772
+ }
773
+ }
774
+ return {
775
+ written: false,
776
+ errors: secretFindings.map((f) => ({
777
+ kind: "literal_secret",
778
+ server: f.server,
779
+ message: `literal secret in ${f.location} field '${f.field}' (pattern ${f.pattern}); expected a \${VAR} template`
780
+ }))
781
+ };
782
+ }
783
+ lastRejectionFingerprintByPath.delete(path);
784
+ safeWriteJsonAtomic(path, JSON.stringify(config, null, 2), { mode: MCP_FILE_MODE });
785
+ return { written: true, errors: [] };
786
+ }
787
+ var SECRET_FIELD_NAME_RE = /TOKEN|KEY|SECRET|BEARER|PASSWORD/i;
788
+ function collectSecretFields(config) {
789
+ const out = /* @__PURE__ */ new Map();
790
+ if (typeof config !== "object" || config === null)
791
+ return out;
792
+ const servers = config.mcpServers;
793
+ if (typeof servers !== "object" || servers === null)
794
+ return out;
795
+ for (const [server, raw] of Object.entries(servers)) {
796
+ if (typeof raw !== "object" || raw === null)
797
+ continue;
798
+ const entry = raw;
799
+ for (const [block, location] of [
800
+ [entry.env, "env"],
801
+ [entry.headers, "header"]
802
+ ]) {
803
+ if (!block)
804
+ continue;
805
+ for (const [field, value] of Object.entries(block)) {
806
+ if (typeof value !== "string")
807
+ continue;
808
+ if (!SECRET_FIELD_NAME_RE.test(field))
809
+ continue;
810
+ out.set(`${server}\0${field}`, { location, value });
811
+ }
812
+ }
813
+ }
814
+ return out;
815
+ }
816
+ function mcpMirrorParityErrors(provision2, project) {
817
+ const a = collectSecretFields(provision2);
818
+ const b = collectSecretFields(project);
819
+ const mismatches = [];
820
+ const keys = /* @__PURE__ */ new Set([...a.keys(), ...b.keys()]);
821
+ for (const key of keys) {
822
+ const [server, field] = key.split("\0");
823
+ const pv = a.get(key);
824
+ const pj = b.get(key);
825
+ if (pv && !pj) {
826
+ mismatches.push({ server, field, location: pv.location, reason: "missing-in-project" });
827
+ } else if (!pv && pj) {
828
+ mismatches.push({ server, field, location: pj.location, reason: "missing-in-provision" });
829
+ } else if (pv && pj && pv.value !== pj.value) {
830
+ mismatches.push({ server, field, location: pv.location, reason: "value-diverges" });
458
831
  }
459
832
  }
460
- return null;
833
+ return mismatches;
834
+ }
835
+ function formatMirrorMismatch(m) {
836
+ return `[mcp-mirror] [parity-violation] server=${m.server} field=${m.field} location=${m.location} reason=${m.reason}`;
461
837
  }
462
838
 
463
839
  // ../../packages/core/dist/provisioning/frameworks/openclaw/index.js
464
840
  import { execFile, spawn } from "child_process";
465
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2, unlinkSync as unlinkSync2, chmodSync as chmodSync2, renameSync as renameSync2, symlinkSync } from "fs";
841
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync3, unlinkSync as unlinkSync3, chmodSync as chmodSync3, renameSync as renameSync3, symlinkSync } from "fs";
466
842
  import { join as join2, dirname as dirname2, resolve } from "path";
467
843
 
468
844
  // ../../packages/core/dist/integrations/xurl-config.js
469
- import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "fs";
845
+ import { chmodSync as chmodSync2, existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
470
846
  import { homedir } from "os";
471
847
  import { dirname, join } from "path";
472
848
  import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
@@ -594,10 +970,10 @@ function writeXurlStoreForIntegrations(integrations, filePath = getXurlStorePath
594
970
  if (Object.keys(agtApps).length === 0)
595
971
  return null;
596
972
  let existing = null;
597
- if (existsSync(filePath)) {
973
+ if (existsSync2(filePath)) {
598
974
  let raw;
599
975
  try {
600
- raw = readFileSync(filePath, "utf-8");
976
+ raw = readFileSync2(filePath, "utf-8");
601
977
  } catch {
602
978
  return null;
603
979
  }
@@ -610,18 +986,18 @@ function writeXurlStoreForIntegrations(integrations, filePath = getXurlStorePath
610
986
  const merged = mergeXurlStore(existing, agtApps);
611
987
  mkdirSync(dirname(filePath), { recursive: true });
612
988
  const tmpPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
613
- writeFileSync(tmpPath, serializeXurlStore(merged), { mode: XURL_FILE_MODE });
989
+ writeFileSync2(tmpPath, serializeXurlStore(merged), { mode: XURL_FILE_MODE });
614
990
  try {
615
- renameSync(tmpPath, filePath);
991
+ renameSync2(tmpPath, filePath);
616
992
  } catch (err) {
617
993
  try {
618
- unlinkSync(tmpPath);
994
+ unlinkSync2(tmpPath);
619
995
  } catch {
620
996
  }
621
997
  throw err;
622
998
  }
623
999
  try {
624
- chmodSync(filePath, XURL_FILE_MODE);
1000
+ chmodSync2(filePath, XURL_FILE_MODE);
625
1001
  } catch {
626
1002
  }
627
1003
  return filePath;
@@ -1044,9 +1420,9 @@ function writeIntegrationTokenFile(codeName, integrations) {
1044
1420
  if (Object.keys(tokens).length === 0)
1045
1421
  return;
1046
1422
  mkdirSync2(dir, { recursive: true });
1047
- writeFileSync2(tmpFilePath, JSON.stringify(tokens, null, 2));
1048
- chmodSync2(tmpFilePath, 384);
1049
- renameSync2(tmpFilePath, tokenFilePath);
1423
+ writeFileSync3(tmpFilePath, JSON.stringify(tokens, null, 2));
1424
+ chmodSync3(tmpFilePath, 384);
1425
+ renameSync3(tmpFilePath, tokenFilePath);
1050
1426
  }
1051
1427
  function getOpenClawConfigPath(profile) {
1052
1428
  const homeDir = getHomeDir();
@@ -1060,7 +1436,7 @@ function modifyOpenClawConfig(fn, profile) {
1060
1436
  let originalContent;
1061
1437
  let config;
1062
1438
  try {
1063
- originalContent = readFileSync2(configFile, "utf-8");
1439
+ originalContent = readFileSync3(configFile, "utf-8");
1064
1440
  config = JSON.parse(originalContent);
1065
1441
  } catch {
1066
1442
  return;
@@ -1071,7 +1447,7 @@ function modifyOpenClawConfig(fn, profile) {
1071
1447
  const newContent = JSON.stringify(config, null, 2);
1072
1448
  if (newContent === originalContent)
1073
1449
  return;
1074
- writeFileSync2(configFile, newContent);
1450
+ writeFileSync3(configFile, newContent);
1075
1451
  }
1076
1452
  var AUGMENTED_DIR = join2(getHomeDir(), ".augmented");
1077
1453
  function getGatewayPidPath(codeName) {
@@ -1085,7 +1461,7 @@ function getGatewayPortsPath() {
1085
1461
  }
1086
1462
  function readGatewayPid(codeName) {
1087
1463
  try {
1088
- const raw = readFileSync2(getGatewayPidPath(codeName), "utf-8").trim();
1464
+ const raw = readFileSync3(getGatewayPidPath(codeName), "utf-8").trim();
1089
1465
  const pid = parseInt(raw, 10);
1090
1466
  return isNaN(pid) ? null : pid;
1091
1467
  } catch {
@@ -1133,7 +1509,7 @@ function execPromise(cmd, args) {
1133
1509
  }
1134
1510
  function readGatewayPorts() {
1135
1511
  try {
1136
- return JSON.parse(readFileSync2(getGatewayPortsPath(), "utf-8"));
1512
+ return JSON.parse(readFileSync3(getGatewayPortsPath(), "utf-8"));
1137
1513
  } catch {
1138
1514
  return {};
1139
1515
  }
@@ -1369,7 +1745,7 @@ ${entry.content}`
1369
1745
  const configFile = getOpenClawConfigPath(codeName);
1370
1746
  let raw;
1371
1747
  try {
1372
- raw = readFileSync2(configFile, "utf-8");
1748
+ raw = readFileSync3(configFile, "utf-8");
1373
1749
  } catch {
1374
1750
  return false;
1375
1751
  }
@@ -1438,7 +1814,7 @@ ${entry.content}`
1438
1814
  const authFile = join2(authDir, "auth-profiles.json");
1439
1815
  let existing = {};
1440
1816
  try {
1441
- existing = JSON.parse(readFileSync2(authFile, "utf-8"));
1817
+ existing = JSON.parse(readFileSync3(authFile, "utf-8"));
1442
1818
  } catch {
1443
1819
  }
1444
1820
  const existingProfiles = existing["profiles"] ?? {};
@@ -1460,7 +1836,7 @@ ${entry.content}`
1460
1836
  usageStats: existing["usageStats"] ?? {}
1461
1837
  };
1462
1838
  mkdirSync2(authDir, { recursive: true });
1463
- writeFileSync2(authFile, JSON.stringify(output, null, 2));
1839
+ writeFileSync3(authFile, JSON.stringify(output, null, 2));
1464
1840
  },
1465
1841
  async startGateway(codeName, port) {
1466
1842
  const agentAugDir = join2(AUGMENTED_DIR, codeName);
@@ -1497,7 +1873,7 @@ ${entry.content}`
1497
1873
  }
1498
1874
  }
1499
1875
  }
1500
- writeFileSync2(pidPath, String(gatewayPid));
1876
+ writeFileSync3(pidPath, String(gatewayPid));
1501
1877
  return { pid: gatewayPid, port };
1502
1878
  },
1503
1879
  async stopGateway(codeName) {
@@ -1506,7 +1882,7 @@ ${entry.content}`
1506
1882
  return false;
1507
1883
  if (!isProcessAlive(pid)) {
1508
1884
  try {
1509
- unlinkSync2(getGatewayPidPath(codeName));
1885
+ unlinkSync3(getGatewayPidPath(codeName));
1510
1886
  } catch {
1511
1887
  }
1512
1888
  return false;
@@ -1521,7 +1897,7 @@ ${entry.content}`
1521
1897
  await new Promise((r) => setTimeout(r, 200));
1522
1898
  if (!isProcessAlive(pid)) {
1523
1899
  try {
1524
- unlinkSync2(getGatewayPidPath(codeName));
1900
+ unlinkSync3(getGatewayPidPath(codeName));
1525
1901
  } catch {
1526
1902
  }
1527
1903
  return true;
@@ -1532,7 +1908,7 @@ ${entry.content}`
1532
1908
  } catch {
1533
1909
  }
1534
1910
  try {
1535
- unlinkSync2(getGatewayPidPath(codeName));
1911
+ unlinkSync3(getGatewayPidPath(codeName));
1536
1912
  } catch {
1537
1913
  }
1538
1914
  return true;
@@ -1549,7 +1925,7 @@ ${entry.content}`
1549
1925
  if (portPid) {
1550
1926
  try {
1551
1927
  const pidPath = getGatewayPidPath(codeName);
1552
- writeFileSync2(pidPath, String(portPid));
1928
+ writeFileSync3(pidPath, String(portPid));
1553
1929
  } catch {
1554
1930
  }
1555
1931
  return { running: true, pid: portPid, port };
@@ -1557,7 +1933,7 @@ ${entry.content}`
1557
1933
  }
1558
1934
  if (pid) {
1559
1935
  try {
1560
- unlinkSync2(getGatewayPidPath(codeName));
1936
+ unlinkSync3(getGatewayPidPath(codeName));
1561
1937
  } catch {
1562
1938
  }
1563
1939
  }
@@ -1570,13 +1946,13 @@ ${entry.content}`
1570
1946
  const profileConfigPath = join2(profileDir, "openclaw.json");
1571
1947
  let sharedConfig;
1572
1948
  try {
1573
- sharedConfig = JSON.parse(readFileSync2(sharedConfigPath, "utf-8"));
1949
+ sharedConfig = JSON.parse(readFileSync3(sharedConfigPath, "utf-8"));
1574
1950
  } catch {
1575
1951
  sharedConfig = {};
1576
1952
  }
1577
- if (existsSync2(profileConfigPath)) {
1953
+ if (existsSync3(profileConfigPath)) {
1578
1954
  try {
1579
- const existing = JSON.parse(readFileSync2(profileConfigPath, "utf-8"));
1955
+ const existing = JSON.parse(readFileSync3(profileConfigPath, "utf-8"));
1580
1956
  let changed = false;
1581
1957
  if (!existing["gateway"]) {
1582
1958
  if (sharedConfig["gateway"]) {
@@ -1594,7 +1970,7 @@ ${entry.content}`
1594
1970
  changed = true;
1595
1971
  }
1596
1972
  if (changed) {
1597
- writeFileSync2(profileConfigPath, JSON.stringify(existing, null, 2));
1973
+ writeFileSync3(profileConfigPath, JSON.stringify(existing, null, 2));
1598
1974
  }
1599
1975
  } catch {
1600
1976
  }
@@ -1641,13 +2017,13 @@ ${entry.content}`
1641
2017
  }
1642
2018
  };
1643
2019
  mkdirSync2(profileDir, { recursive: true });
1644
- writeFileSync2(profileConfigPath, JSON.stringify(profileConfig, null, 2));
2020
+ writeFileSync3(profileConfigPath, JSON.stringify(profileConfig, null, 2));
1645
2021
  const agentAuthDir = join2(profileDir, "agents", codeName, "agent");
1646
2022
  const mainAgentDir = join2(profileDir, "agents", "main", "agent");
1647
2023
  try {
1648
2024
  mkdirSync2(agentAuthDir, { recursive: true });
1649
2025
  mkdirSync2(join2(profileDir, "agents", "main"), { recursive: true });
1650
- if (!existsSync2(mainAgentDir)) {
2026
+ if (!existsSync3(mainAgentDir)) {
1651
2027
  symlinkSync(agentAuthDir, mainAgentDir, "dir");
1652
2028
  }
1653
2029
  } catch {
@@ -1661,7 +2037,7 @@ ${entry.content}`
1661
2037
  const authFile = join2(authDir, "auth-profiles.json");
1662
2038
  let existing = {};
1663
2039
  try {
1664
- existing = JSON.parse(readFileSync2(authFile, "utf-8"));
2040
+ existing = JSON.parse(readFileSync3(authFile, "utf-8"));
1665
2041
  } catch {
1666
2042
  }
1667
2043
  const existingProfiles = existing["profiles"] ?? {};
@@ -1673,7 +2049,7 @@ ${entry.content}`
1673
2049
  usageStats: existing["usageStats"] ?? {}
1674
2050
  };
1675
2051
  mkdirSync2(authDir, { recursive: true });
1676
- writeFileSync2(authFile, JSON.stringify(output, null, 2));
2052
+ writeFileSync3(authFile, JSON.stringify(output, null, 2));
1677
2053
  }
1678
2054
  if (integrationConfig.toolAllow.length > 0) {
1679
2055
  modifyOpenClawConfig((config) => {
@@ -1796,7 +2172,7 @@ ${entry.content}`
1796
2172
  for (const file of files) {
1797
2173
  const filePath = join2(skillDir, file.relativePath);
1798
2174
  mkdirSync2(dirname2(filePath), { recursive: true });
1799
- writeFileSync2(filePath, file.content);
2175
+ writeFileSync3(filePath, file.content);
1800
2176
  }
1801
2177
  },
1802
2178
  writeMcpServer(codeName, serverId, config) {
@@ -1892,7 +2268,7 @@ ${entry.content}`
1892
2268
  readGatewayToken(codeName) {
1893
2269
  const homeDir = getHomeDir();
1894
2270
  try {
1895
- const config = JSON.parse(readFileSync2(join2(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
2271
+ const config = JSON.parse(readFileSync3(join2(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
1896
2272
  return config?.gateway?.auth?.token;
1897
2273
  } catch {
1898
2274
  return void 0;
@@ -2033,7 +2409,7 @@ ${entry.content}`
2033
2409
  registerFramework(openclawAdapter);
2034
2410
 
2035
2411
  // ../../packages/core/dist/provisioning/frameworks/nemoclaw/index.js
2036
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, existsSync as existsSync3, chmodSync as chmodSync3 } from "fs";
2412
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3, existsSync as existsSync4, chmodSync as chmodSync4 } from "fs";
2037
2413
  import { join as join3, dirname as dirname3, resolve as resolve2, sep } from "path";
2038
2414
  import { homedir as homedir2 } from "os";
2039
2415
  import { execFile as execFile2 } from "child_process";
@@ -2056,9 +2432,9 @@ function ensureDir(dir) {
2056
2432
  }
2057
2433
  function readDeploymentTarget(codeName) {
2058
2434
  const targetFile = join3(getConfigDir(codeName), "target.json");
2059
- if (!existsSync3(targetFile))
2435
+ if (!existsSync4(targetFile))
2060
2436
  return null;
2061
- return JSON.parse(readFileSync3(targetFile, "utf-8"));
2437
+ return JSON.parse(readFileSync4(targetFile, "utf-8"));
2062
2438
  }
2063
2439
  async function sshExec(target, command, options) {
2064
2440
  const sshArgs = [
@@ -2096,7 +2472,7 @@ async function syncLocalAssetsToRemote(codeName) {
2096
2472
  if (!target)
2097
2473
  return;
2098
2474
  const localAssetsDir = getConfigDir(codeName);
2099
- if (!existsSync3(localAssetsDir))
2475
+ if (!existsSync4(localAssetsDir))
2100
2476
  return;
2101
2477
  const remoteDir = `/opt/augmented/${codeName}`;
2102
2478
  const remoteAssetsDir = `${remoteDir}/assets`;
@@ -2200,7 +2576,7 @@ var nemoClawAdapter = {
2200
2576
  await scpPush(target, blueprintPath, `${remoteDir}/blueprint.json`);
2201
2577
  for (const file of ["CHARTER.md", "TOOLS.md"]) {
2202
2578
  const localPath = join3(teamDir, file);
2203
- if (existsSync3(localPath)) {
2579
+ if (existsSync4(localPath)) {
2204
2580
  await scpPush(target, localPath, `${remoteDir}/${file}`);
2205
2581
  }
2206
2582
  }
@@ -2229,7 +2605,7 @@ var nemoClawAdapter = {
2229
2605
  const configDir = getConfigDir(codeName);
2230
2606
  ensureDir(configDir);
2231
2607
  const authFile = join3(configDir, "auth-profiles.json");
2232
- const existing = existsSync3(authFile) ? JSON.parse(readFileSync3(authFile, "utf-8")) : {};
2608
+ const existing = existsSync4(authFile) ? JSON.parse(readFileSync4(authFile, "utf-8")) : {};
2233
2609
  for (const profile of profiles) {
2234
2610
  const previous = existing[profile.profile_name];
2235
2611
  existing[profile.profile_name] = {
@@ -2240,7 +2616,7 @@ var nemoClawAdapter = {
2240
2616
  ...profile.metadata
2241
2617
  };
2242
2618
  }
2243
- writeFileSync3(authFile, JSON.stringify(existing, null, 2), { mode: 384 });
2619
+ writeFileSync4(authFile, JSON.stringify(existing, null, 2), { mode: 384 });
2244
2620
  syncLocalAssetsToRemote(codeName).catch(() => {
2245
2621
  });
2246
2622
  },
@@ -2262,7 +2638,7 @@ var nemoClawAdapter = {
2262
2638
  }
2263
2639
  const configDir = getConfigDir(codeName);
2264
2640
  ensureDir(configDir);
2265
- writeFileSync3(join3(configDir, "gateway.json"), JSON.stringify({
2641
+ writeFileSync4(join3(configDir, "gateway.json"), JSON.stringify({
2266
2642
  pid: result.pid,
2267
2643
  port: result.port,
2268
2644
  host: target.host,
@@ -2299,7 +2675,7 @@ var nemoClawAdapter = {
2299
2675
  readGatewayToken(codeName) {
2300
2676
  try {
2301
2677
  const gatewayFile = join3(getConfigDir(codeName), "gateway.json");
2302
- const config = JSON.parse(readFileSync3(gatewayFile, "utf-8"));
2678
+ const config = JSON.parse(readFileSync4(gatewayFile, "utf-8"));
2303
2679
  return config?.token;
2304
2680
  } catch {
2305
2681
  return void 0;
@@ -2314,364 +2690,71 @@ var nemoClawAdapter = {
2314
2690
  const creds = decryptIntegrationCredentials(integration.credentials);
2315
2691
  const apiKey = creds.api_key ?? creds.access_token;
2316
2692
  if (apiKey) {
2317
- const envKey = `INTEGRATION_${integration.definition_id.toUpperCase().replace(/-/g, "_")}_KEY`;
2318
- env[envKey] = apiKey;
2319
- }
2320
- }
2321
- writeFileSync3(envFile, JSON.stringify(env, null, 2), { mode: 384 });
2322
- syncLocalAssetsToRemote(codeName).catch(() => {
2323
- });
2324
- },
2325
- installSkillFiles(codeName, skillId, files) {
2326
- if (!/^[a-zA-Z0-9_-]+$/.test(skillId)) {
2327
- throw new Error(`Invalid skill ID: ${skillId}`);
2328
- }
2329
- const skillDir = resolve2(getConfigDir(codeName), "skills", skillId);
2330
- for (const file of files) {
2331
- const filePath = resolve2(skillDir, file.relativePath);
2332
- if (!filePath.startsWith(`${skillDir}${sep}`)) {
2333
- throw new Error(`Invalid skill path: ${file.relativePath}`);
2334
- }
2335
- mkdirSync3(dirname3(filePath), { recursive: true });
2336
- writeFileSync3(filePath, file.content);
2337
- }
2338
- syncLocalAssetsToRemote(codeName).catch(() => {
2339
- });
2340
- },
2341
- writeMcpServer(codeName, serverId, config) {
2342
- const configDir = getConfigDir(codeName);
2343
- ensureDir(configDir);
2344
- const mcpFile = join3(configDir, "mcp-servers.json");
2345
- const existing = existsSync3(mcpFile) ? JSON.parse(readFileSync3(mcpFile, "utf-8")) : {};
2346
- existing[serverId] = config;
2347
- writeFileSync3(mcpFile, JSON.stringify(existing, null, 2), { mode: 384 });
2348
- chmodSync3(mcpFile, 384);
2349
- syncLocalAssetsToRemote(codeName).catch(() => {
2350
- });
2351
- },
2352
- async syncScheduledTasks(codeName, tasks, gatewayPort) {
2353
- const target = readDeploymentTarget(codeName);
2354
- if (!target)
2355
- return;
2356
- const configDir = getConfigDir(codeName);
2357
- ensureDir(configDir);
2358
- const tasksFile = join3(configDir, "scheduled-tasks.json");
2359
- writeFileSync3(tasksFile, JSON.stringify(tasks, null, 2));
2360
- try {
2361
- const remoteDir = `/opt/augmented/${codeName}`;
2362
- await scpPush(target, tasksFile, `${remoteDir}/scheduled-tasks.json`);
2363
- await sshExec(target, `nemoclaw cron sync ${codeName} --config ${remoteDir}/scheduled-tasks.json`);
2364
- } catch {
2365
- }
2366
- }
2367
- };
2368
- function extractAllowedDomains(input) {
2369
- const domains = /* @__PURE__ */ new Set();
2370
- const controlPlaneHost = process.env["AGT_HOST"] ? new URL(process.env["AGT_HOST"]).hostname : "api.agt.localhost";
2371
- domains.add(controlPlaneHost);
2372
- for (const tool of input.toolsFrontmatter.tools) {
2373
- if (tool.network?.allowlist_domains) {
2374
- for (const domain of tool.network.allowlist_domains) {
2375
- domains.add(domain);
2376
- }
2377
- }
2378
- }
2379
- return [...domains];
2380
- }
2381
- registerFramework(nemoClawAdapter);
2382
-
2383
- // ../../packages/core/dist/provisioning/mcp-config-guards.js
2384
- import { chmodSync as chmodSync4, existsSync as existsSync4, readFileSync as readFileSync4, renameSync as renameSync3, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3 } from "fs";
2385
-
2386
- // ../../packages/core/dist/provisioning/mcp-secret-lint.js
2387
- var LITERAL_SECRET_PATTERNS = [
2388
- // Slack bot token — `xoxb-<workspace>-<...>`
2389
- { name: "slack_bot_token", re: /^xoxb-/ },
2390
- // Slack app-level token (Socket Mode) — `xapp-<...>`
2391
- { name: "slack_app_token", re: /^xapp-/ },
2392
- // AGT host API key — `tlk_<...>` (see claudecode-plugin-augmented README).
2393
- { name: "agt_host_api_key", re: /^tlk_/ },
2394
- // Composio / generic api-key prefix — `ak_<...>`
2395
- { name: "composio_api_key", re: /^ak_/ },
2396
- // Telegram bot token — `<bot id>:AA<...>` (BotFather format). ENG-5901
2397
- // PR 4: the original `\d{10}:AAE` (from the issue AC) was too narrow —
2398
- // live tokens on agt-aws-1 carry `AA` + a varying third character
2399
- // (don/scout/stirling all had AA-not-E tokens the lint and migration
2400
- // missed). Bot ids are 8–12 digits; the token part always starts `AA`.
2401
- { name: "telegram_bot_token", re: /^\d{8,12}:AA[A-Za-z0-9_-]/ },
2402
- // ENG-5901 extension beyond the original AC's five patterns: a literal
2403
- // JWT (`eyJ...`) is the shape of a leaked AGT_API_KEY, which the
2404
- // value-prefix patterns above would otherwise miss. Header values often
2405
- // carry it behind `Bearer ` (or a copy-pasted `Authorization: Bearer `),
2406
- // so those prefixes are optionally consumed (CodeRabbit #1731).
2407
- // Templates (`Bearer ${AGT_API_KEY}`) and concrete non-secret values
2408
- // (UUIDs, hosts) never put `eyJ` after the prefix, so this stays
2409
- // false-positive-safe inside .mcp.json.
2410
- { name: "jwt_agt_api_key", re: /^(?:authorization:\s*)?(?:bearer\s+)?eyJ[A-Za-z0-9_-]+\./i }
2411
- ];
2412
- function matchLiteralSecret(value) {
2413
- for (const { name, re } of LITERAL_SECRET_PATTERNS) {
2414
- if (re.test(value))
2415
- return name;
2416
- }
2417
- return null;
2418
- }
2419
- function scanRecord(server, record, location, findings) {
2420
- if (!record)
2421
- return;
2422
- for (const [field, value] of Object.entries(record)) {
2423
- if (typeof value !== "string")
2424
- continue;
2425
- const pattern = matchLiteralSecret(value);
2426
- if (pattern)
2427
- findings.push({ server, field, location, pattern });
2428
- }
2429
- }
2430
- function scanConfigForLiteralSecrets(config) {
2431
- const findings = [];
2432
- if (typeof config !== "object" || config === null)
2433
- return findings;
2434
- const servers = config.mcpServers;
2435
- if (typeof servers !== "object" || servers === null)
2436
- return findings;
2437
- for (const [server, raw] of Object.entries(servers)) {
2438
- if (typeof raw !== "object" || raw === null)
2439
- continue;
2440
- const entry = raw;
2441
- scanRecord(server, entry.env, "env", findings);
2442
- scanRecord(server, entry.headers, "header", findings);
2443
- }
2444
- return findings;
2445
- }
2446
- function formatLiteralSecretRejection(f) {
2447
- return `[mcp-write] [literal-secret-rejected] field=${f.field} server=${f.server} location=${f.location} pattern=${f.pattern}`;
2448
- }
2449
-
2450
- // ../../packages/core/dist/provisioning/mcp-config-guards.js
2451
- var MCP_FILE_MODE = 384;
2452
- var lastRejectionFingerprintByPath = /* @__PURE__ */ new Map();
2453
- var REQUIRED_ENV_RULES_BY_SERVER = {
2454
- "cloud-broker": [
2455
- { key: "AGT_HOST", mustBeConcrete: false },
2456
- { key: "AGT_API_KEY", mustBeConcrete: false },
2457
- // ENG-4744: this is the bug shape — writer used to omit this
2458
- // entirely, or render it as a literal `${AGT_AGENT_ID}` instead
2459
- // of the agent's real UUID. The broker has no way to substitute
2460
- // it post-spawn, so a placeholder here = silently broken agent.
2461
- { key: "AGT_AGENT_ID", mustBeConcrete: true }
2462
- ]
2463
- };
2464
- var PLACEHOLDER_RE = /\$\{[^}]+\}/;
2465
- function validateRenderedMcpConfig(config) {
2466
- const errors = [];
2467
- if (typeof config !== "object" || config === null || Array.isArray(config)) {
2468
- return {
2469
- ok: false,
2470
- errors: [
2471
- {
2472
- kind: "invalid_json_shape",
2473
- server: "*",
2474
- message: "config root must be a non-null object"
2475
- }
2476
- ]
2477
- };
2478
- }
2479
- const root = config;
2480
- if (root.mcpServers === void 0) {
2481
- return { ok: true };
2482
- }
2483
- if (typeof root.mcpServers !== "object" || root.mcpServers === null) {
2484
- return {
2485
- ok: false,
2486
- errors: [
2487
- {
2488
- kind: "invalid_json_shape",
2489
- server: "*",
2490
- message: "mcpServers must be an object"
2491
- }
2492
- ]
2493
- };
2494
- }
2495
- if (Array.isArray(root.mcpServers)) {
2496
- return {
2497
- ok: false,
2498
- errors: [
2499
- {
2500
- kind: "invalid_json_shape",
2501
- server: "*",
2502
- message: "mcpServers must be an object"
2503
- }
2504
- ]
2505
- };
2506
- }
2507
- for (const [serverKey, raw] of Object.entries(root.mcpServers)) {
2508
- if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
2509
- errors.push({
2510
- kind: "invalid_json_shape",
2511
- server: serverKey,
2512
- message: `entry must be an object`
2513
- });
2514
- continue;
2515
- }
2516
- const entry = raw;
2517
- const entryRecord = entry;
2518
- if (typeof entryRecord["url"] === "string") {
2519
- const type = entryRecord["type"];
2520
- if (type !== "http" && type !== "sse") {
2521
- errors.push({
2522
- kind: "remote_mcp_missing_type",
2523
- server: serverKey,
2524
- message: `url-based entry must include \`type: "http"\` or \`type: "sse"\` (Claude Code MCP schema requires it)`
2525
- });
2526
- }
2527
- }
2528
- const rules = REQUIRED_ENV_RULES_BY_SERVER[serverKey];
2529
- if (rules) {
2530
- const env = entry.env ?? {};
2531
- for (const rule of rules) {
2532
- const value = env[rule.key];
2533
- if (typeof value !== "string" || value.length === 0) {
2534
- errors.push({
2535
- kind: "missing_required_env",
2536
- server: serverKey,
2537
- message: `missing required env key: ${rule.key}`
2538
- });
2539
- continue;
2540
- }
2541
- if (rule.mustBeConcrete && PLACEHOLDER_RE.test(value)) {
2542
- errors.push({
2543
- kind: "unexpanded_placeholder",
2544
- server: serverKey,
2545
- message: `env.${rule.key} contains an unexpanded \${...} placeholder; expected a concrete value`
2546
- });
2547
- }
2548
- }
2549
- }
2550
- }
2551
- return errors.length === 0 ? { ok: true } : { ok: false, errors };
2552
- }
2553
- function formatValidationErrors(errors) {
2554
- return errors.map((e) => `${e.server}:${e.kind}=${e.message}`).join("; ");
2555
- }
2556
- function safeWriteJsonAtomic(path, content, opts = {}) {
2557
- const keepBackup = opts.keepBackup !== false;
2558
- const rename = opts.renamer ?? renameSync3;
2559
- const tmpPath = `${path}.new`;
2560
- const bakPath = `${path}.bak`;
2561
- let movedOriginalToBackup = false;
2562
- try {
2563
- writeFileSync4(tmpPath, content);
2564
- if (opts.mode !== void 0) {
2565
- chmodSync4(tmpPath, opts.mode);
2566
- }
2567
- } catch (err) {
2568
- try {
2569
- if (existsSync4(tmpPath))
2570
- unlinkSync3(tmpPath);
2571
- } catch {
2572
- }
2573
- throw err;
2574
- }
2575
- try {
2576
- if (keepBackup && existsSync4(path)) {
2577
- rename(path, bakPath);
2578
- movedOriginalToBackup = true;
2693
+ const envKey = `INTEGRATION_${integration.definition_id.toUpperCase().replace(/-/g, "_")}_KEY`;
2694
+ env[envKey] = apiKey;
2695
+ }
2579
2696
  }
2580
- rename(tmpPath, path);
2581
- } catch (err) {
2582
- try {
2583
- if (existsSync4(tmpPath))
2584
- unlinkSync3(tmpPath);
2585
- } catch {
2697
+ writeFileSync4(envFile, JSON.stringify(env, null, 2), { mode: 384 });
2698
+ syncLocalAssetsToRemote(codeName).catch(() => {
2699
+ });
2700
+ },
2701
+ installSkillFiles(codeName, skillId, files) {
2702
+ if (!/^[a-zA-Z0-9_-]+$/.test(skillId)) {
2703
+ throw new Error(`Invalid skill ID: ${skillId}`);
2586
2704
  }
2587
- if (movedOriginalToBackup && !existsSync4(path) && existsSync4(bakPath)) {
2588
- try {
2589
- renameSync3(bakPath, path);
2590
- } catch {
2705
+ const skillDir = resolve2(getConfigDir(codeName), "skills", skillId);
2706
+ for (const file of files) {
2707
+ const filePath = resolve2(skillDir, file.relativePath);
2708
+ if (!filePath.startsWith(`${skillDir}${sep}`)) {
2709
+ throw new Error(`Invalid skill path: ${file.relativePath}`);
2591
2710
  }
2711
+ mkdirSync3(dirname3(filePath), { recursive: true });
2712
+ writeFileSync4(filePath, file.content);
2592
2713
  }
2593
- throw err;
2594
- }
2595
- }
2596
- function safeWriteMcpJson(path, config) {
2597
- const validation = validateRenderedMcpConfig(config);
2598
- if (!validation.ok) {
2599
- return { written: false, errors: validation.errors };
2600
- }
2601
- const secretFindings = scanConfigForLiteralSecrets(config);
2602
- if (secretFindings.length > 0) {
2603
- const fingerprint = secretFindings.map((f) => `${f.server}.${f.field}.${f.location}`).sort().join("|");
2604
- if (lastRejectionFingerprintByPath.get(path) !== fingerprint) {
2605
- lastRejectionFingerprintByPath.set(path, fingerprint);
2606
- for (const f of secretFindings) {
2607
- process.stderr.write(`${formatLiteralSecretRejection(f)}
2608
- `);
2609
- }
2714
+ syncLocalAssetsToRemote(codeName).catch(() => {
2715
+ });
2716
+ },
2717
+ writeMcpServer(codeName, serverId, config) {
2718
+ const configDir = getConfigDir(codeName);
2719
+ ensureDir(configDir);
2720
+ const mcpFile = join3(configDir, "mcp-servers.json");
2721
+ const existing = existsSync4(mcpFile) ? JSON.parse(readFileSync4(mcpFile, "utf-8")) : {};
2722
+ existing[serverId] = config;
2723
+ writeFileSync4(mcpFile, JSON.stringify(existing, null, 2), { mode: 384 });
2724
+ chmodSync4(mcpFile, 384);
2725
+ syncLocalAssetsToRemote(codeName).catch(() => {
2726
+ });
2727
+ },
2728
+ async syncScheduledTasks(codeName, tasks, gatewayPort) {
2729
+ const target = readDeploymentTarget(codeName);
2730
+ if (!target)
2731
+ return;
2732
+ const configDir = getConfigDir(codeName);
2733
+ ensureDir(configDir);
2734
+ const tasksFile = join3(configDir, "scheduled-tasks.json");
2735
+ writeFileSync4(tasksFile, JSON.stringify(tasks, null, 2));
2736
+ try {
2737
+ const remoteDir = `/opt/augmented/${codeName}`;
2738
+ await scpPush(target, tasksFile, `${remoteDir}/scheduled-tasks.json`);
2739
+ await sshExec(target, `nemoclaw cron sync ${codeName} --config ${remoteDir}/scheduled-tasks.json`);
2740
+ } catch {
2610
2741
  }
2611
- return {
2612
- written: false,
2613
- errors: secretFindings.map((f) => ({
2614
- kind: "literal_secret",
2615
- server: f.server,
2616
- message: `literal secret in ${f.location} field '${f.field}' (pattern ${f.pattern}); expected a \${VAR} template`
2617
- }))
2618
- };
2619
2742
  }
2620
- lastRejectionFingerprintByPath.delete(path);
2621
- safeWriteJsonAtomic(path, JSON.stringify(config, null, 2), { mode: MCP_FILE_MODE });
2622
- return { written: true, errors: [] };
2623
- }
2624
- var SECRET_FIELD_NAME_RE = /TOKEN|KEY|SECRET|BEARER|PASSWORD/i;
2625
- function collectSecretFields(config) {
2626
- const out = /* @__PURE__ */ new Map();
2627
- if (typeof config !== "object" || config === null)
2628
- return out;
2629
- const servers = config.mcpServers;
2630
- if (typeof servers !== "object" || servers === null)
2631
- return out;
2632
- for (const [server, raw] of Object.entries(servers)) {
2633
- if (typeof raw !== "object" || raw === null)
2634
- continue;
2635
- const entry = raw;
2636
- for (const [block, location] of [
2637
- [entry.env, "env"],
2638
- [entry.headers, "header"]
2639
- ]) {
2640
- if (!block)
2641
- continue;
2642
- for (const [field, value] of Object.entries(block)) {
2643
- if (typeof value !== "string")
2644
- continue;
2645
- if (!SECRET_FIELD_NAME_RE.test(field))
2646
- continue;
2647
- out.set(`${server}\0${field}`, { location, value });
2743
+ };
2744
+ function extractAllowedDomains(input) {
2745
+ const domains = /* @__PURE__ */ new Set();
2746
+ const controlPlaneHost = process.env["AGT_HOST"] ? new URL(process.env["AGT_HOST"]).hostname : "api.agt.localhost";
2747
+ domains.add(controlPlaneHost);
2748
+ for (const tool of input.toolsFrontmatter.tools) {
2749
+ if (tool.network?.allowlist_domains) {
2750
+ for (const domain of tool.network.allowlist_domains) {
2751
+ domains.add(domain);
2648
2752
  }
2649
2753
  }
2650
2754
  }
2651
- return out;
2652
- }
2653
- function mcpMirrorParityErrors(provision2, project) {
2654
- const a = collectSecretFields(provision2);
2655
- const b = collectSecretFields(project);
2656
- const mismatches = [];
2657
- const keys = /* @__PURE__ */ new Set([...a.keys(), ...b.keys()]);
2658
- for (const key of keys) {
2659
- const [server, field] = key.split("\0");
2660
- const pv = a.get(key);
2661
- const pj = b.get(key);
2662
- if (pv && !pj) {
2663
- mismatches.push({ server, field, location: pv.location, reason: "missing-in-project" });
2664
- } else if (!pv && pj) {
2665
- mismatches.push({ server, field, location: pj.location, reason: "missing-in-provision" });
2666
- } else if (pv && pj && pv.value !== pj.value) {
2667
- mismatches.push({ server, field, location: pv.location, reason: "value-diverges" });
2668
- }
2669
- }
2670
- return mismatches;
2671
- }
2672
- function formatMirrorMismatch(m) {
2673
- return `[mcp-mirror] [parity-violation] server=${m.server} field=${m.field} location=${m.location} reason=${m.reason}`;
2755
+ return [...domains];
2674
2756
  }
2757
+ registerFramework(nemoClawAdapter);
2675
2758
 
2676
2759
  // ../../packages/core/dist/provisioning/frameworks/claudecode/identity.js
2677
2760
  function buildMemorySection(hasQmd) {
@@ -3787,70 +3870,6 @@ The marginal cost of completeness is near zero. Do the whole thing.
3787
3870
  ${frontmatter.environment === "prod" ? "- Production environment: exercise extra caution with all operations.\n" : ""}`;
3788
3871
  }
3789
3872
 
3790
- // ../../packages/core/dist/provisioning/env-integrations-file.js
3791
- function shellQuote(value) {
3792
- return `'${value.replace(/'/g, `'\\''`)}'`;
3793
- }
3794
- var CHANNEL_SECRET_ENV_KEYS = [
3795
- "SLACK_BOT_TOKEN",
3796
- "SLACK_APP_TOKEN",
3797
- "TELEGRAM_BOT_TOKEN",
3798
- "MSTEAMS_CLIENT_SECRET"
3799
- ];
3800
- var MCP_SERVER_SECRET_ENV_KEYS = [
3801
- "COMPOSIO_API_KEY",
3802
- "PIPEDREAM_CLIENT_SECRET"
3803
- ];
3804
- var PRESERVED_ENV_KEYS = [
3805
- ...CHANNEL_SECRET_ENV_KEYS,
3806
- ...MCP_SERVER_SECRET_ENV_KEYS
3807
- ];
3808
- var HEADER = "# Augmented integrations \u2014 auto-generated, do not edit";
3809
- function parseEnvFileEntries(content) {
3810
- const out = /* @__PURE__ */ new Map();
3811
- for (const line of content.split("\n")) {
3812
- if (!line || line.startsWith("#") || !line.includes("="))
3813
- continue;
3814
- const eqIdx = line.indexOf("=");
3815
- out.set(line.slice(0, eqIdx), line.slice(eqIdx + 1));
3816
- }
3817
- return out;
3818
- }
3819
- function renderEnvIntegrations(entries) {
3820
- const lines = [HEADER];
3821
- for (const [key, rendered] of entries)
3822
- lines.push(`${key}=${rendered}`);
3823
- return lines.join("\n") + "\n";
3824
- }
3825
- function mergeEnvIntegrationsContent(existing, args) {
3826
- const current = existing === null ? /* @__PURE__ */ new Map() : parseEnvFileEntries(existing);
3827
- let next;
3828
- if (args.mode === "upsert") {
3829
- next = new Map(current);
3830
- for (const [key, raw] of Object.entries(args.updates)) {
3831
- if (raw === null)
3832
- next.delete(key);
3833
- else
3834
- next.set(key, shellQuote(raw));
3835
- }
3836
- } else {
3837
- next = /* @__PURE__ */ new Map();
3838
- for (const [key, raw] of Object.entries(args.updates)) {
3839
- if (raw !== null)
3840
- next.set(key, shellQuote(raw));
3841
- }
3842
- const preserve = args.preserveKeys ?? PRESERVED_ENV_KEYS;
3843
- for (const key of preserve) {
3844
- if (key in args.updates)
3845
- continue;
3846
- if (!next.has(key) && current.has(key)) {
3847
- next.set(key, current.get(key));
3848
- }
3849
- }
3850
- }
3851
- return renderEnvIntegrations(next);
3852
- }
3853
-
3854
3873
  // ../../packages/core/dist/provisioning/frameworks/claudecode/index.js
3855
3874
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync5, chmodSync as chmodSync5, readdirSync, rmSync, copyFileSync } from "fs";
3856
3875
  import { join as join4, relative, dirname as dirname4 } from "path";
@@ -5054,6 +5073,12 @@ function buildMcpJson(input) {
5054
5073
  // dashboard links) in tool replies. Falls back to NEXT_PUBLIC_APP_URL
5055
5074
  // / AGT_CONSOLE_URL — same chain consoleUrl uses for kanban links.
5056
5075
  AGT_APP_URL: process.env["AGT_APP_URL"] ?? process.env["NEXT_PUBLIC_APP_URL"] ?? process.env["AGT_CONSOLE_URL"] ?? "",
5076
+ // ENG-6229: arms the in-session `request_restart` self-restart tool.
5077
+ // Read at provision time from the manager's env (like AGT_HOST above),
5078
+ // NOT a per-spawn `${...}` template — it's a host-level gate. Empty by
5079
+ // default ⇒ the tool isn't registered at all (ships dark). When an
5080
+ // operator sets it on the host, the next /host/refresh bakes it in.
5081
+ AGT_AGENT_SELF_RESTART_ENABLED: process.env["AGT_AGENT_SELF_RESTART_ENABLED"] ?? "",
5057
5082
  // Include PATH/HOME so the MCP subprocess can resolve binaries
5058
5083
  PATH: process.env["PATH"] ?? "",
5059
5084
  HOME: process.env["HOME"] ?? ""
@@ -6785,22 +6810,6 @@ var ManagedAgentsAdapter = {
6785
6810
  };
6786
6811
  registerFramework(ManagedAgentsAdapter);
6787
6812
 
6788
- // src/lib/globals.ts
6789
- import chalk from "chalk";
6790
- var _jsonMode = false;
6791
- function setJsonMode(enabled) {
6792
- _jsonMode = enabled;
6793
- if (enabled) {
6794
- chalk.level = 0;
6795
- }
6796
- }
6797
- function isJsonMode() {
6798
- return _jsonMode;
6799
- }
6800
- function jsonOutput(data) {
6801
- console.log(JSON.stringify(data, null, 2));
6802
- }
6803
-
6804
6813
  // src/lib/config.ts
6805
6814
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, existsSync as existsSync6 } from "fs";
6806
6815
  import { join as join6 } from "path";
@@ -7052,23 +7061,20 @@ async function getHostId() {
7052
7061
  return hostId;
7053
7062
  }
7054
7063
 
7055
- // ../../packages/core/dist/provisioning/provisioner.js
7056
- import { createHash } from "crypto";
7057
- function sha256(content) {
7058
- return createHash("sha256").update(content, "utf8").digest("hex");
7064
+ // src/lib/globals.ts
7065
+ import chalk from "chalk";
7066
+ var _jsonMode = false;
7067
+ function setJsonMode(enabled) {
7068
+ _jsonMode = enabled;
7069
+ if (enabled) {
7070
+ chalk.level = 0;
7071
+ }
7059
7072
  }
7060
- function provision(input, frameworkId = "openclaw") {
7061
- const adapter = getFramework(frameworkId);
7062
- const artifacts = adapter.buildArtifacts(input);
7063
- const charterHash = sha256(input.charterContent);
7064
- const toolsHash = sha256(input.toolsContent);
7065
- const teamDir = `.augmented/${input.agent.code_name}`;
7066
- return {
7067
- teamDir,
7068
- artifacts,
7069
- charterHash,
7070
- toolsHash
7071
- };
7073
+ function isJsonMode() {
7074
+ return _jsonMode;
7075
+ }
7076
+ function jsonOutput(data) {
7077
+ console.log(JSON.stringify(data, null, 2));
7072
7078
  }
7073
7079
 
7074
7080
  // src/commands/manager.ts
@@ -7684,20 +7690,18 @@ async function managerUninstallSystemUnitCommand() {
7684
7690
  }
7685
7691
 
7686
7692
  export {
7687
- getIntegration,
7693
+ provision,
7688
7694
  extractCommandNotFound,
7695
+ getIntegration,
7696
+ CHANNEL_SECRET_ENV_KEYS,
7689
7697
  LITERAL_SECRET_PATTERNS,
7690
7698
  safeWriteJsonAtomic,
7691
7699
  INTEGRATIONS_SECTION_START,
7692
7700
  INTEGRATIONS_SECTION_END,
7693
7701
  estimateActiveTasksTokens,
7694
- CHANNEL_SECRET_ENV_KEYS,
7695
7702
  provisionStopHook,
7696
7703
  provisionIsolationHook,
7697
7704
  provisionOrientHook,
7698
- setJsonMode,
7699
- isJsonMode,
7700
- jsonOutput,
7701
7705
  getApiKey,
7702
7706
  getActiveTeam,
7703
7707
  setActiveTeam,
@@ -7708,14 +7712,16 @@ export {
7708
7712
  ApiError,
7709
7713
  api,
7710
7714
  getHostId,
7715
+ getManagerPaths,
7716
+ startWatchdog,
7711
7717
  success,
7712
7718
  error,
7713
7719
  warn,
7714
7720
  info,
7715
7721
  table,
7716
- provision,
7717
- getManagerPaths,
7718
- startWatchdog,
7722
+ setJsonMode,
7723
+ isJsonMode,
7724
+ jsonOutput,
7719
7725
  managerStartCommand,
7720
7726
  SUPERVISOR_RESTART_EXIT_CODE,
7721
7727
  managerStopCommand,
@@ -7725,4 +7731,4 @@ export {
7725
7731
  managerInstallSystemUnitCommand,
7726
7732
  managerUninstallSystemUnitCommand
7727
7733
  };
7728
- //# sourceMappingURL=chunk-4Y7APKV7.js.map
7734
+ //# sourceMappingURL=chunk-4B6KOQQL.js.map