@integrity-labs/agt-cli 0.19.14 → 0.19.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/agt.js +3 -3
- package/dist/{chunk-HA4IUBVC.js → chunk-3K3RO5NS.js} +2 -1
- package/dist/{chunk-KLNFWXOI.js → chunk-DVWBVANP.js} +379 -141
- package/dist/chunk-DVWBVANP.js.map +1 -0
- package/dist/{claude-pair-runtime-VXN4NVGR.js → claude-pair-runtime-UF4OMFCA.js} +2 -2
- package/dist/lib/manager-worker.js +206 -30
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/{persistent-session-CFDGW7QE.js → persistent-session-M2GVL6Z6.js} +2 -2
- package/mcp/slack-channel.js +111 -0
- package/package.json +1 -1
- package/dist/chunk-KLNFWXOI.js.map +0 -1
- /package/dist/{chunk-HA4IUBVC.js.map → chunk-3K3RO5NS.js.map} +0 -0
- /package/dist/{claude-pair-runtime-VXN4NVGR.js.map → claude-pair-runtime-UF4OMFCA.js.map} +0 -0
- /package/dist/{persistent-session-CFDGW7QE.js.map → persistent-session-M2GVL6Z6.js.map} +0 -0
|
@@ -2632,11 +2632,146 @@ function extractAllowedDomains(input) {
|
|
|
2632
2632
|
registerFramework(nemoClawAdapter);
|
|
2633
2633
|
|
|
2634
2634
|
// ../../packages/core/dist/provisioning/frameworks/claudecode/index.js
|
|
2635
|
-
import { readFileSync as
|
|
2635
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync5, chmodSync as chmodSync4, readdirSync, rmSync, copyFileSync } from "fs";
|
|
2636
2636
|
import { join as join4, relative, dirname as dirname4 } from "path";
|
|
2637
2637
|
import { homedir as homedir3 } from "os";
|
|
2638
2638
|
import { execFile as execFile3 } from "child_process";
|
|
2639
2639
|
|
|
2640
|
+
// ../../packages/core/dist/provisioning/mcp-config-guards.js
|
|
2641
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, renameSync as renameSync3, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3 } from "fs";
|
|
2642
|
+
var REQUIRED_ENV_RULES_BY_SERVER = {
|
|
2643
|
+
"cloud-broker": [
|
|
2644
|
+
{ key: "AGT_HOST", mustBeConcrete: false },
|
|
2645
|
+
{ key: "AGT_API_KEY", mustBeConcrete: false },
|
|
2646
|
+
// ENG-4744: this is the bug shape — writer used to omit this
|
|
2647
|
+
// entirely, or render it as a literal `${AGT_AGENT_ID}` instead
|
|
2648
|
+
// of the agent's real UUID. The broker has no way to substitute
|
|
2649
|
+
// it post-spawn, so a placeholder here = silently broken agent.
|
|
2650
|
+
{ key: "AGT_AGENT_ID", mustBeConcrete: true }
|
|
2651
|
+
]
|
|
2652
|
+
};
|
|
2653
|
+
var PLACEHOLDER_RE = /\$\{[^}]+\}/;
|
|
2654
|
+
function validateRenderedMcpConfig(config) {
|
|
2655
|
+
const errors = [];
|
|
2656
|
+
if (typeof config !== "object" || config === null || Array.isArray(config)) {
|
|
2657
|
+
return {
|
|
2658
|
+
ok: false,
|
|
2659
|
+
errors: [
|
|
2660
|
+
{
|
|
2661
|
+
kind: "invalid_json_shape",
|
|
2662
|
+
server: "*",
|
|
2663
|
+
message: "config root must be a non-null object"
|
|
2664
|
+
}
|
|
2665
|
+
]
|
|
2666
|
+
};
|
|
2667
|
+
}
|
|
2668
|
+
const root = config;
|
|
2669
|
+
if (root.mcpServers === void 0) {
|
|
2670
|
+
return { ok: true };
|
|
2671
|
+
}
|
|
2672
|
+
if (typeof root.mcpServers !== "object" || root.mcpServers === null) {
|
|
2673
|
+
return {
|
|
2674
|
+
ok: false,
|
|
2675
|
+
errors: [
|
|
2676
|
+
{
|
|
2677
|
+
kind: "invalid_json_shape",
|
|
2678
|
+
server: "*",
|
|
2679
|
+
message: "mcpServers must be an object"
|
|
2680
|
+
}
|
|
2681
|
+
]
|
|
2682
|
+
};
|
|
2683
|
+
}
|
|
2684
|
+
if (Array.isArray(root.mcpServers)) {
|
|
2685
|
+
return {
|
|
2686
|
+
ok: false,
|
|
2687
|
+
errors: [
|
|
2688
|
+
{
|
|
2689
|
+
kind: "invalid_json_shape",
|
|
2690
|
+
server: "*",
|
|
2691
|
+
message: "mcpServers must be an object"
|
|
2692
|
+
}
|
|
2693
|
+
]
|
|
2694
|
+
};
|
|
2695
|
+
}
|
|
2696
|
+
for (const [serverKey, raw] of Object.entries(root.mcpServers)) {
|
|
2697
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
2698
|
+
errors.push({
|
|
2699
|
+
kind: "invalid_json_shape",
|
|
2700
|
+
server: serverKey,
|
|
2701
|
+
message: `entry must be an object`
|
|
2702
|
+
});
|
|
2703
|
+
continue;
|
|
2704
|
+
}
|
|
2705
|
+
const entry = raw;
|
|
2706
|
+
const rules = REQUIRED_ENV_RULES_BY_SERVER[serverKey];
|
|
2707
|
+
if (rules) {
|
|
2708
|
+
const env2 = entry.env ?? {};
|
|
2709
|
+
for (const rule of rules) {
|
|
2710
|
+
const value = env2[rule.key];
|
|
2711
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
2712
|
+
errors.push({
|
|
2713
|
+
kind: "missing_required_env",
|
|
2714
|
+
server: serverKey,
|
|
2715
|
+
message: `missing required env key: ${rule.key}`
|
|
2716
|
+
});
|
|
2717
|
+
continue;
|
|
2718
|
+
}
|
|
2719
|
+
if (rule.mustBeConcrete && PLACEHOLDER_RE.test(value)) {
|
|
2720
|
+
errors.push({
|
|
2721
|
+
kind: "unexpanded_placeholder",
|
|
2722
|
+
server: serverKey,
|
|
2723
|
+
message: `env.${rule.key} contains an unexpanded \${...} placeholder; expected a concrete value`
|
|
2724
|
+
});
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
return errors.length === 0 ? { ok: true } : { ok: false, errors };
|
|
2730
|
+
}
|
|
2731
|
+
function formatValidationErrors(errors) {
|
|
2732
|
+
return errors.map((e) => `${e.server}:${e.kind}=${e.message}`).join("; ");
|
|
2733
|
+
}
|
|
2734
|
+
function safeWriteJsonAtomic(path, content, opts = {}) {
|
|
2735
|
+
const keepBackup = opts.keepBackup !== false;
|
|
2736
|
+
const rename = opts.renamer ?? renameSync3;
|
|
2737
|
+
const tmpPath = `${path}.new`;
|
|
2738
|
+
const bakPath = `${path}.bak`;
|
|
2739
|
+
let movedOriginalToBackup = false;
|
|
2740
|
+
try {
|
|
2741
|
+
writeFileSync4(tmpPath, content);
|
|
2742
|
+
} catch (err) {
|
|
2743
|
+
throw err;
|
|
2744
|
+
}
|
|
2745
|
+
try {
|
|
2746
|
+
if (keepBackup && existsSync4(path)) {
|
|
2747
|
+
rename(path, bakPath);
|
|
2748
|
+
movedOriginalToBackup = true;
|
|
2749
|
+
}
|
|
2750
|
+
rename(tmpPath, path);
|
|
2751
|
+
} catch (err) {
|
|
2752
|
+
try {
|
|
2753
|
+
if (existsSync4(tmpPath))
|
|
2754
|
+
unlinkSync3(tmpPath);
|
|
2755
|
+
} catch {
|
|
2756
|
+
}
|
|
2757
|
+
if (movedOriginalToBackup && !existsSync4(path) && existsSync4(bakPath)) {
|
|
2758
|
+
try {
|
|
2759
|
+
renameSync3(bakPath, path);
|
|
2760
|
+
} catch {
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
throw err;
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2766
|
+
function safeWriteMcpJson(path, config) {
|
|
2767
|
+
const validation = validateRenderedMcpConfig(config);
|
|
2768
|
+
if (!validation.ok) {
|
|
2769
|
+
return { written: false, errors: validation.errors };
|
|
2770
|
+
}
|
|
2771
|
+
safeWriteJsonAtomic(path, JSON.stringify(config, null, 2));
|
|
2772
|
+
return { written: true, errors: [] };
|
|
2773
|
+
}
|
|
2774
|
+
|
|
2640
2775
|
// ../../packages/core/dist/provisioning/frameworks/claudecode/identity.js
|
|
2641
2776
|
function buildMemorySection(hasQmd) {
|
|
2642
2777
|
const recall = hasQmd ? `### Recall
|
|
@@ -3300,7 +3435,7 @@ function migrateLegacyClaudecodeDir(codeName, log) {
|
|
|
3300
3435
|
if (migratedCodeNames.has(codeName))
|
|
3301
3436
|
return;
|
|
3302
3437
|
const legacyRoot = join4(getHomeDir3(), ".augmented", codeName, "claudecode");
|
|
3303
|
-
if (!
|
|
3438
|
+
if (!existsSync5(legacyRoot)) {
|
|
3304
3439
|
migratedCodeNames.add(codeName);
|
|
3305
3440
|
return;
|
|
3306
3441
|
}
|
|
@@ -3318,25 +3453,25 @@ function migrateLegacyClaudecodeDir(codeName, log) {
|
|
|
3318
3453
|
walkAndMigrate(src, dest);
|
|
3319
3454
|
continue;
|
|
3320
3455
|
}
|
|
3321
|
-
if (entry.name === ".mcp.json" &&
|
|
3456
|
+
if (entry.name === ".mcp.json" && existsSync5(dest)) {
|
|
3322
3457
|
try {
|
|
3323
|
-
const oldCfg = JSON.parse(
|
|
3324
|
-
const newCfg = JSON.parse(
|
|
3458
|
+
const oldCfg = JSON.parse(readFileSync5(src, "utf-8"));
|
|
3459
|
+
const newCfg = JSON.parse(readFileSync5(dest, "utf-8"));
|
|
3325
3460
|
const merged = { mcpServers: { ...oldCfg.mcpServers ?? {}, ...newCfg.mcpServers ?? {} } };
|
|
3326
|
-
|
|
3461
|
+
writeFileSync5(dest, JSON.stringify(merged, null, 2));
|
|
3327
3462
|
emit(`[migrate] '${codeName}' merged .mcp.json (${Object.keys(merged.mcpServers).length} servers)`);
|
|
3328
3463
|
} catch (err) {
|
|
3329
3464
|
throw new Error(`Failed merging .mcp.json (${src} \u2192 ${dest}): ${err.message}`);
|
|
3330
3465
|
}
|
|
3331
3466
|
continue;
|
|
3332
3467
|
}
|
|
3333
|
-
if (!
|
|
3468
|
+
if (!existsSync5(dest)) {
|
|
3334
3469
|
copyFileSync(src, dest);
|
|
3335
3470
|
continue;
|
|
3336
3471
|
}
|
|
3337
3472
|
try {
|
|
3338
|
-
const srcStat =
|
|
3339
|
-
const destStat =
|
|
3473
|
+
const srcStat = readFileSync5(src);
|
|
3474
|
+
const destStat = readFileSync5(dest);
|
|
3340
3475
|
if (!srcStat.equals(destStat)) {
|
|
3341
3476
|
}
|
|
3342
3477
|
} catch (err) {
|
|
@@ -3362,38 +3497,69 @@ function syncMcpToProject(codeName) {
|
|
|
3362
3497
|
const provisionMcpPath = join4(agentDir, "provision", ".mcp.json");
|
|
3363
3498
|
const projectMcpPath = join4(projectDir, ".mcp.json");
|
|
3364
3499
|
try {
|
|
3365
|
-
const content =
|
|
3500
|
+
const content = readFileSync5(provisionMcpPath, "utf-8");
|
|
3366
3501
|
mkdirSync4(projectDir, { recursive: true });
|
|
3367
|
-
|
|
3502
|
+
writeFileSync5(projectMcpPath, content);
|
|
3368
3503
|
} catch {
|
|
3369
3504
|
}
|
|
3370
3505
|
renderChannelMessageHandlerForAgent(codeName);
|
|
3371
3506
|
}
|
|
3507
|
+
var INTEGRATIONS_SUMMARY_FILE = "integrations-summary.json";
|
|
3508
|
+
function integrationsSummaryPath(codeName) {
|
|
3509
|
+
return join4(getAgentDir(codeName), "provision", INTEGRATIONS_SUMMARY_FILE);
|
|
3510
|
+
}
|
|
3511
|
+
function writeIntegrationsSummaryForAgent(codeName, summaries) {
|
|
3512
|
+
const target = integrationsSummaryPath(codeName);
|
|
3513
|
+
try {
|
|
3514
|
+
mkdirSync4(dirname4(target), { recursive: true });
|
|
3515
|
+
writeFileSync5(target, JSON.stringify(summaries, null, 2));
|
|
3516
|
+
} catch {
|
|
3517
|
+
}
|
|
3518
|
+
}
|
|
3519
|
+
function readIntegrationsSummaryForAgent(codeName) {
|
|
3520
|
+
try {
|
|
3521
|
+
const raw = readFileSync5(integrationsSummaryPath(codeName), "utf-8");
|
|
3522
|
+
const parsed = JSON.parse(raw);
|
|
3523
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
3524
|
+
} catch {
|
|
3525
|
+
return [];
|
|
3526
|
+
}
|
|
3527
|
+
}
|
|
3372
3528
|
function renderChannelMessageHandlerForAgent(codeName) {
|
|
3373
3529
|
const agentDir = getAgentDir(codeName);
|
|
3374
3530
|
const projectDir = getProjectDir(codeName);
|
|
3375
3531
|
const provisionMcpPath = join4(agentDir, "provision", ".mcp.json");
|
|
3376
3532
|
let mcpServerKeys;
|
|
3377
3533
|
try {
|
|
3378
|
-
const config = JSON.parse(
|
|
3534
|
+
const config = JSON.parse(readFileSync5(provisionMcpPath, "utf-8"));
|
|
3379
3535
|
mcpServerKeys = Object.keys(config.mcpServers ?? {});
|
|
3380
3536
|
} catch {
|
|
3381
3537
|
return;
|
|
3382
3538
|
}
|
|
3383
|
-
const
|
|
3539
|
+
const integrations = readIntegrationsSummaryForAgent(codeName);
|
|
3540
|
+
const content = buildChannelMessageHandlerAgent({ mcpServerKeys, integrations });
|
|
3384
3541
|
for (const baseDir of [agentDir, projectDir]) {
|
|
3385
3542
|
const target = join4(baseDir, ".claude", "agents", "channel-message-handler.md");
|
|
3386
3543
|
try {
|
|
3387
3544
|
mkdirSync4(dirname4(target), { recursive: true });
|
|
3388
|
-
|
|
3545
|
+
writeFileSync5(target, content);
|
|
3389
3546
|
} catch {
|
|
3390
3547
|
}
|
|
3391
3548
|
}
|
|
3392
3549
|
}
|
|
3550
|
+
function writeMcpJsonGuarded(codeName, path, config) {
|
|
3551
|
+
const result = safeWriteMcpJson(path, config);
|
|
3552
|
+
if (!result.written) {
|
|
3553
|
+
process.stderr.write(`[manager-worker] [mcp-validate] skipping write for '${codeName}': ${formatValidationErrors(result.errors)}
|
|
3554
|
+
`);
|
|
3555
|
+
return false;
|
|
3556
|
+
}
|
|
3557
|
+
return true;
|
|
3558
|
+
}
|
|
3393
3559
|
function readExistingMcpEnvVar(codeName, serverId, envKey) {
|
|
3394
3560
|
const mcpJsonPath = join4(getAgentDir(codeName), "provision", ".mcp.json");
|
|
3395
3561
|
try {
|
|
3396
|
-
const raw =
|
|
3562
|
+
const raw = readFileSync5(mcpJsonPath, "utf-8");
|
|
3397
3563
|
const config = JSON.parse(raw);
|
|
3398
3564
|
const server = config.mcpServers?.[serverId];
|
|
3399
3565
|
if (!server || typeof server !== "object")
|
|
@@ -3408,6 +3574,18 @@ function readExistingMcpEnvVar(codeName, serverId, envKey) {
|
|
|
3408
3574
|
return void 0;
|
|
3409
3575
|
}
|
|
3410
3576
|
}
|
|
3577
|
+
var PLACEHOLDER_LITERAL_RE = /\$\{[^}]+\}/;
|
|
3578
|
+
function resolveBrokerAgentId(codeName, fallback) {
|
|
3579
|
+
const existing = readExistingMcpEnvVar(codeName, "cloud-broker", "AGT_AGENT_ID");
|
|
3580
|
+
if (existing && !PLACEHOLDER_LITERAL_RE.test(existing))
|
|
3581
|
+
return existing;
|
|
3582
|
+
const fromAugmented = readExistingMcpEnvVar(codeName, "augmented", "AGT_AGENT_ID");
|
|
3583
|
+
if (fromAugmented && !PLACEHOLDER_LITERAL_RE.test(fromAugmented))
|
|
3584
|
+
return fromAugmented;
|
|
3585
|
+
if (fallback && !PLACEHOLDER_LITERAL_RE.test(fallback))
|
|
3586
|
+
return fallback;
|
|
3587
|
+
return void 0;
|
|
3588
|
+
}
|
|
3411
3589
|
function deployArtifactsToProject(codeName, provisionDir) {
|
|
3412
3590
|
const projectDir = getProjectDir(codeName);
|
|
3413
3591
|
mkdirSync4(projectDir, { recursive: true });
|
|
@@ -3418,27 +3596,27 @@ function deployArtifactsToProject(codeName, provisionDir) {
|
|
|
3418
3596
|
const src = join4(provisionDir, file);
|
|
3419
3597
|
const dest = join4(projectDir, file);
|
|
3420
3598
|
try {
|
|
3421
|
-
const srcContent =
|
|
3422
|
-
if (file === "CLAUDE.md" &&
|
|
3423
|
-
const destContent =
|
|
3599
|
+
const srcContent = readFileSync5(src, "utf-8");
|
|
3600
|
+
if (file === "CLAUDE.md" && existsSync5(dest)) {
|
|
3601
|
+
const destContent = readFileSync5(dest, "utf-8");
|
|
3424
3602
|
const stripIndex = (s) => s.replace(new RegExp(`${SKILLS_START}[\\s\\S]*?${SKILLS_END}`), "").trimEnd();
|
|
3425
3603
|
if (stripIndex(srcContent) === stripIndex(destContent))
|
|
3426
3604
|
continue;
|
|
3427
3605
|
const indexMatch = destContent.match(new RegExp(`${SKILLS_START}[\\s\\S]*?${SKILLS_END}`));
|
|
3428
3606
|
if (indexMatch) {
|
|
3429
|
-
|
|
3607
|
+
writeFileSync5(dest, srcContent.trimEnd() + "\n\n" + indexMatch[0] + "\n");
|
|
3430
3608
|
continue;
|
|
3431
3609
|
}
|
|
3432
3610
|
}
|
|
3433
|
-
|
|
3611
|
+
writeFileSync5(dest, srcContent);
|
|
3434
3612
|
} catch {
|
|
3435
3613
|
}
|
|
3436
3614
|
}
|
|
3437
3615
|
const skillsDir = join4(provisionDir, ".claude", "skills");
|
|
3438
3616
|
const destSkillsDir = join4(projectDir, ".claude", "skills");
|
|
3439
3617
|
try {
|
|
3440
|
-
if (
|
|
3441
|
-
const srcFolders =
|
|
3618
|
+
if (existsSync5(destSkillsDir)) {
|
|
3619
|
+
const srcFolders = existsSync5(skillsDir) ? new Set(readdirSync(skillsDir)) : /* @__PURE__ */ new Set();
|
|
3442
3620
|
for (const folder of readdirSync(destSkillsDir)) {
|
|
3443
3621
|
if (folder.startsWith("knowledge-") || folder === "core-knowledge" && !srcFolders.has(folder)) {
|
|
3444
3622
|
try {
|
|
@@ -3448,21 +3626,21 @@ function deployArtifactsToProject(codeName, provisionDir) {
|
|
|
3448
3626
|
}
|
|
3449
3627
|
}
|
|
3450
3628
|
}
|
|
3451
|
-
if (
|
|
3629
|
+
if (existsSync5(skillsDir)) {
|
|
3452
3630
|
for (const skillFolder of readdirSync(skillsDir)) {
|
|
3453
3631
|
const srcSkillFile = join4(skillsDir, skillFolder, "SKILL.md");
|
|
3454
|
-
if (!
|
|
3632
|
+
if (!existsSync5(srcSkillFile))
|
|
3455
3633
|
continue;
|
|
3456
3634
|
const destFolder = join4(destSkillsDir, skillFolder);
|
|
3457
3635
|
const destFile = join4(destFolder, "SKILL.md");
|
|
3458
|
-
const srcContent =
|
|
3636
|
+
const srcContent = readFileSync5(srcSkillFile, "utf-8");
|
|
3459
3637
|
try {
|
|
3460
|
-
if (
|
|
3638
|
+
if (existsSync5(destFile) && readFileSync5(destFile, "utf-8") === srcContent)
|
|
3461
3639
|
continue;
|
|
3462
3640
|
} catch {
|
|
3463
3641
|
}
|
|
3464
3642
|
mkdirSync4(destFolder, { recursive: true });
|
|
3465
|
-
|
|
3643
|
+
writeFileSync5(destFile, srcContent);
|
|
3466
3644
|
}
|
|
3467
3645
|
}
|
|
3468
3646
|
} catch {
|
|
@@ -3470,9 +3648,9 @@ function deployArtifactsToProject(codeName, provisionDir) {
|
|
|
3470
3648
|
const agentsDir = join4(provisionDir, ".claude", "agents");
|
|
3471
3649
|
const destAgentsDir = join4(projectDir, ".claude", "agents");
|
|
3472
3650
|
try {
|
|
3473
|
-
if (
|
|
3651
|
+
if (existsSync5(agentsDir)) {
|
|
3474
3652
|
const sourceAgentFiles = new Set(readdirSync(agentsDir).filter((f) => f.endsWith(".md")));
|
|
3475
|
-
if (
|
|
3653
|
+
if (existsSync5(destAgentsDir)) {
|
|
3476
3654
|
for (const destFile of readdirSync(destAgentsDir)) {
|
|
3477
3655
|
if (!destFile.endsWith(".md"))
|
|
3478
3656
|
continue;
|
|
@@ -3487,14 +3665,14 @@ function deployArtifactsToProject(codeName, provisionDir) {
|
|
|
3487
3665
|
for (const agentFile of sourceAgentFiles) {
|
|
3488
3666
|
const srcPath = join4(agentsDir, agentFile);
|
|
3489
3667
|
const destPath = join4(destAgentsDir, agentFile);
|
|
3490
|
-
const srcContent =
|
|
3668
|
+
const srcContent = readFileSync5(srcPath, "utf-8");
|
|
3491
3669
|
try {
|
|
3492
|
-
if (
|
|
3670
|
+
if (existsSync5(destPath) && readFileSync5(destPath, "utf-8") === srcContent)
|
|
3493
3671
|
continue;
|
|
3494
3672
|
} catch {
|
|
3495
3673
|
}
|
|
3496
3674
|
mkdirSync4(destAgentsDir, { recursive: true });
|
|
3497
|
-
|
|
3675
|
+
writeFileSync5(destPath, srcContent);
|
|
3498
3676
|
}
|
|
3499
3677
|
}
|
|
3500
3678
|
} catch {
|
|
@@ -3502,10 +3680,10 @@ function deployArtifactsToProject(codeName, provisionDir) {
|
|
|
3502
3680
|
const agentMcpPath = join4(getAgentDir(codeName), "provision", ".mcp.json");
|
|
3503
3681
|
const projectMcpPath = join4(projectDir, ".mcp.json");
|
|
3504
3682
|
try {
|
|
3505
|
-
const agentMcp = JSON.parse(
|
|
3683
|
+
const agentMcp = JSON.parse(readFileSync5(agentMcpPath, "utf-8"));
|
|
3506
3684
|
let projectMcp;
|
|
3507
3685
|
try {
|
|
3508
|
-
projectMcp = JSON.parse(
|
|
3686
|
+
projectMcp = JSON.parse(readFileSync5(projectMcpPath, "utf-8"));
|
|
3509
3687
|
} catch {
|
|
3510
3688
|
projectMcp = { mcpServers: {} };
|
|
3511
3689
|
}
|
|
@@ -3516,28 +3694,28 @@ function deployArtifactsToProject(codeName, provisionDir) {
|
|
|
3516
3694
|
return !(entry && typeof entry["url"] === "string" && entry["url"].startsWith("/"));
|
|
3517
3695
|
}));
|
|
3518
3696
|
projectMcp["mcpServers"] = { ...stripRelativeUrls(projectServers), ...stripRelativeUrls(agentServers) };
|
|
3519
|
-
|
|
3697
|
+
writeFileSync5(projectMcpPath, JSON.stringify(projectMcp, null, 2));
|
|
3520
3698
|
} catch {
|
|
3521
3699
|
}
|
|
3522
3700
|
const agentDir = getAgentDir(codeName);
|
|
3523
3701
|
for (const envFile of [".env", ".env.integrations"]) {
|
|
3524
3702
|
try {
|
|
3525
|
-
const content =
|
|
3526
|
-
|
|
3703
|
+
const content = readFileSync5(join4(agentDir, envFile), "utf-8");
|
|
3704
|
+
writeFileSync5(join4(projectDir, envFile), content);
|
|
3527
3705
|
} catch {
|
|
3528
3706
|
}
|
|
3529
3707
|
}
|
|
3530
3708
|
try {
|
|
3531
3709
|
const gitDir = join4(projectDir, ".git");
|
|
3532
3710
|
const hookSrc = join4(provisionDir, ".git-hooks", "pre-commit");
|
|
3533
|
-
if (
|
|
3711
|
+
if (existsSync5(gitDir) && existsSync5(hookSrc)) {
|
|
3534
3712
|
const hooksDir = join4(gitDir, "hooks");
|
|
3535
3713
|
mkdirSync4(hooksDir, { recursive: true });
|
|
3536
3714
|
const hookDest = join4(hooksDir, "pre-commit");
|
|
3537
|
-
const srcContent =
|
|
3538
|
-
const upToDate =
|
|
3715
|
+
const srcContent = readFileSync5(hookSrc, "utf-8");
|
|
3716
|
+
const upToDate = existsSync5(hookDest) && readFileSync5(hookDest, "utf-8") === srcContent;
|
|
3539
3717
|
if (!upToDate)
|
|
3540
|
-
|
|
3718
|
+
writeFileSync5(hookDest, srcContent);
|
|
3541
3719
|
chmodSync4(hookDest, 493);
|
|
3542
3720
|
}
|
|
3543
3721
|
} catch {
|
|
@@ -3578,7 +3756,7 @@ function provisionStopHook(codeName) {
|
|
|
3578
3756
|
"esac",
|
|
3579
3757
|
"exit 0"
|
|
3580
3758
|
].join("\n") + "\n";
|
|
3581
|
-
|
|
3759
|
+
writeFileSync5(hookScriptPath, hookScript, { mode: 493 });
|
|
3582
3760
|
const ghostHookPath = join4(claudeDir, "agt-ghost-reply-hook.sh");
|
|
3583
3761
|
const ghostHookScript = [
|
|
3584
3762
|
"#!/bin/bash",
|
|
@@ -3698,11 +3876,11 @@ function provisionStopHook(codeName) {
|
|
|
3698
3876
|
"fi",
|
|
3699
3877
|
"exit 0"
|
|
3700
3878
|
].join("\n") + "\n";
|
|
3701
|
-
|
|
3879
|
+
writeFileSync5(ghostHookPath, ghostHookScript, { mode: 493 });
|
|
3702
3880
|
const settingsPath = join4(claudeDir, "settings.local.json");
|
|
3703
3881
|
let settings = {};
|
|
3704
3882
|
try {
|
|
3705
|
-
settings = JSON.parse(
|
|
3883
|
+
settings = JSON.parse(readFileSync5(settingsPath, "utf-8"));
|
|
3706
3884
|
} catch {
|
|
3707
3885
|
}
|
|
3708
3886
|
const hooks = settings["hooks"] ?? {};
|
|
@@ -3715,7 +3893,7 @@ function provisionStopHook(codeName) {
|
|
|
3715
3893
|
}
|
|
3716
3894
|
];
|
|
3717
3895
|
settings["hooks"] = hooks;
|
|
3718
|
-
|
|
3896
|
+
writeFileSync5(settingsPath, JSON.stringify(settings, null, 2));
|
|
3719
3897
|
}
|
|
3720
3898
|
function provisionIsolationHook(codeName) {
|
|
3721
3899
|
const projectDir = getProjectDir(codeName);
|
|
@@ -3778,11 +3956,11 @@ function provisionIsolationHook(codeName) {
|
|
|
3778
3956
|
"",
|
|
3779
3957
|
"exit 0"
|
|
3780
3958
|
].join("\n") + "\n";
|
|
3781
|
-
|
|
3959
|
+
writeFileSync5(hookScriptPath, hookScript, { mode: 493 });
|
|
3782
3960
|
const settingsPath = join4(claudeDir, "settings.local.json");
|
|
3783
3961
|
let settings = {};
|
|
3784
3962
|
try {
|
|
3785
|
-
settings = JSON.parse(
|
|
3963
|
+
settings = JSON.parse(readFileSync5(settingsPath, "utf-8"));
|
|
3786
3964
|
} catch {
|
|
3787
3965
|
}
|
|
3788
3966
|
const hooks = settings["hooks"] ?? {};
|
|
@@ -3797,13 +3975,13 @@ function provisionIsolationHook(codeName) {
|
|
|
3797
3975
|
}
|
|
3798
3976
|
];
|
|
3799
3977
|
settings["hooks"] = hooks;
|
|
3800
|
-
|
|
3978
|
+
writeFileSync5(settingsPath, JSON.stringify(settings, null, 2));
|
|
3801
3979
|
}
|
|
3802
3980
|
function modifyJsonConfig(filePath, fn) {
|
|
3803
3981
|
let originalContent;
|
|
3804
3982
|
let config;
|
|
3805
3983
|
try {
|
|
3806
|
-
originalContent =
|
|
3984
|
+
originalContent = readFileSync5(filePath, "utf-8");
|
|
3807
3985
|
config = JSON.parse(originalContent);
|
|
3808
3986
|
} catch {
|
|
3809
3987
|
return;
|
|
@@ -3814,7 +3992,7 @@ function modifyJsonConfig(filePath, fn) {
|
|
|
3814
3992
|
const newContent = JSON.stringify(config, null, 2);
|
|
3815
3993
|
if (newContent === originalContent)
|
|
3816
3994
|
return;
|
|
3817
|
-
|
|
3995
|
+
writeFileSync5(filePath, newContent);
|
|
3818
3996
|
}
|
|
3819
3997
|
var SECRETS_DENY_PERMISSIONS = [
|
|
3820
3998
|
// Read blocks
|
|
@@ -3925,6 +4103,7 @@ function sanitizeMcpName(name) {
|
|
|
3925
4103
|
}
|
|
3926
4104
|
function buildChannelMessageHandlerAgent(args) {
|
|
3927
4105
|
const mcpServerKeys = args?.mcpServerKeys ?? [];
|
|
4106
|
+
const integrations = args?.integrations ?? [];
|
|
3928
4107
|
const mcpWildcards = Array.from(new Set(mcpServerKeys.map((k) => `mcp__${sanitizeMcpName(k)}__*`)));
|
|
3929
4108
|
const tools = [
|
|
3930
4109
|
"Bash",
|
|
@@ -3937,6 +4116,19 @@ function buildChannelMessageHandlerAgent(args) {
|
|
|
3937
4116
|
"Agent",
|
|
3938
4117
|
...mcpWildcards
|
|
3939
4118
|
].join(", ");
|
|
4119
|
+
const integrationsBlock = integrations.length === 0 ? "" : `
|
|
4120
|
+
## Integrations available
|
|
4121
|
+
|
|
4122
|
+
You inherit the parent agent's environment, including credentials for the integrations below. Env vars follow the convention \`<DEFINITION_ID>_ACCESS_TOKEN\` for OAuth and \`<DEFINITION_ID>_API_KEY\` for API-key integrations (e.g. \`GITHUB_ACCESS_TOKEN\`, \`POSTIZ_API_KEY\`). Where a CLI is listed, prefer it over raw curl \u2014 the CLI handles auth automatically.
|
|
4123
|
+
|
|
4124
|
+
${integrations.map((i) => {
|
|
4125
|
+
const cli = i.cliBinary ? ` \u2014 use the \`${i.cliBinary}\` CLI` : "";
|
|
4126
|
+
const desc = i.description ? `. ${i.description}` : "";
|
|
4127
|
+
return `- **${i.name}**${cli}${desc}`;
|
|
4128
|
+
}).join("\n")}
|
|
4129
|
+
|
|
4130
|
+
If asked about your capabilities, **check first** (run the CLI, echo the env var, or invoke an MCP tool) before answering. Do not claim a capability is absent without verifying \u2014 the parent's environment is yours.
|
|
4131
|
+
`;
|
|
3940
4132
|
return `---
|
|
3941
4133
|
name: channel-message-handler
|
|
3942
4134
|
description: Handles a single inbound Slack/Telegram/Direct-Chat message end to end. Posts the reply itself via the matching channel tool. The parent agent dispatches to this subagent only for slow requests (\u2265 ~60s) so the parent's listener turn stays free for new inbound work.
|
|
@@ -3958,7 +4150,7 @@ Your job:
|
|
|
3958
4150
|
3. End. Do not do additional follow-up work; if more is needed, the user will send another message.
|
|
3959
4151
|
|
|
3960
4152
|
Do NOT post intermediate progress updates unless the work spans 5+ minutes \u2014 keep noise low. The parent already sent a single-line acknowledgement before dispatching you.
|
|
3961
|
-
`;
|
|
4153
|
+
${integrationsBlock}`;
|
|
3962
4154
|
}
|
|
3963
4155
|
function buildPostizMcpEntry(integration) {
|
|
3964
4156
|
const rawBaseUrl = integration.config["base_url"];
|
|
@@ -4148,9 +4340,19 @@ var claudeCodeAdapter = {
|
|
|
4148
4340
|
// turn return immediately on dispatch, so new inbound messages get a
|
|
4149
4341
|
// fresh turn while the subagent does the work in parallel. Triggered
|
|
4150
4342
|
// by the "Channel message triage" instruction in CLAUDE.md.
|
|
4343
|
+
// ENG-4821: integrations are rendered into the subagent body so it
|
|
4344
|
+
// stops claiming "no creds" for capabilities the parent has — and the
|
|
4345
|
+
// sidecar JSON keeps incremental writeIntegrations syncs in lockstep.
|
|
4151
4346
|
{
|
|
4152
4347
|
relativePath: ".claude/agents/channel-message-handler.md",
|
|
4153
|
-
content: buildChannelMessageHandlerAgent({
|
|
4348
|
+
content: buildChannelMessageHandlerAgent({
|
|
4349
|
+
mcpServerKeys: initialMcpServerKeys,
|
|
4350
|
+
integrations: integrationSummaries
|
|
4351
|
+
})
|
|
4352
|
+
},
|
|
4353
|
+
{
|
|
4354
|
+
relativePath: `provision/${INTEGRATIONS_SUMMARY_FILE}`,
|
|
4355
|
+
content: JSON.stringify(integrationSummaries, null, 2)
|
|
4154
4356
|
}
|
|
4155
4357
|
];
|
|
4156
4358
|
const knowledgeEntries = input.knowledge ?? [];
|
|
@@ -4205,7 +4407,7 @@ ${sections}`
|
|
|
4205
4407
|
} catch {
|
|
4206
4408
|
continue;
|
|
4207
4409
|
}
|
|
4208
|
-
if (
|
|
4410
|
+
if (existsSync5(join4(agentRoot, "registration.json"))) {
|
|
4209
4411
|
agents.add(entry);
|
|
4210
4412
|
}
|
|
4211
4413
|
}
|
|
@@ -4219,14 +4421,14 @@ ${sections}`
|
|
|
4219
4421
|
const projectDir = getProjectDir(codeName);
|
|
4220
4422
|
mkdirSync4(agentDir, { recursive: true });
|
|
4221
4423
|
mkdirSync4(projectDir, { recursive: true });
|
|
4222
|
-
|
|
4424
|
+
writeFileSync5(join4(agentDir, "registration.json"), JSON.stringify({
|
|
4223
4425
|
code_name: codeName,
|
|
4224
4426
|
team_dir: teamDir,
|
|
4225
4427
|
project_dir: projectDir,
|
|
4226
4428
|
framework: "claude-code",
|
|
4227
4429
|
registered_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
4228
4430
|
}, null, 2));
|
|
4229
|
-
if (
|
|
4431
|
+
if (existsSync5(teamDir)) {
|
|
4230
4432
|
deployArtifactsToProject(codeName, teamDir);
|
|
4231
4433
|
}
|
|
4232
4434
|
return true;
|
|
@@ -4238,9 +4440,9 @@ ${sections}`
|
|
|
4238
4440
|
try {
|
|
4239
4441
|
const agentDir = getAgentDir(codeName);
|
|
4240
4442
|
const regFile = join4(agentDir, "registration.json");
|
|
4241
|
-
if (
|
|
4242
|
-
const { unlinkSync:
|
|
4243
|
-
|
|
4443
|
+
if (existsSync5(regFile)) {
|
|
4444
|
+
const { unlinkSync: unlinkSync5 } = await import("fs");
|
|
4445
|
+
unlinkSync5(regFile);
|
|
4244
4446
|
}
|
|
4245
4447
|
return true;
|
|
4246
4448
|
} catch {
|
|
@@ -4264,7 +4466,7 @@ ${sections}`
|
|
|
4264
4466
|
}
|
|
4265
4467
|
if (envLines.length > 1) {
|
|
4266
4468
|
const envPath = join4(agentDir, ".env");
|
|
4267
|
-
|
|
4469
|
+
writeFileSync5(envPath, envLines.join("\n") + "\n");
|
|
4268
4470
|
chmodSync4(envPath, SECRET_FILE_MODE);
|
|
4269
4471
|
}
|
|
4270
4472
|
},
|
|
@@ -4313,13 +4515,15 @@ ${sections}`
|
|
|
4313
4515
|
mkdirSync4(dirname4(provisionMcpPath), { recursive: true });
|
|
4314
4516
|
let mcpConfig2 = { mcpServers: {} };
|
|
4315
4517
|
try {
|
|
4316
|
-
mcpConfig2 = JSON.parse(
|
|
4518
|
+
mcpConfig2 = JSON.parse(readFileSync5(provisionMcpPath, "utf-8"));
|
|
4317
4519
|
if (!mcpConfig2.mcpServers)
|
|
4318
4520
|
mcpConfig2.mcpServers = {};
|
|
4319
4521
|
} catch {
|
|
4320
4522
|
}
|
|
4321
4523
|
mcpConfig2.mcpServers["telegram"] = telegramEntry;
|
|
4322
|
-
|
|
4524
|
+
if (!writeMcpJsonGuarded(codeName, provisionMcpPath, mcpConfig2)) {
|
|
4525
|
+
return;
|
|
4526
|
+
}
|
|
4323
4527
|
syncMcpToProject(codeName);
|
|
4324
4528
|
return;
|
|
4325
4529
|
}
|
|
@@ -4330,7 +4534,7 @@ ${sections}`
|
|
|
4330
4534
|
if (channelId === "discord") {
|
|
4331
4535
|
const botToken = config["bot_token"];
|
|
4332
4536
|
if (botToken) {
|
|
4333
|
-
|
|
4537
|
+
writeFileSync5(join4(channelDir, ".env"), `DISCORD_BOT_TOKEN=${botToken}
|
|
4334
4538
|
`);
|
|
4335
4539
|
}
|
|
4336
4540
|
} else if (channelId === "slack") {
|
|
@@ -4353,8 +4557,8 @@ ${sections}`
|
|
|
4353
4557
|
if (botToken) {
|
|
4354
4558
|
const localSlackChannel = join4(getHomeDir3(), ".augmented", "_mcp", "slack-channel.js");
|
|
4355
4559
|
const slackEntry = {
|
|
4356
|
-
command:
|
|
4357
|
-
args:
|
|
4560
|
+
command: existsSync5(localSlackChannel) ? "node" : "npx",
|
|
4561
|
+
args: existsSync5(localSlackChannel) ? [localSlackChannel] : ["-y", "@augmented/claude-code-channel-slack"],
|
|
4358
4562
|
env: {
|
|
4359
4563
|
SLACK_BOT_TOKEN: botToken,
|
|
4360
4564
|
...appToken ? { SLACK_APP_TOKEN: appToken } : {},
|
|
@@ -4372,16 +4576,18 @@ ${sections}`
|
|
|
4372
4576
|
mkdirSync4(dirname4(provisionMcpPath), { recursive: true });
|
|
4373
4577
|
let mcpConfig2 = { mcpServers: {} };
|
|
4374
4578
|
try {
|
|
4375
|
-
mcpConfig2 = JSON.parse(
|
|
4579
|
+
mcpConfig2 = JSON.parse(readFileSync5(provisionMcpPath, "utf-8"));
|
|
4376
4580
|
if (!mcpConfig2.mcpServers)
|
|
4377
4581
|
mcpConfig2.mcpServers = {};
|
|
4378
4582
|
} catch {
|
|
4379
4583
|
}
|
|
4380
4584
|
mcpConfig2.mcpServers["slack"] = slackEntry;
|
|
4381
|
-
|
|
4585
|
+
if (!writeMcpJsonGuarded(codeName, provisionMcpPath, mcpConfig2)) {
|
|
4586
|
+
return;
|
|
4587
|
+
}
|
|
4382
4588
|
syncMcpToProject(codeName);
|
|
4383
4589
|
const staleChannelsPath = join4(getProjectDir(codeName), ".mcp-channels.json");
|
|
4384
|
-
if (
|
|
4590
|
+
if (existsSync5(staleChannelsPath)) {
|
|
4385
4591
|
try {
|
|
4386
4592
|
rmSync(staleChannelsPath, { force: true });
|
|
4387
4593
|
} catch {
|
|
@@ -4394,7 +4600,7 @@ ${sections}`
|
|
|
4394
4600
|
const mcpJsonPath = join4(agentDir, "provision", ".mcp.json");
|
|
4395
4601
|
let mcpConfig;
|
|
4396
4602
|
try {
|
|
4397
|
-
mcpConfig = JSON.parse(
|
|
4603
|
+
mcpConfig = JSON.parse(readFileSync5(mcpJsonPath, "utf-8"));
|
|
4398
4604
|
} catch {
|
|
4399
4605
|
mcpConfig = { mcpServers: {} };
|
|
4400
4606
|
}
|
|
@@ -4430,7 +4636,7 @@ ${sections}`
|
|
|
4430
4636
|
...oneshotBlockKitAskUserEnabled && process.env["AGT_API_KEY"] ? { AGT_API_KEY: process.env["AGT_API_KEY"] } : {},
|
|
4431
4637
|
...oneshotBlockKitAskUserEnabled && options?.agentId ? { AGT_AGENT_ID: options.agentId } : {}
|
|
4432
4638
|
} : {};
|
|
4433
|
-
if (isPersistent &&
|
|
4639
|
+
if (isPersistent && existsSync5(localSlackChannel)) {
|
|
4434
4640
|
mcpServers["slack"] = {
|
|
4435
4641
|
command: "node",
|
|
4436
4642
|
args: [localSlackChannel],
|
|
@@ -4456,15 +4662,16 @@ ${sections}`
|
|
|
4456
4662
|
};
|
|
4457
4663
|
}
|
|
4458
4664
|
}
|
|
4459
|
-
|
|
4460
|
-
|
|
4665
|
+
if (writeMcpJsonGuarded(codeName, mcpJsonPath, mcpConfig)) {
|
|
4666
|
+
syncMcpToProject(codeName);
|
|
4667
|
+
}
|
|
4461
4668
|
},
|
|
4462
4669
|
hasChannelCredentials(codeName, channelId) {
|
|
4463
4670
|
const provisionMcpPath = join4(getAgentDir(codeName), "provision", ".mcp.json");
|
|
4464
|
-
if (!
|
|
4671
|
+
if (!existsSync5(provisionMcpPath))
|
|
4465
4672
|
return false;
|
|
4466
4673
|
try {
|
|
4467
|
-
const parsed = JSON.parse(
|
|
4674
|
+
const parsed = JSON.parse(readFileSync5(provisionMcpPath, "utf-8"));
|
|
4468
4675
|
return Boolean(parsed.mcpServers?.[channelId]);
|
|
4469
4676
|
} catch {
|
|
4470
4677
|
return false;
|
|
@@ -4504,12 +4711,22 @@ ${sections}`
|
|
|
4504
4711
|
const schedulesPath = join4(agentDir, "schedules.json");
|
|
4505
4712
|
const mapped = mapScheduledTasks(tasks);
|
|
4506
4713
|
mkdirSync4(agentDir, { recursive: true });
|
|
4507
|
-
|
|
4714
|
+
writeFileSync5(schedulesPath, JSON.stringify({ schedules: mapped }, null, 2));
|
|
4508
4715
|
return Promise.resolve();
|
|
4509
4716
|
},
|
|
4510
4717
|
writeIntegrations(codeName, integrations) {
|
|
4511
4718
|
const agentDir = getAgentDir(codeName);
|
|
4512
4719
|
mkdirSync4(agentDir, { recursive: true });
|
|
4720
|
+
const summariesForSidecar = integrations.map((i) => {
|
|
4721
|
+
const def = INTEGRATION_REGISTRY.find((d) => d.id === i.definition_id);
|
|
4722
|
+
return {
|
|
4723
|
+
id: i.definition_id,
|
|
4724
|
+
name: def?.name || i.display_name || i.definition_id,
|
|
4725
|
+
cliBinary: def?.cli_tool?.binary,
|
|
4726
|
+
description: def?.description || (i.auth_type === "managed" ? "Managed integration via Composio" : void 0)
|
|
4727
|
+
};
|
|
4728
|
+
});
|
|
4729
|
+
writeIntegrationsSummaryForAgent(codeName, summariesForSidecar);
|
|
4513
4730
|
const decryptedIntegrations = integrations.map((integration) => ({
|
|
4514
4731
|
...integration,
|
|
4515
4732
|
credentials: decryptIntegrationCredentials(integration.credentials)
|
|
@@ -4542,7 +4759,7 @@ ${sections}`
|
|
|
4542
4759
|
}
|
|
4543
4760
|
if (envLines.length > 1) {
|
|
4544
4761
|
const envPath = join4(agentDir, ".env.integrations");
|
|
4545
|
-
|
|
4762
|
+
writeFileSync5(envPath, envLines.join("\n") + "\n");
|
|
4546
4763
|
chmodSync4(envPath, SECRET_FILE_MODE);
|
|
4547
4764
|
}
|
|
4548
4765
|
writeXurlStoreForIntegrations(decryptedIntegrations);
|
|
@@ -4574,53 +4791,50 @@ ${sections}`
|
|
|
4574
4791
|
}
|
|
4575
4792
|
const hasCloudBroker = integrations.some((i) => i.definition_id === "cloud-broker");
|
|
4576
4793
|
if (hasCloudBroker) {
|
|
4577
|
-
const
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4794
|
+
const brokerAgentId = resolveBrokerAgentId(codeName);
|
|
4795
|
+
if (!brokerAgentId) {
|
|
4796
|
+
process.stderr.write(`[manager-worker] [cloud-broker] skipping write for '${codeName}': no real AGT_AGENT_ID available (no existing broker entry, no augmented entry to copy from). The full-provision artifact pipeline will recreate this on the next cycle.
|
|
4797
|
+
`);
|
|
4798
|
+
} else {
|
|
4799
|
+
this.writeMcpServer(codeName, "cloud-broker", {
|
|
4800
|
+
command: "npx",
|
|
4801
|
+
args: ["-y", "@integrity-labs/cloud-broker@latest"],
|
|
4802
|
+
env: {
|
|
4803
|
+
AGT_HOST: "${AGT_HOST}",
|
|
4804
|
+
AGT_API_KEY: "${AGT_API_KEY}",
|
|
4805
|
+
AGT_AGENT_ID: brokerAgentId,
|
|
4806
|
+
// ENG-4788: cloud-broker@0.6+ exits at startup if AGT_RUN_ID
|
|
4807
|
+
// is missing. Mirror buildMcpJson's entry on incremental sync
|
|
4808
|
+
// so an agent that connects AWS post-provision boots cleanly.
|
|
4809
|
+
AGT_RUN_ID: "${AGT_RUN_ID}",
|
|
4810
|
+
PATH: process.env["PATH"] ?? "",
|
|
4811
|
+
HOME: process.env["HOME"] ?? ""
|
|
4812
|
+
}
|
|
4813
|
+
});
|
|
4814
|
+
}
|
|
4593
4815
|
}
|
|
4594
4816
|
const projectDir = getProjectDir(codeName);
|
|
4595
4817
|
const claudeMdPath = join4(projectDir, "CLAUDE.md");
|
|
4596
4818
|
try {
|
|
4597
|
-
const existing =
|
|
4598
|
-
const
|
|
4599
|
-
const def = INTEGRATION_REGISTRY.find((d) => d.id === i.definition_id);
|
|
4600
|
-
return {
|
|
4601
|
-
id: i.definition_id,
|
|
4602
|
-
name: def?.name || i.display_name || i.definition_id,
|
|
4603
|
-
cliBinary: def?.cli_tool?.binary,
|
|
4604
|
-
description: def?.description || (i.auth_type === "managed" ? "Managed integration via Composio" : void 0)
|
|
4605
|
-
};
|
|
4606
|
-
});
|
|
4607
|
-
const newSection = buildIntegrationsSection(summaries);
|
|
4819
|
+
const existing = readFileSync5(claudeMdPath, "utf-8");
|
|
4820
|
+
const newSection = buildIntegrationsSection(summariesForSidecar);
|
|
4608
4821
|
let updated;
|
|
4609
4822
|
if (existing.includes("## Integrations")) {
|
|
4610
4823
|
updated = existing.replace(/## Integrations[\s\S]*?(?=## Rules)/, newSection);
|
|
4611
4824
|
} else {
|
|
4612
4825
|
updated = existing.replace("## Rules", `${newSection}## Rules`);
|
|
4613
4826
|
}
|
|
4614
|
-
|
|
4827
|
+
writeFileSync5(claudeMdPath, updated);
|
|
4615
4828
|
const agentDir2 = getAgentDir(codeName);
|
|
4616
4829
|
const envSrc = join4(agentDir2, ".env.integrations");
|
|
4617
4830
|
try {
|
|
4618
|
-
const envContent =
|
|
4619
|
-
|
|
4831
|
+
const envContent = readFileSync5(envSrc, "utf-8");
|
|
4832
|
+
writeFileSync5(join4(projectDir, ".env.integrations"), envContent);
|
|
4620
4833
|
} catch {
|
|
4621
4834
|
}
|
|
4622
4835
|
} catch {
|
|
4623
4836
|
}
|
|
4837
|
+
renderChannelMessageHandlerForAgent(codeName);
|
|
4624
4838
|
},
|
|
4625
4839
|
writeMcpServer(codeName, serverId, config) {
|
|
4626
4840
|
const agentDir = getAgentDir(codeName);
|
|
@@ -4628,7 +4842,7 @@ ${sections}`
|
|
|
4628
4842
|
mkdirSync4(join4(agentDir, "provision"), { recursive: true });
|
|
4629
4843
|
let mcpConfig;
|
|
4630
4844
|
try {
|
|
4631
|
-
mcpConfig = JSON.parse(
|
|
4845
|
+
mcpConfig = JSON.parse(readFileSync5(mcpJsonPath, "utf-8"));
|
|
4632
4846
|
} catch {
|
|
4633
4847
|
mcpConfig = { mcpServers: {} };
|
|
4634
4848
|
}
|
|
@@ -4680,8 +4894,9 @@ ${sections}`
|
|
|
4680
4894
|
serverEntry["env"] = config.env;
|
|
4681
4895
|
}
|
|
4682
4896
|
mcpServers[serverId] = serverEntry;
|
|
4683
|
-
|
|
4684
|
-
|
|
4897
|
+
if (writeMcpJsonGuarded(codeName, mcpJsonPath, mcpConfig)) {
|
|
4898
|
+
syncMcpToProject(codeName);
|
|
4899
|
+
}
|
|
4685
4900
|
},
|
|
4686
4901
|
getMcpPath(codeName) {
|
|
4687
4902
|
return join4(getAgentDir(codeName), "provision", ".mcp.json");
|
|
@@ -4691,7 +4906,7 @@ ${sections}`
|
|
|
4691
4906
|
const mcpJsonPath = join4(agentDir, "provision", ".mcp.json");
|
|
4692
4907
|
let mcpConfig;
|
|
4693
4908
|
try {
|
|
4694
|
-
mcpConfig = JSON.parse(
|
|
4909
|
+
mcpConfig = JSON.parse(readFileSync5(mcpJsonPath, "utf-8"));
|
|
4695
4910
|
} catch {
|
|
4696
4911
|
return;
|
|
4697
4912
|
}
|
|
@@ -4699,8 +4914,9 @@ ${sections}`
|
|
|
4699
4914
|
if (!mcpServers || !(serverId in mcpServers))
|
|
4700
4915
|
return;
|
|
4701
4916
|
delete mcpServers[serverId];
|
|
4702
|
-
|
|
4703
|
-
|
|
4917
|
+
if (writeMcpJsonGuarded(codeName, mcpJsonPath, mcpConfig)) {
|
|
4918
|
+
syncMcpToProject(codeName);
|
|
4919
|
+
}
|
|
4704
4920
|
},
|
|
4705
4921
|
installSkillFiles(codeName, skillId, files) {
|
|
4706
4922
|
assertValidCodeName(skillId);
|
|
@@ -4720,13 +4936,13 @@ ${sections}`
|
|
|
4720
4936
|
throw new Error(`Path traversal detected: ${file.relativePath} resolves outside ${skillDir}`);
|
|
4721
4937
|
}
|
|
4722
4938
|
mkdirSync4(join4(filePath, ".."), { recursive: true });
|
|
4723
|
-
if (isPluginManaged &&
|
|
4939
|
+
if (isPluginManaged && existsSync5(filePath)) {
|
|
4724
4940
|
try {
|
|
4725
4941
|
chmodSync4(filePath, READ_WRITE_MODE);
|
|
4726
4942
|
} catch {
|
|
4727
4943
|
}
|
|
4728
4944
|
}
|
|
4729
|
-
|
|
4945
|
+
writeFileSync5(filePath, file.content);
|
|
4730
4946
|
if (isPluginManaged) {
|
|
4731
4947
|
try {
|
|
4732
4948
|
chmodSync4(filePath, READ_ONLY_MODE);
|
|
@@ -4742,7 +4958,7 @@ ${sections}`
|
|
|
4742
4958
|
mkdirSync4(agentDir, { recursive: true });
|
|
4743
4959
|
let pluginsConfig;
|
|
4744
4960
|
try {
|
|
4745
|
-
pluginsConfig = JSON.parse(
|
|
4961
|
+
pluginsConfig = JSON.parse(readFileSync5(pluginsJsonPath, "utf-8"));
|
|
4746
4962
|
} catch {
|
|
4747
4963
|
pluginsConfig = { plugins: {} };
|
|
4748
4964
|
}
|
|
@@ -4755,7 +4971,7 @@ ${sections}`
|
|
|
4755
4971
|
installed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4756
4972
|
...pluginConfig ? { config: pluginConfig } : {}
|
|
4757
4973
|
};
|
|
4758
|
-
|
|
4974
|
+
writeFileSync5(pluginsJsonPath, JSON.stringify(pluginsConfig, null, 2));
|
|
4759
4975
|
},
|
|
4760
4976
|
/**
|
|
4761
4977
|
* Full plugin provisioning: install scripts, register hooks, apply permissions,
|
|
@@ -4790,7 +5006,7 @@ ${sections}`
|
|
|
4790
5006
|
const settingsPath = join4(claudeDir, "settings.local.json");
|
|
4791
5007
|
let settings = {};
|
|
4792
5008
|
try {
|
|
4793
|
-
settings = JSON.parse(
|
|
5009
|
+
settings = JSON.parse(readFileSync5(settingsPath, "utf-8"));
|
|
4794
5010
|
} catch {
|
|
4795
5011
|
}
|
|
4796
5012
|
const existingHooks = settings["hooks"] ?? {};
|
|
@@ -4824,13 +5040,13 @@ ${sections}`
|
|
|
4824
5040
|
}
|
|
4825
5041
|
}
|
|
4826
5042
|
settings["hooks"] = existingHooks;
|
|
4827
|
-
|
|
5043
|
+
writeFileSync5(settingsPath, JSON.stringify(settings, null, 2));
|
|
4828
5044
|
}
|
|
4829
5045
|
if (plugin.allowed_tools.length > 0) {
|
|
4830
5046
|
const settingsPath = join4(claudeDir, "settings.local.json");
|
|
4831
5047
|
let settings = {};
|
|
4832
5048
|
try {
|
|
4833
|
-
settings = JSON.parse(
|
|
5049
|
+
settings = JSON.parse(readFileSync5(settingsPath, "utf-8"));
|
|
4834
5050
|
} catch {
|
|
4835
5051
|
}
|
|
4836
5052
|
const existingPerms = settings["permissions"] ?? {};
|
|
@@ -4842,12 +5058,12 @@ ${sections}`
|
|
|
4842
5058
|
}
|
|
4843
5059
|
existingPerms["allow"] = allowList;
|
|
4844
5060
|
settings["permissions"] = existingPerms;
|
|
4845
|
-
|
|
5061
|
+
writeFileSync5(settingsPath, JSON.stringify(settings, null, 2));
|
|
4846
5062
|
}
|
|
4847
5063
|
if (contextValues && Object.keys(contextValues).length > 0) {
|
|
4848
5064
|
const configDir = join4(projectDir, `.${plugin.slug}`);
|
|
4849
5065
|
mkdirSync4(configDir, { recursive: true });
|
|
4850
|
-
|
|
5066
|
+
writeFileSync5(join4(configDir, "config.json"), JSON.stringify(contextValues, null, 2));
|
|
4851
5067
|
}
|
|
4852
5068
|
},
|
|
4853
5069
|
executePluginHook(ctx) {
|
|
@@ -4909,7 +5125,7 @@ ${sections}`
|
|
|
4909
5125
|
if (Object.keys(tokens).length === 0)
|
|
4910
5126
|
return;
|
|
4911
5127
|
const tokenPath = join4(agentDir, ".tokens.json");
|
|
4912
|
-
|
|
5128
|
+
writeFileSync5(tokenPath, JSON.stringify(tokens, null, 2));
|
|
4913
5129
|
chmodSync4(tokenPath, SECRET_FILE_MODE);
|
|
4914
5130
|
}
|
|
4915
5131
|
};
|
|
@@ -5199,13 +5415,13 @@ function jsonOutput(data) {
|
|
|
5199
5415
|
}
|
|
5200
5416
|
|
|
5201
5417
|
// src/lib/config.ts
|
|
5202
|
-
import { readFileSync as
|
|
5418
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, existsSync as existsSync6 } from "fs";
|
|
5203
5419
|
import { join as join6 } from "path";
|
|
5204
5420
|
import { homedir as homedir5 } from "os";
|
|
5205
5421
|
var AUGMENTED_DIR2 = join6(homedir5(), ".augmented");
|
|
5206
5422
|
var CONFIG_PATH = join6(AUGMENTED_DIR2, "config.json");
|
|
5207
5423
|
function ensureAugmentedDir() {
|
|
5208
|
-
if (!
|
|
5424
|
+
if (!existsSync6(AUGMENTED_DIR2)) {
|
|
5209
5425
|
mkdirSync5(AUGMENTED_DIR2, { recursive: true });
|
|
5210
5426
|
}
|
|
5211
5427
|
}
|
|
@@ -5219,7 +5435,7 @@ function loadFromShellProfile(force = false) {
|
|
|
5219
5435
|
const candidates = shell.includes("zsh") ? [join6(home, ".zshrc"), join6(home, ".zprofile")] : shell.includes("fish") ? [join6(home, ".config", "fish", "config.fish")] : [join6(home, ".bashrc"), join6(home, ".bash_profile")];
|
|
5220
5436
|
for (const profile of candidates) {
|
|
5221
5437
|
try {
|
|
5222
|
-
const content =
|
|
5438
|
+
const content = readFileSync6(profile, "utf-8");
|
|
5223
5439
|
for (const key of ["AGT_HOST", "AGT_API_KEY", "AGT_TEAM"]) {
|
|
5224
5440
|
if (!force && process.env[key]) continue;
|
|
5225
5441
|
const match = content.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).map(
|
|
@@ -5244,7 +5460,7 @@ function getApiKey() {
|
|
|
5244
5460
|
}
|
|
5245
5461
|
function getConfig() {
|
|
5246
5462
|
try {
|
|
5247
|
-
const raw =
|
|
5463
|
+
const raw = readFileSync6(CONFIG_PATH, "utf-8");
|
|
5248
5464
|
return JSON.parse(raw);
|
|
5249
5465
|
} catch {
|
|
5250
5466
|
return {};
|
|
@@ -5252,7 +5468,7 @@ function getConfig() {
|
|
|
5252
5468
|
}
|
|
5253
5469
|
function saveConfig(config) {
|
|
5254
5470
|
ensureAugmentedDir();
|
|
5255
|
-
|
|
5471
|
+
writeFileSync6(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
5256
5472
|
}
|
|
5257
5473
|
function getActiveTeam() {
|
|
5258
5474
|
const envTeam = process.env["AGT_TEAM"];
|
|
@@ -5599,7 +5815,12 @@ var SLACK_SCOPE_REGISTRY = [
|
|
|
5599
5815
|
name: "Write Bot Profile",
|
|
5600
5816
|
description: "Update the bot's own profile (status emoji + status text). Used to surface live/offline state to operators without polling.",
|
|
5601
5817
|
category: "users",
|
|
5602
|
-
risk: "low"
|
|
5818
|
+
risk: "low",
|
|
5819
|
+
// ENG-4812: Slack rejects this scope under oauth_config.scopes.bot
|
|
5820
|
+
// with `illegal_bot_scopes`. It must be granted via a user token —
|
|
5821
|
+
// which is what `setBotStatus()` (calling users.profile.set in
|
|
5822
|
+
// packages/mcp/src/slack-channel.ts) actually requires anyway.
|
|
5823
|
+
token_type: "user"
|
|
5603
5824
|
},
|
|
5604
5825
|
// ── Channel Management ───────────────────────────────────────────────────
|
|
5605
5826
|
{
|
|
@@ -5741,6 +5962,9 @@ function getScopesByCategory() {
|
|
|
5741
5962
|
}
|
|
5742
5963
|
return map;
|
|
5743
5964
|
}
|
|
5965
|
+
function getSlackScopeDefinition(scope) {
|
|
5966
|
+
return SLACK_SCOPE_REGISTRY.find((s) => s.scope === scope);
|
|
5967
|
+
}
|
|
5744
5968
|
var SLACK_SCOPE_PRESETS = {
|
|
5745
5969
|
minimal: [
|
|
5746
5970
|
"app_mentions:read",
|
|
@@ -5826,9 +6050,23 @@ function generateSlackAppManifest(input) {
|
|
|
5826
6050
|
},
|
|
5827
6051
|
oauth_config: {
|
|
5828
6052
|
...redirect_urls && redirect_urls.length > 0 ? { redirect_urls } : {},
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
6053
|
+
// ENG-4812: partition by token_type so user-only scopes
|
|
6054
|
+
// (e.g. users.profile:write) don't end up under `bot` and
|
|
6055
|
+
// trigger Slack's `illegal_bot_scopes` rejection. Scopes
|
|
6056
|
+
// without an explicit token_type default to 'bot' — matches
|
|
6057
|
+
// pre-fix behaviour for the registry's standard-token-set.
|
|
6058
|
+
scopes: (() => {
|
|
6059
|
+
const botScopes = [];
|
|
6060
|
+
const userScopes = [];
|
|
6061
|
+
for (const scope of scopes) {
|
|
6062
|
+
const def = getSlackScopeDefinition(scope);
|
|
6063
|
+
if (def?.token_type === "user")
|
|
6064
|
+
userScopes.push(scope);
|
|
6065
|
+
else
|
|
6066
|
+
botScopes.push(scope);
|
|
6067
|
+
}
|
|
6068
|
+
return userScopes.length > 0 ? { bot: botScopes, user: userScopes } : { bot: botScopes };
|
|
6069
|
+
})()
|
|
5832
6070
|
},
|
|
5833
6071
|
settings: {
|
|
5834
6072
|
...botEvents.size > 0 ? { event_subscriptions: { bot_events: [...botEvents].sort() } } : {},
|
|
@@ -7599,13 +7837,13 @@ function provision(input, frameworkId = "openclaw") {
|
|
|
7599
7837
|
|
|
7600
7838
|
// src/commands/manager.ts
|
|
7601
7839
|
import chalk3 from "chalk";
|
|
7602
|
-
import { existsSync as
|
|
7840
|
+
import { existsSync as existsSync8, realpathSync } from "fs";
|
|
7603
7841
|
import { join as join8 } from "path";
|
|
7604
7842
|
import { homedir as homedir6, userInfo } from "os";
|
|
7605
7843
|
import { spawn as spawn3 } from "child_process";
|
|
7606
7844
|
|
|
7607
7845
|
// src/lib/watchdog.ts
|
|
7608
|
-
import { readFileSync as
|
|
7846
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync7, unlinkSync as unlinkSync4, existsSync as existsSync7, mkdirSync as mkdirSync6, openSync, closeSync, chmodSync as chmodSync5 } from "fs";
|
|
7609
7847
|
import { join as join7 } from "path";
|
|
7610
7848
|
import { spawn as spawn2, execFileSync } from "child_process";
|
|
7611
7849
|
var DEFAULT_CONFIG_DIR = join7(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
@@ -7617,17 +7855,17 @@ function getManagerPaths(configDir) {
|
|
|
7617
7855
|
};
|
|
7618
7856
|
}
|
|
7619
7857
|
function ensureDir2(configDir) {
|
|
7620
|
-
if (!
|
|
7858
|
+
if (!existsSync7(configDir)) {
|
|
7621
7859
|
mkdirSync6(configDir, { recursive: true });
|
|
7622
7860
|
}
|
|
7623
7861
|
}
|
|
7624
7862
|
function writePidFile(configDir, pid) {
|
|
7625
7863
|
ensureDir2(configDir);
|
|
7626
|
-
|
|
7864
|
+
writeFileSync7(getManagerPaths(configDir).pidFile, String(pid), { mode: 384 });
|
|
7627
7865
|
}
|
|
7628
7866
|
function readPidFile(configDir) {
|
|
7629
7867
|
try {
|
|
7630
|
-
const raw =
|
|
7868
|
+
const raw = readFileSync7(getManagerPaths(configDir).pidFile, "utf-8").trim();
|
|
7631
7869
|
const pid = parseInt(raw, 10);
|
|
7632
7870
|
return isNaN(pid) ? null : pid;
|
|
7633
7871
|
} catch {
|
|
@@ -7636,7 +7874,7 @@ function readPidFile(configDir) {
|
|
|
7636
7874
|
}
|
|
7637
7875
|
function removePidFile(configDir) {
|
|
7638
7876
|
try {
|
|
7639
|
-
|
|
7877
|
+
unlinkSync4(getManagerPaths(configDir).pidFile);
|
|
7640
7878
|
} catch {
|
|
7641
7879
|
}
|
|
7642
7880
|
}
|
|
@@ -7665,7 +7903,7 @@ function defaultPgrep() {
|
|
|
7665
7903
|
}
|
|
7666
7904
|
function readStateFile(configDir) {
|
|
7667
7905
|
try {
|
|
7668
|
-
const raw =
|
|
7906
|
+
const raw = readFileSync7(getManagerPaths(configDir).stateFile, "utf-8");
|
|
7669
7907
|
return JSON.parse(raw);
|
|
7670
7908
|
} catch {
|
|
7671
7909
|
return null;
|
|
@@ -7673,7 +7911,7 @@ function readStateFile(configDir) {
|
|
|
7673
7911
|
}
|
|
7674
7912
|
function removeStateFile(configDir) {
|
|
7675
7913
|
try {
|
|
7676
|
-
|
|
7914
|
+
unlinkSync4(getManagerPaths(configDir).stateFile);
|
|
7677
7915
|
} catch {
|
|
7678
7916
|
}
|
|
7679
7917
|
}
|
|
@@ -7721,7 +7959,7 @@ function startWatchdog(opts) {
|
|
|
7721
7959
|
const deadline = Date.now() + 5e3;
|
|
7722
7960
|
const sleepBuf = new Int32Array(new SharedArrayBuffer(4));
|
|
7723
7961
|
while (Date.now() < deadline) {
|
|
7724
|
-
if (
|
|
7962
|
+
if (existsSync7(pidFile)) {
|
|
7725
7963
|
return { pid: child.pid };
|
|
7726
7964
|
}
|
|
7727
7965
|
if (child.exitCode !== null) {
|
|
@@ -8045,7 +8283,7 @@ function resolveStableAgtBin(rawPath) {
|
|
|
8045
8283
|
if (!prefix || !formula) return rawPath;
|
|
8046
8284
|
const candidates = [`${prefix}/bin/${formula}`, `${prefix}/bin/agt`];
|
|
8047
8285
|
for (const candidate of candidates) {
|
|
8048
|
-
if (!
|
|
8286
|
+
if (!existsSync8(candidate)) continue;
|
|
8049
8287
|
try {
|
|
8050
8288
|
realpathSync(candidate);
|
|
8051
8289
|
return candidate;
|
|
@@ -8276,4 +8514,4 @@ export {
|
|
|
8276
8514
|
managerInstallSystemUnitCommand,
|
|
8277
8515
|
managerUninstallSystemUnitCommand
|
|
8278
8516
|
};
|
|
8279
|
-
//# sourceMappingURL=chunk-
|
|
8517
|
+
//# sourceMappingURL=chunk-DVWBVANP.js.map
|