@integrity-labs/agt-cli 0.27.136 → 0.27.137

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,65 +9,7 @@ import {
9
9
  parseDeliveryTarget,
10
10
  registerFramework,
11
11
  wrapScheduledTaskPrompt
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
- }
12
+ } from "./chunk-TDMOEMDM.js";
71
13
 
72
14
  // ../../packages/core/dist/integrations/registry.js
73
15
  var INTEGRATION_REGISTRY = [
@@ -479,370 +421,52 @@ function getIntegration(id) {
479
421
  return integrationMap.get(id);
480
422
  }
481
423
 
482
- // ../../packages/core/dist/provisioning/env-integrations-file.js
483
- function shellQuote(value) {
484
- return `'${value.replace(/'/g, `'\\''`)}'`;
485
- }
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" });
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(":");
446
+ }
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;
831
458
  }
832
459
  }
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}`;
460
+ return null;
837
461
  }
838
462
 
839
463
  // ../../packages/core/dist/provisioning/frameworks/openclaw/index.js
840
464
  import { execFile, spawn } from "child_process";
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";
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";
842
466
  import { join as join2, dirname as dirname2, resolve } from "path";
843
467
 
844
468
  // ../../packages/core/dist/integrations/xurl-config.js
845
- import { chmodSync as chmodSync2, existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
469
+ import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "fs";
846
470
  import { homedir } from "os";
847
471
  import { dirname, join } from "path";
848
472
  import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
@@ -970,10 +594,10 @@ function writeXurlStoreForIntegrations(integrations, filePath = getXurlStorePath
970
594
  if (Object.keys(agtApps).length === 0)
971
595
  return null;
972
596
  let existing = null;
973
- if (existsSync2(filePath)) {
597
+ if (existsSync(filePath)) {
974
598
  let raw;
975
599
  try {
976
- raw = readFileSync2(filePath, "utf-8");
600
+ raw = readFileSync(filePath, "utf-8");
977
601
  } catch {
978
602
  return null;
979
603
  }
@@ -986,18 +610,18 @@ function writeXurlStoreForIntegrations(integrations, filePath = getXurlStorePath
986
610
  const merged = mergeXurlStore(existing, agtApps);
987
611
  mkdirSync(dirname(filePath), { recursive: true });
988
612
  const tmpPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
989
- writeFileSync2(tmpPath, serializeXurlStore(merged), { mode: XURL_FILE_MODE });
613
+ writeFileSync(tmpPath, serializeXurlStore(merged), { mode: XURL_FILE_MODE });
990
614
  try {
991
- renameSync2(tmpPath, filePath);
615
+ renameSync(tmpPath, filePath);
992
616
  } catch (err) {
993
617
  try {
994
- unlinkSync2(tmpPath);
618
+ unlinkSync(tmpPath);
995
619
  } catch {
996
620
  }
997
621
  throw err;
998
622
  }
999
623
  try {
1000
- chmodSync2(filePath, XURL_FILE_MODE);
624
+ chmodSync(filePath, XURL_FILE_MODE);
1001
625
  } catch {
1002
626
  }
1003
627
  return filePath;
@@ -1420,9 +1044,9 @@ function writeIntegrationTokenFile(codeName, integrations) {
1420
1044
  if (Object.keys(tokens).length === 0)
1421
1045
  return;
1422
1046
  mkdirSync2(dir, { recursive: true });
1423
- writeFileSync3(tmpFilePath, JSON.stringify(tokens, null, 2));
1424
- chmodSync3(tmpFilePath, 384);
1425
- renameSync3(tmpFilePath, tokenFilePath);
1047
+ writeFileSync2(tmpFilePath, JSON.stringify(tokens, null, 2));
1048
+ chmodSync2(tmpFilePath, 384);
1049
+ renameSync2(tmpFilePath, tokenFilePath);
1426
1050
  }
1427
1051
  function getOpenClawConfigPath(profile) {
1428
1052
  const homeDir = getHomeDir();
@@ -1436,7 +1060,7 @@ function modifyOpenClawConfig(fn, profile) {
1436
1060
  let originalContent;
1437
1061
  let config;
1438
1062
  try {
1439
- originalContent = readFileSync3(configFile, "utf-8");
1063
+ originalContent = readFileSync2(configFile, "utf-8");
1440
1064
  config = JSON.parse(originalContent);
1441
1065
  } catch {
1442
1066
  return;
@@ -1447,7 +1071,7 @@ function modifyOpenClawConfig(fn, profile) {
1447
1071
  const newContent = JSON.stringify(config, null, 2);
1448
1072
  if (newContent === originalContent)
1449
1073
  return;
1450
- writeFileSync3(configFile, newContent);
1074
+ writeFileSync2(configFile, newContent);
1451
1075
  }
1452
1076
  var AUGMENTED_DIR = join2(getHomeDir(), ".augmented");
1453
1077
  function getGatewayPidPath(codeName) {
@@ -1461,7 +1085,7 @@ function getGatewayPortsPath() {
1461
1085
  }
1462
1086
  function readGatewayPid(codeName) {
1463
1087
  try {
1464
- const raw = readFileSync3(getGatewayPidPath(codeName), "utf-8").trim();
1088
+ const raw = readFileSync2(getGatewayPidPath(codeName), "utf-8").trim();
1465
1089
  const pid = parseInt(raw, 10);
1466
1090
  return isNaN(pid) ? null : pid;
1467
1091
  } catch {
@@ -1509,7 +1133,7 @@ function execPromise(cmd, args) {
1509
1133
  }
1510
1134
  function readGatewayPorts() {
1511
1135
  try {
1512
- return JSON.parse(readFileSync3(getGatewayPortsPath(), "utf-8"));
1136
+ return JSON.parse(readFileSync2(getGatewayPortsPath(), "utf-8"));
1513
1137
  } catch {
1514
1138
  return {};
1515
1139
  }
@@ -1745,7 +1369,7 @@ ${entry.content}`
1745
1369
  const configFile = getOpenClawConfigPath(codeName);
1746
1370
  let raw;
1747
1371
  try {
1748
- raw = readFileSync3(configFile, "utf-8");
1372
+ raw = readFileSync2(configFile, "utf-8");
1749
1373
  } catch {
1750
1374
  return false;
1751
1375
  }
@@ -1814,7 +1438,7 @@ ${entry.content}`
1814
1438
  const authFile = join2(authDir, "auth-profiles.json");
1815
1439
  let existing = {};
1816
1440
  try {
1817
- existing = JSON.parse(readFileSync3(authFile, "utf-8"));
1441
+ existing = JSON.parse(readFileSync2(authFile, "utf-8"));
1818
1442
  } catch {
1819
1443
  }
1820
1444
  const existingProfiles = existing["profiles"] ?? {};
@@ -1836,7 +1460,7 @@ ${entry.content}`
1836
1460
  usageStats: existing["usageStats"] ?? {}
1837
1461
  };
1838
1462
  mkdirSync2(authDir, { recursive: true });
1839
- writeFileSync3(authFile, JSON.stringify(output, null, 2));
1463
+ writeFileSync2(authFile, JSON.stringify(output, null, 2));
1840
1464
  },
1841
1465
  async startGateway(codeName, port) {
1842
1466
  const agentAugDir = join2(AUGMENTED_DIR, codeName);
@@ -1873,7 +1497,7 @@ ${entry.content}`
1873
1497
  }
1874
1498
  }
1875
1499
  }
1876
- writeFileSync3(pidPath, String(gatewayPid));
1500
+ writeFileSync2(pidPath, String(gatewayPid));
1877
1501
  return { pid: gatewayPid, port };
1878
1502
  },
1879
1503
  async stopGateway(codeName) {
@@ -1882,7 +1506,7 @@ ${entry.content}`
1882
1506
  return false;
1883
1507
  if (!isProcessAlive(pid)) {
1884
1508
  try {
1885
- unlinkSync3(getGatewayPidPath(codeName));
1509
+ unlinkSync2(getGatewayPidPath(codeName));
1886
1510
  } catch {
1887
1511
  }
1888
1512
  return false;
@@ -1897,7 +1521,7 @@ ${entry.content}`
1897
1521
  await new Promise((r) => setTimeout(r, 200));
1898
1522
  if (!isProcessAlive(pid)) {
1899
1523
  try {
1900
- unlinkSync3(getGatewayPidPath(codeName));
1524
+ unlinkSync2(getGatewayPidPath(codeName));
1901
1525
  } catch {
1902
1526
  }
1903
1527
  return true;
@@ -1908,7 +1532,7 @@ ${entry.content}`
1908
1532
  } catch {
1909
1533
  }
1910
1534
  try {
1911
- unlinkSync3(getGatewayPidPath(codeName));
1535
+ unlinkSync2(getGatewayPidPath(codeName));
1912
1536
  } catch {
1913
1537
  }
1914
1538
  return true;
@@ -1925,7 +1549,7 @@ ${entry.content}`
1925
1549
  if (portPid) {
1926
1550
  try {
1927
1551
  const pidPath = getGatewayPidPath(codeName);
1928
- writeFileSync3(pidPath, String(portPid));
1552
+ writeFileSync2(pidPath, String(portPid));
1929
1553
  } catch {
1930
1554
  }
1931
1555
  return { running: true, pid: portPid, port };
@@ -1933,7 +1557,7 @@ ${entry.content}`
1933
1557
  }
1934
1558
  if (pid) {
1935
1559
  try {
1936
- unlinkSync3(getGatewayPidPath(codeName));
1560
+ unlinkSync2(getGatewayPidPath(codeName));
1937
1561
  } catch {
1938
1562
  }
1939
1563
  }
@@ -1946,13 +1570,13 @@ ${entry.content}`
1946
1570
  const profileConfigPath = join2(profileDir, "openclaw.json");
1947
1571
  let sharedConfig;
1948
1572
  try {
1949
- sharedConfig = JSON.parse(readFileSync3(sharedConfigPath, "utf-8"));
1573
+ sharedConfig = JSON.parse(readFileSync2(sharedConfigPath, "utf-8"));
1950
1574
  } catch {
1951
1575
  sharedConfig = {};
1952
1576
  }
1953
- if (existsSync3(profileConfigPath)) {
1577
+ if (existsSync2(profileConfigPath)) {
1954
1578
  try {
1955
- const existing = JSON.parse(readFileSync3(profileConfigPath, "utf-8"));
1579
+ const existing = JSON.parse(readFileSync2(profileConfigPath, "utf-8"));
1956
1580
  let changed = false;
1957
1581
  if (!existing["gateway"]) {
1958
1582
  if (sharedConfig["gateway"]) {
@@ -1970,7 +1594,7 @@ ${entry.content}`
1970
1594
  changed = true;
1971
1595
  }
1972
1596
  if (changed) {
1973
- writeFileSync3(profileConfigPath, JSON.stringify(existing, null, 2));
1597
+ writeFileSync2(profileConfigPath, JSON.stringify(existing, null, 2));
1974
1598
  }
1975
1599
  } catch {
1976
1600
  }
@@ -2017,13 +1641,13 @@ ${entry.content}`
2017
1641
  }
2018
1642
  };
2019
1643
  mkdirSync2(profileDir, { recursive: true });
2020
- writeFileSync3(profileConfigPath, JSON.stringify(profileConfig, null, 2));
1644
+ writeFileSync2(profileConfigPath, JSON.stringify(profileConfig, null, 2));
2021
1645
  const agentAuthDir = join2(profileDir, "agents", codeName, "agent");
2022
1646
  const mainAgentDir = join2(profileDir, "agents", "main", "agent");
2023
1647
  try {
2024
1648
  mkdirSync2(agentAuthDir, { recursive: true });
2025
1649
  mkdirSync2(join2(profileDir, "agents", "main"), { recursive: true });
2026
- if (!existsSync3(mainAgentDir)) {
1650
+ if (!existsSync2(mainAgentDir)) {
2027
1651
  symlinkSync(agentAuthDir, mainAgentDir, "dir");
2028
1652
  }
2029
1653
  } catch {
@@ -2037,7 +1661,7 @@ ${entry.content}`
2037
1661
  const authFile = join2(authDir, "auth-profiles.json");
2038
1662
  let existing = {};
2039
1663
  try {
2040
- existing = JSON.parse(readFileSync3(authFile, "utf-8"));
1664
+ existing = JSON.parse(readFileSync2(authFile, "utf-8"));
2041
1665
  } catch {
2042
1666
  }
2043
1667
  const existingProfiles = existing["profiles"] ?? {};
@@ -2049,7 +1673,7 @@ ${entry.content}`
2049
1673
  usageStats: existing["usageStats"] ?? {}
2050
1674
  };
2051
1675
  mkdirSync2(authDir, { recursive: true });
2052
- writeFileSync3(authFile, JSON.stringify(output, null, 2));
1676
+ writeFileSync2(authFile, JSON.stringify(output, null, 2));
2053
1677
  }
2054
1678
  if (integrationConfig.toolAllow.length > 0) {
2055
1679
  modifyOpenClawConfig((config) => {
@@ -2172,7 +1796,7 @@ ${entry.content}`
2172
1796
  for (const file of files) {
2173
1797
  const filePath = join2(skillDir, file.relativePath);
2174
1798
  mkdirSync2(dirname2(filePath), { recursive: true });
2175
- writeFileSync3(filePath, file.content);
1799
+ writeFileSync2(filePath, file.content);
2176
1800
  }
2177
1801
  },
2178
1802
  writeMcpServer(codeName, serverId, config) {
@@ -2268,7 +1892,7 @@ ${entry.content}`
2268
1892
  readGatewayToken(codeName) {
2269
1893
  const homeDir = getHomeDir();
2270
1894
  try {
2271
- const config = JSON.parse(readFileSync3(join2(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
1895
+ const config = JSON.parse(readFileSync2(join2(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
2272
1896
  return config?.gateway?.auth?.token;
2273
1897
  } catch {
2274
1898
  return void 0;
@@ -2409,7 +2033,7 @@ ${entry.content}`
2409
2033
  registerFramework(openclawAdapter);
2410
2034
 
2411
2035
  // ../../packages/core/dist/provisioning/frameworks/nemoclaw/index.js
2412
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3, existsSync as existsSync4, chmodSync as chmodSync4 } from "fs";
2036
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, existsSync as existsSync3, chmodSync as chmodSync3 } from "fs";
2413
2037
  import { join as join3, dirname as dirname3, resolve as resolve2, sep } from "path";
2414
2038
  import { homedir as homedir2 } from "os";
2415
2039
  import { execFile as execFile2 } from "child_process";
@@ -2432,9 +2056,9 @@ function ensureDir(dir) {
2432
2056
  }
2433
2057
  function readDeploymentTarget(codeName) {
2434
2058
  const targetFile = join3(getConfigDir(codeName), "target.json");
2435
- if (!existsSync4(targetFile))
2059
+ if (!existsSync3(targetFile))
2436
2060
  return null;
2437
- return JSON.parse(readFileSync4(targetFile, "utf-8"));
2061
+ return JSON.parse(readFileSync3(targetFile, "utf-8"));
2438
2062
  }
2439
2063
  async function sshExec(target, command, options) {
2440
2064
  const sshArgs = [
@@ -2472,7 +2096,7 @@ async function syncLocalAssetsToRemote(codeName) {
2472
2096
  if (!target)
2473
2097
  return;
2474
2098
  const localAssetsDir = getConfigDir(codeName);
2475
- if (!existsSync4(localAssetsDir))
2099
+ if (!existsSync3(localAssetsDir))
2476
2100
  return;
2477
2101
  const remoteDir = `/opt/augmented/${codeName}`;
2478
2102
  const remoteAssetsDir = `${remoteDir}/assets`;
@@ -2576,7 +2200,7 @@ var nemoClawAdapter = {
2576
2200
  await scpPush(target, blueprintPath, `${remoteDir}/blueprint.json`);
2577
2201
  for (const file of ["CHARTER.md", "TOOLS.md"]) {
2578
2202
  const localPath = join3(teamDir, file);
2579
- if (existsSync4(localPath)) {
2203
+ if (existsSync3(localPath)) {
2580
2204
  await scpPush(target, localPath, `${remoteDir}/${file}`);
2581
2205
  }
2582
2206
  }
@@ -2605,7 +2229,7 @@ var nemoClawAdapter = {
2605
2229
  const configDir = getConfigDir(codeName);
2606
2230
  ensureDir(configDir);
2607
2231
  const authFile = join3(configDir, "auth-profiles.json");
2608
- const existing = existsSync4(authFile) ? JSON.parse(readFileSync4(authFile, "utf-8")) : {};
2232
+ const existing = existsSync3(authFile) ? JSON.parse(readFileSync3(authFile, "utf-8")) : {};
2609
2233
  for (const profile of profiles) {
2610
2234
  const previous = existing[profile.profile_name];
2611
2235
  existing[profile.profile_name] = {
@@ -2616,7 +2240,7 @@ var nemoClawAdapter = {
2616
2240
  ...profile.metadata
2617
2241
  };
2618
2242
  }
2619
- writeFileSync4(authFile, JSON.stringify(existing, null, 2), { mode: 384 });
2243
+ writeFileSync3(authFile, JSON.stringify(existing, null, 2), { mode: 384 });
2620
2244
  syncLocalAssetsToRemote(codeName).catch(() => {
2621
2245
  });
2622
2246
  },
@@ -2638,7 +2262,7 @@ var nemoClawAdapter = {
2638
2262
  }
2639
2263
  const configDir = getConfigDir(codeName);
2640
2264
  ensureDir(configDir);
2641
- writeFileSync4(join3(configDir, "gateway.json"), JSON.stringify({
2265
+ writeFileSync3(join3(configDir, "gateway.json"), JSON.stringify({
2642
2266
  pid: result.pid,
2643
2267
  port: result.port,
2644
2268
  host: target.host,
@@ -2675,7 +2299,7 @@ var nemoClawAdapter = {
2675
2299
  readGatewayToken(codeName) {
2676
2300
  try {
2677
2301
  const gatewayFile = join3(getConfigDir(codeName), "gateway.json");
2678
- const config = JSON.parse(readFileSync4(gatewayFile, "utf-8"));
2302
+ const config = JSON.parse(readFileSync3(gatewayFile, "utf-8"));
2679
2303
  return config?.token;
2680
2304
  } catch {
2681
2305
  return void 0;
@@ -2694,7 +2318,7 @@ var nemoClawAdapter = {
2694
2318
  env[envKey] = apiKey;
2695
2319
  }
2696
2320
  }
2697
- writeFileSync4(envFile, JSON.stringify(env, null, 2), { mode: 384 });
2321
+ writeFileSync3(envFile, JSON.stringify(env, null, 2), { mode: 384 });
2698
2322
  syncLocalAssetsToRemote(codeName).catch(() => {
2699
2323
  });
2700
2324
  },
@@ -2702,59 +2326,352 @@ var nemoClawAdapter = {
2702
2326
  if (!/^[a-zA-Z0-9_-]+$/.test(skillId)) {
2703
2327
  throw new Error(`Invalid skill ID: ${skillId}`);
2704
2328
  }
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}`);
2710
- }
2711
- mkdirSync3(dirname3(filePath), { recursive: true });
2712
- writeFileSync4(filePath, file.content);
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 {
2713
2572
  }
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));
2573
+ throw err;
2574
+ }
2575
+ try {
2576
+ if (keepBackup && existsSync4(path)) {
2577
+ rename(path, bakPath);
2578
+ movedOriginalToBackup = true;
2579
+ }
2580
+ rename(tmpPath, path);
2581
+ } catch (err) {
2736
2582
  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`);
2583
+ if (existsSync4(tmpPath))
2584
+ unlinkSync3(tmpPath);
2740
2585
  } catch {
2741
2586
  }
2587
+ if (movedOriginalToBackup && !existsSync4(path) && existsSync4(bakPath)) {
2588
+ try {
2589
+ renameSync3(bakPath, path);
2590
+ } catch {
2591
+ }
2592
+ }
2593
+ throw err;
2742
2594
  }
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);
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
+ `);
2752
2609
  }
2753
2610
  }
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
+ };
2754
2619
  }
2755
- return [...domains];
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 });
2648
+ }
2649
+ }
2650
+ }
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}`;
2756
2674
  }
2757
- registerFramework(nemoClawAdapter);
2758
2675
 
2759
2676
  // ../../packages/core/dist/provisioning/frameworks/claudecode/identity.js
2760
2677
  function buildMemorySection(hasQmd) {
@@ -3870,6 +3787,70 @@ The marginal cost of completeness is near zero. Do the whole thing.
3870
3787
  ${frontmatter.environment === "prod" ? "- Production environment: exercise extra caution with all operations.\n" : ""}`;
3871
3788
  }
3872
3789
 
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
+
3873
3854
  // ../../packages/core/dist/provisioning/frameworks/claudecode/index.js
3874
3855
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync5, chmodSync as chmodSync5, readdirSync, rmSync, copyFileSync } from "fs";
3875
3856
  import { join as join4, relative, dirname as dirname4 } from "path";
@@ -6810,6 +6791,22 @@ var ManagedAgentsAdapter = {
6810
6791
  };
6811
6792
  registerFramework(ManagedAgentsAdapter);
6812
6793
 
6794
+ // src/lib/globals.ts
6795
+ import chalk from "chalk";
6796
+ var _jsonMode = false;
6797
+ function setJsonMode(enabled) {
6798
+ _jsonMode = enabled;
6799
+ if (enabled) {
6800
+ chalk.level = 0;
6801
+ }
6802
+ }
6803
+ function isJsonMode() {
6804
+ return _jsonMode;
6805
+ }
6806
+ function jsonOutput(data) {
6807
+ console.log(JSON.stringify(data, null, 2));
6808
+ }
6809
+
6813
6810
  // src/lib/config.ts
6814
6811
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, existsSync as existsSync6 } from "fs";
6815
6812
  import { join as join6 } from "path";
@@ -7061,20 +7058,23 @@ async function getHostId() {
7061
7058
  return hostId;
7062
7059
  }
7063
7060
 
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
- }
7072
- }
7073
- function isJsonMode() {
7074
- return _jsonMode;
7061
+ // ../../packages/core/dist/provisioning/provisioner.js
7062
+ import { createHash } from "crypto";
7063
+ function sha256(content) {
7064
+ return createHash("sha256").update(content, "utf8").digest("hex");
7075
7065
  }
7076
- function jsonOutput(data) {
7077
- console.log(JSON.stringify(data, null, 2));
7066
+ function provision(input, frameworkId = "openclaw") {
7067
+ const adapter = getFramework(frameworkId);
7068
+ const artifacts = adapter.buildArtifacts(input);
7069
+ const charterHash = sha256(input.charterContent);
7070
+ const toolsHash = sha256(input.toolsContent);
7071
+ const teamDir = `.augmented/${input.agent.code_name}`;
7072
+ return {
7073
+ teamDir,
7074
+ artifacts,
7075
+ charterHash,
7076
+ toolsHash
7077
+ };
7078
7078
  }
7079
7079
 
7080
7080
  // src/commands/manager.ts
@@ -7690,18 +7690,20 @@ async function managerUninstallSystemUnitCommand() {
7690
7690
  }
7691
7691
 
7692
7692
  export {
7693
- provision,
7694
- extractCommandNotFound,
7695
7693
  getIntegration,
7696
- CHANNEL_SECRET_ENV_KEYS,
7694
+ extractCommandNotFound,
7697
7695
  LITERAL_SECRET_PATTERNS,
7698
7696
  safeWriteJsonAtomic,
7699
7697
  INTEGRATIONS_SECTION_START,
7700
7698
  INTEGRATIONS_SECTION_END,
7701
7699
  estimateActiveTasksTokens,
7700
+ CHANNEL_SECRET_ENV_KEYS,
7702
7701
  provisionStopHook,
7703
7702
  provisionIsolationHook,
7704
7703
  provisionOrientHook,
7704
+ setJsonMode,
7705
+ isJsonMode,
7706
+ jsonOutput,
7705
7707
  getApiKey,
7706
7708
  getActiveTeam,
7707
7709
  setActiveTeam,
@@ -7712,16 +7714,14 @@ export {
7712
7714
  ApiError,
7713
7715
  api,
7714
7716
  getHostId,
7715
- getManagerPaths,
7716
- startWatchdog,
7717
7717
  success,
7718
7718
  error,
7719
7719
  warn,
7720
7720
  info,
7721
7721
  table,
7722
- setJsonMode,
7723
- isJsonMode,
7724
- jsonOutput,
7722
+ provision,
7723
+ getManagerPaths,
7724
+ startWatchdog,
7725
7725
  managerStartCommand,
7726
7726
  SUPERVISOR_RESTART_EXIT_CODE,
7727
7727
  managerStopCommand,
@@ -7731,4 +7731,4 @@ export {
7731
7731
  managerInstallSystemUnitCommand,
7732
7732
  managerUninstallSystemUnitCommand
7733
7733
  };
7734
- //# sourceMappingURL=chunk-4B6KOQQL.js.map
7734
+ //# sourceMappingURL=chunk-UIRCFCED.js.map