@integrity-labs/agt-cli 0.28.359 → 0.28.361
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 +4 -4
- package/dist/{chunk-FAGXXKWZ.js → chunk-3D7IBJYZ.js} +1606 -188
- package/dist/chunk-3D7IBJYZ.js.map +1 -0
- package/dist/{chunk-TVFNWNSP.js → chunk-7EKDO7A5.js} +199 -1090
- package/dist/chunk-7EKDO7A5.js.map +1 -0
- package/dist/{claude-pair-runtime-ASRAOWWQ.js → claude-pair-runtime-LKXINT7K.js} +2 -2
- package/dist/lib/manager-worker.js +283 -744
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/direct-chat-channel.js +17 -1
- package/dist/mcp/origami.js +17 -1
- package/dist/mcp/slack-channel.js +17 -1
- package/dist/mcp/telegram-channel.js +17 -1
- package/dist/{persistent-session-R7JOZNIC.js → persistent-session-7VMIE4G4.js} +2 -2
- package/dist/{responsiveness-probe-7SUERVWL.js → responsiveness-probe-XJ7DQX4M.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-FAGXXKWZ.js.map +0 -1
- package/dist/chunk-TVFNWNSP.js.map +0 -1
- /package/dist/{claude-pair-runtime-ASRAOWWQ.js.map → claude-pair-runtime-LKXINT7K.js.map} +0 -0
- /package/dist/{persistent-session-R7JOZNIC.js.map → persistent-session-7VMIE4G4.js.map} +0 -0
- /package/dist/{responsiveness-probe-7SUERVWL.js.map → responsiveness-probe-XJ7DQX4M.js.map} +0 -0
|
@@ -2,15 +2,12 @@ import {
|
|
|
2
2
|
ApiError,
|
|
3
3
|
CHANNEL_SECRET_ENV_KEYS,
|
|
4
4
|
HostFlagStore,
|
|
5
|
-
HttpOpencodeClient,
|
|
6
5
|
INTEGRATIONS_SECTION_END,
|
|
7
6
|
INTEGRATIONS_SECTION_START,
|
|
8
|
-
OpencodeInboundBridge,
|
|
9
7
|
SUPERVISOR_RESTART_EXIT_CODE,
|
|
10
8
|
api,
|
|
11
9
|
atomicWriteFileSync,
|
|
12
10
|
buildConnectivityProbeDeps,
|
|
13
|
-
buildOpencodeTranscript,
|
|
14
11
|
buildProbeEnv,
|
|
15
12
|
classifyEnvIntegrationsDiff,
|
|
16
13
|
clearPresenceReaperState,
|
|
@@ -19,7 +16,6 @@ import {
|
|
|
19
16
|
defaultFlagsCachePath,
|
|
20
17
|
deriveMcpServerKey,
|
|
21
18
|
diffEnvIntegrations,
|
|
22
|
-
emptyOpencodeTranscript,
|
|
23
19
|
envOnlyRespawnVars,
|
|
24
20
|
estimateActiveTasksTokens,
|
|
25
21
|
exchangeApiKey,
|
|
@@ -32,7 +28,6 @@ import {
|
|
|
32
28
|
getHostId,
|
|
33
29
|
givenUpMcpServerKeys,
|
|
34
30
|
liveProxyExtraHeaderVars,
|
|
35
|
-
parseOpencodeModelRef,
|
|
36
31
|
pinAllowsUrgent,
|
|
37
32
|
provision,
|
|
38
33
|
provisionAutoKanbanProgressHook,
|
|
@@ -42,15 +37,13 @@ import {
|
|
|
42
37
|
provisionPreCompactHook,
|
|
43
38
|
provisionSessionStateHook,
|
|
44
39
|
provisionStopHook,
|
|
45
|
-
readChannelServerEnv,
|
|
46
40
|
reapMissingMcpSessions,
|
|
47
41
|
reapStaleMcpChildren,
|
|
48
42
|
requireHost,
|
|
49
43
|
resolveEffectivePinRaw,
|
|
50
44
|
safeWriteJsonAtomic,
|
|
51
|
-
setConfigHash
|
|
52
|
-
|
|
53
|
-
} from "../chunk-TVFNWNSP.js";
|
|
45
|
+
setConfigHash
|
|
46
|
+
} from "../chunk-7EKDO7A5.js";
|
|
54
47
|
import {
|
|
55
48
|
getProjectDir as getProjectDir2,
|
|
56
49
|
getReadyTasks,
|
|
@@ -83,6 +76,7 @@ import {
|
|
|
83
76
|
creditWatchdogGiveUpCount,
|
|
84
77
|
describeOnboardingChannel,
|
|
85
78
|
egressMode,
|
|
79
|
+
execFilePromiseLong,
|
|
86
80
|
extractFrontmatter,
|
|
87
81
|
formatActorId,
|
|
88
82
|
formatRunMarker,
|
|
@@ -91,14 +85,17 @@ import {
|
|
|
91
85
|
getLastFailureContext,
|
|
92
86
|
getProjectDir,
|
|
93
87
|
getSessionState,
|
|
88
|
+
hashFile,
|
|
94
89
|
injectMessage,
|
|
95
90
|
injectMessageWithStatus,
|
|
91
|
+
injectOpencodeMessage,
|
|
96
92
|
isAgentIdle,
|
|
97
93
|
isAgentPromptReady,
|
|
98
94
|
isBareAck,
|
|
99
95
|
isConversationFailureCategory,
|
|
100
96
|
isEmptyTotals,
|
|
101
97
|
isOnboardingArea,
|
|
98
|
+
isOpencodeSessionHealthy,
|
|
102
99
|
isParseError,
|
|
103
100
|
isResolveError,
|
|
104
101
|
isSelfCompletion,
|
|
@@ -109,6 +106,7 @@ import {
|
|
|
109
106
|
isVacuousDeliverReason,
|
|
110
107
|
isolationMode,
|
|
111
108
|
laneTagFragment,
|
|
109
|
+
log,
|
|
112
110
|
minutesSinceLocalMidnight,
|
|
113
111
|
paneLogPath,
|
|
114
112
|
parseDeliverAssertion,
|
|
@@ -118,8 +116,11 @@ import {
|
|
|
118
116
|
parseUsageBanner,
|
|
119
117
|
peekCurrentSession,
|
|
120
118
|
prepareForRespawn,
|
|
119
|
+
readChannelServerEnv,
|
|
121
120
|
readDirectChatSessionState,
|
|
121
|
+
readOpencodePaneLogTail,
|
|
122
122
|
readPaneLogTail,
|
|
123
|
+
readProvisionedOpencodeModel,
|
|
123
124
|
reloadEgressSidecar,
|
|
124
125
|
resetRestartCount,
|
|
125
126
|
resolveAgentTimezone,
|
|
@@ -132,26 +133,30 @@ import {
|
|
|
132
133
|
sendToAgent,
|
|
133
134
|
serializeUsageLimitMarker,
|
|
134
135
|
sessionTranscriptDir,
|
|
136
|
+
sha256,
|
|
137
|
+
startOpencodeSession,
|
|
135
138
|
startPersistentSession,
|
|
136
139
|
stopAllSessionsAndWait,
|
|
140
|
+
stopOpencodeSession,
|
|
137
141
|
stopPersistentSession,
|
|
138
142
|
subagentActivityAgeSeconds,
|
|
139
143
|
sumTranscriptUsageInWindow,
|
|
140
144
|
takeWatchdogGiveUpCount,
|
|
141
145
|
takeZombieDetection,
|
|
146
|
+
toOpencodeModel,
|
|
142
147
|
transcriptActivityAgeSeconds,
|
|
143
148
|
writeEgressAllowlist
|
|
144
|
-
} from "../chunk-
|
|
149
|
+
} from "../chunk-3D7IBJYZ.js";
|
|
145
150
|
import {
|
|
146
151
|
reapOrphanChannelMcps
|
|
147
152
|
} from "../chunk-XWVM4KPK.js";
|
|
148
153
|
|
|
149
154
|
// src/lib/manager-worker.ts
|
|
150
|
-
import { createHash as
|
|
151
|
-
import { readFileSync as
|
|
155
|
+
import { createHash as createHash13 } from "crypto";
|
|
156
|
+
import { readFileSync as readFileSync17, writeFileSync as writeFileSync11, mkdirSync as mkdirSync8, existsSync as existsSync11, rmSync as rmSync5, readdirSync as readdirSync5, statSync as statSync4, copyFileSync } from "fs";
|
|
152
157
|
import { execFileSync as syncExecFile } from "child_process";
|
|
153
|
-
import { join as
|
|
154
|
-
import { homedir as
|
|
158
|
+
import { join as join21, dirname as dirname5, delimiter as pathDelimiter } from "path";
|
|
159
|
+
import { homedir as homedir10 } from "os";
|
|
155
160
|
import { fileURLToPath } from "url";
|
|
156
161
|
|
|
157
162
|
// src/lib/claude-code-upgrade-throttle.ts
|
|
@@ -3976,125 +3981,6 @@ function writeManagedSkillManifest(path, ids) {
|
|
|
3976
3981
|
}
|
|
3977
3982
|
}
|
|
3978
3983
|
|
|
3979
|
-
// src/lib/manager/runtime.ts
|
|
3980
|
-
import { createHash as createHash6 } from "crypto";
|
|
3981
|
-
import { readFileSync as readFileSync13, appendFileSync, mkdirSync as mkdirSync6, chmodSync, existsSync as existsSync6 } from "fs";
|
|
3982
|
-
import { join as join14, dirname as dirname5 } from "path";
|
|
3983
|
-
import { homedir as homedir6 } from "os";
|
|
3984
|
-
function redactForDiskLog(value) {
|
|
3985
|
-
try {
|
|
3986
|
-
return value.replace(/\b(Bearer\s+)[A-Za-z0-9._-]+\b/gi, "$1[REDACTED]").replace(/\bxox[baprs]-[A-Za-z0-9-]+\b/g, "[REDACTED-SLACK]").replace(/\btlk_[A-Za-z0-9._-]+\b/g, "[REDACTED-HOST]").replace(/\bsk-ant-[A-Za-z0-9_-]+\b/g, "[REDACTED-ANTHROPIC]").replace(/\b\d{8,12}:[A-Za-z0-9_-]{30,}\b/g, "[REDACTED-TELEGRAM]").replace(
|
|
3987
|
-
/\b([A-Z0-9_]*(?:TOKEN|SECRET|API[_-]?KEY|PASSWORD)[A-Z0-9_]*)=(?:"[^"\r\n]*"|'[^'\r\n]*'|[^\s\r\n]+)/gi,
|
|
3988
|
-
"$1=[REDACTED]"
|
|
3989
|
-
);
|
|
3990
|
-
} catch {
|
|
3991
|
-
return "[REDACTED]";
|
|
3992
|
-
}
|
|
3993
|
-
}
|
|
3994
|
-
var managerLogPath = null;
|
|
3995
|
-
var managerLogWritable = true;
|
|
3996
|
-
function log(msg) {
|
|
3997
|
-
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
3998
|
-
const safeMsg = redactForDiskLog(msg);
|
|
3999
|
-
const line = `[manager-worker ${ts}] ${safeMsg}
|
|
4000
|
-
`;
|
|
4001
|
-
if (!managerLogPath) {
|
|
4002
|
-
try {
|
|
4003
|
-
managerLogPath = join14(homedir6(), ".augmented", "manager.log");
|
|
4004
|
-
mkdirSync6(dirname5(managerLogPath), { recursive: true });
|
|
4005
|
-
if (existsSync6(managerLogPath)) {
|
|
4006
|
-
chmodSync(managerLogPath, 384);
|
|
4007
|
-
}
|
|
4008
|
-
} catch {
|
|
4009
|
-
}
|
|
4010
|
-
}
|
|
4011
|
-
let appendedToFile = false;
|
|
4012
|
-
if (managerLogPath && managerLogWritable) {
|
|
4013
|
-
try {
|
|
4014
|
-
appendFileSync(managerLogPath, line, { encoding: "utf-8", mode: 384 });
|
|
4015
|
-
appendedToFile = true;
|
|
4016
|
-
} catch (err) {
|
|
4017
|
-
managerLogWritable = false;
|
|
4018
|
-
process.stderr.write(
|
|
4019
|
-
`[manager-worker ${ts}] [log] manager.log append failed; falling back to stderr-only: ${err.message}
|
|
4020
|
-
`
|
|
4021
|
-
);
|
|
4022
|
-
}
|
|
4023
|
-
}
|
|
4024
|
-
if (!appendedToFile || process.stderr.isTTY === true) {
|
|
4025
|
-
process.stderr.write(line);
|
|
4026
|
-
}
|
|
4027
|
-
}
|
|
4028
|
-
function sha256(content) {
|
|
4029
|
-
return createHash6("sha256").update(content, "utf8").digest("hex");
|
|
4030
|
-
}
|
|
4031
|
-
function hashFile(filePath) {
|
|
4032
|
-
try {
|
|
4033
|
-
const content = readFileSync13(filePath, "utf-8");
|
|
4034
|
-
return sha256(content);
|
|
4035
|
-
} catch {
|
|
4036
|
-
return null;
|
|
4037
|
-
}
|
|
4038
|
-
}
|
|
4039
|
-
var ChildProcessError = class extends Error {
|
|
4040
|
-
code;
|
|
4041
|
-
stdout;
|
|
4042
|
-
stderr;
|
|
4043
|
-
constructor(code, stdout, stderr) {
|
|
4044
|
-
const stderrSnippet = stderr.trim().slice(0, 500);
|
|
4045
|
-
const stdoutSnippet = stdout.trim().slice(0, 500);
|
|
4046
|
-
const detail = stderrSnippet || stdoutSnippet || "(no output)";
|
|
4047
|
-
super(`Exit code ${code}: ${detail}`);
|
|
4048
|
-
this.name = "ChildProcessError";
|
|
4049
|
-
this.code = code;
|
|
4050
|
-
this.stdout = stdout;
|
|
4051
|
-
this.stderr = stderr;
|
|
4052
|
-
}
|
|
4053
|
-
};
|
|
4054
|
-
async function execFilePromiseLong(cmd, args, opts) {
|
|
4055
|
-
const { spawn: sp } = await import("child_process");
|
|
4056
|
-
return new Promise((resolve, reject) => {
|
|
4057
|
-
const child = sp(cmd, args, {
|
|
4058
|
-
cwd: opts?.cwd,
|
|
4059
|
-
stdio: [opts?.stdin === "ignore" ? "ignore" : "pipe", "pipe", "pipe"],
|
|
4060
|
-
...opts?.env ? { env: opts.env } : {}
|
|
4061
|
-
});
|
|
4062
|
-
if (opts?.onSpawn && typeof child.pid === "number") {
|
|
4063
|
-
try {
|
|
4064
|
-
opts.onSpawn(child.pid);
|
|
4065
|
-
} catch {
|
|
4066
|
-
}
|
|
4067
|
-
}
|
|
4068
|
-
let stdout = "";
|
|
4069
|
-
let stderr = "";
|
|
4070
|
-
child.stdout?.on("data", (d) => {
|
|
4071
|
-
stdout += d.toString();
|
|
4072
|
-
});
|
|
4073
|
-
child.stderr?.on("data", (d) => {
|
|
4074
|
-
stderr += d.toString();
|
|
4075
|
-
});
|
|
4076
|
-
const timer = setTimeout(() => {
|
|
4077
|
-
child.kill();
|
|
4078
|
-
reject(new Error(`Timed out after ${opts?.timeout ?? 12e4}ms`));
|
|
4079
|
-
}, opts?.timeout ?? 12e4);
|
|
4080
|
-
child.on("close", (code) => {
|
|
4081
|
-
clearTimeout(timer);
|
|
4082
|
-
if (opts?.onExit && typeof child.pid === "number") {
|
|
4083
|
-
try {
|
|
4084
|
-
opts.onExit(child.pid);
|
|
4085
|
-
} catch {
|
|
4086
|
-
}
|
|
4087
|
-
}
|
|
4088
|
-
if (code !== 0) reject(new ChildProcessError(code, stdout, stderr));
|
|
4089
|
-
else resolve({ stdout, stderr });
|
|
4090
|
-
});
|
|
4091
|
-
child.on("error", (err) => {
|
|
4092
|
-
clearTimeout(timer);
|
|
4093
|
-
reject(err);
|
|
4094
|
-
});
|
|
4095
|
-
});
|
|
4096
|
-
}
|
|
4097
|
-
|
|
4098
3984
|
// src/lib/manager/restart-timing.ts
|
|
4099
3985
|
var pendingRequested = /* @__PURE__ */ new Map();
|
|
4100
3986
|
var tracks = /* @__PURE__ */ new Map();
|
|
@@ -4188,9 +4074,9 @@ function resolveModelChain(refreshData) {
|
|
|
4188
4074
|
}
|
|
4189
4075
|
|
|
4190
4076
|
// src/lib/manager/claude-auth.ts
|
|
4191
|
-
import { existsSync as
|
|
4192
|
-
import { join as
|
|
4193
|
-
import { homedir as
|
|
4077
|
+
import { existsSync as existsSync6, rmSync as rmSync3 } from "fs";
|
|
4078
|
+
import { join as join14 } from "path";
|
|
4079
|
+
import { homedir as homedir6 } from "os";
|
|
4194
4080
|
async function applyClaudeAuthToEnv(childEnv, label) {
|
|
4195
4081
|
const apiKey = getApiKey();
|
|
4196
4082
|
if (!apiKey) {
|
|
@@ -4202,10 +4088,10 @@ async function applyClaudeAuthToEnv(childEnv, label) {
|
|
|
4202
4088
|
throw new Error("claude_auth_mode=api_key but /host/exchange returned no decrypted key");
|
|
4203
4089
|
}
|
|
4204
4090
|
childEnv.ANTHROPIC_API_KEY = exchange.anthropicApiKey;
|
|
4205
|
-
const claudeDir =
|
|
4091
|
+
const claudeDir = join14(homedir6(), ".claude");
|
|
4206
4092
|
for (const filename of [".credentials.json", "credentials.json"]) {
|
|
4207
|
-
const p =
|
|
4208
|
-
if (
|
|
4093
|
+
const p = join14(claudeDir, filename);
|
|
4094
|
+
if (existsSync6(p)) {
|
|
4209
4095
|
try {
|
|
4210
4096
|
rmSync3(p, { force: true });
|
|
4211
4097
|
log(`[${label}] Removed ${p} (api_key mode \u2014 preventing OAuth fallback)`);
|
|
@@ -4219,8 +4105,8 @@ async function applyClaudeAuthToEnv(childEnv, label) {
|
|
|
4219
4105
|
}
|
|
4220
4106
|
|
|
4221
4107
|
// src/lib/manager/kanban/parsers.ts
|
|
4222
|
-
import { existsSync as
|
|
4223
|
-
import { join as
|
|
4108
|
+
import { existsSync as existsSync7, readFileSync as readFileSync13 } from "fs";
|
|
4109
|
+
import { join as join15 } from "path";
|
|
4224
4110
|
var STANDUP_TEMPLATES = /* @__PURE__ */ new Set(["daily-standup", "end-of-day-summary"]);
|
|
4225
4111
|
var TASK_UPDATE_TEMPLATES = /* @__PURE__ */ new Set(["hourly-status", "task-update"]);
|
|
4226
4112
|
var PLAN_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan"]);
|
|
@@ -4356,12 +4242,12 @@ function getBuiltInSkillContent(skillId) {
|
|
|
4356
4242
|
if (builtInSkillCache.has(skillId)) return builtInSkillCache.get(skillId);
|
|
4357
4243
|
try {
|
|
4358
4244
|
const candidates = [
|
|
4359
|
-
|
|
4360
|
-
|
|
4245
|
+
join15(process.cwd(), "skills", skillId, "SKILL.md"),
|
|
4246
|
+
join15(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "..", "..", "skills", skillId, "SKILL.md")
|
|
4361
4247
|
];
|
|
4362
4248
|
for (const candidate of candidates) {
|
|
4363
|
-
if (
|
|
4364
|
-
const content =
|
|
4249
|
+
if (existsSync7(candidate)) {
|
|
4250
|
+
const content = readFileSync13(candidate, "utf-8");
|
|
4365
4251
|
const files = [{ relativePath: "SKILL.md", content }];
|
|
4366
4252
|
builtInSkillCache.set(skillId, files);
|
|
4367
4253
|
return files;
|
|
@@ -4502,19 +4388,19 @@ function formatBoardForPrompt(items, template) {
|
|
|
4502
4388
|
}
|
|
4503
4389
|
|
|
4504
4390
|
// src/lib/manager/kanban/nudge-state-cache.ts
|
|
4505
|
-
import { existsSync as
|
|
4506
|
-
import { join as
|
|
4391
|
+
import { existsSync as existsSync8, readFileSync as readFileSync14, writeFileSync as writeFileSync7 } from "fs";
|
|
4392
|
+
import { join as join16 } from "path";
|
|
4507
4393
|
var CACHE_FILENAME2 = "kanban-nudge-state.json";
|
|
4508
4394
|
var KANBAN_NUDGE_STATE_VERSION = 1;
|
|
4509
4395
|
function getKanbanNudgeStateFile(configDir) {
|
|
4510
|
-
return
|
|
4396
|
+
return join16(configDir, CACHE_FILENAME2);
|
|
4511
4397
|
}
|
|
4512
4398
|
function loadKanbanNudgeState(target, configDir) {
|
|
4513
4399
|
const path = getKanbanNudgeStateFile(configDir);
|
|
4514
|
-
if (!
|
|
4400
|
+
if (!existsSync8(path)) return;
|
|
4515
4401
|
let parsed;
|
|
4516
4402
|
try {
|
|
4517
|
-
parsed = JSON.parse(
|
|
4403
|
+
parsed = JSON.parse(readFileSync14(path, "utf-8"));
|
|
4518
4404
|
} catch {
|
|
4519
4405
|
return;
|
|
4520
4406
|
}
|
|
@@ -4545,7 +4431,7 @@ function saveKanbanNudgeState(source, configDir) {
|
|
|
4545
4431
|
}
|
|
4546
4432
|
|
|
4547
4433
|
// src/lib/manager/kanban/notify.ts
|
|
4548
|
-
import { createHash as
|
|
4434
|
+
import { createHash as createHash6 } from "crypto";
|
|
4549
4435
|
async function enqueueKanbanNotice(opts) {
|
|
4550
4436
|
try {
|
|
4551
4437
|
const res = await api.post(
|
|
@@ -4560,7 +4446,7 @@ async function enqueueKanbanNotice(opts) {
|
|
|
4560
4446
|
return res.ok === true;
|
|
4561
4447
|
} catch (err) {
|
|
4562
4448
|
const errText = err instanceof Error ? err.message : String(err);
|
|
4563
|
-
const errId =
|
|
4449
|
+
const errId = createHash6("sha256").update(errText).digest("hex").slice(0, 12);
|
|
4564
4450
|
log(`[kanban] notice enqueue failed for agent_id=${opts.agentId} error_id=${errId}`);
|
|
4565
4451
|
return false;
|
|
4566
4452
|
}
|
|
@@ -4575,7 +4461,7 @@ async function cancelKanbanNotice(agentId) {
|
|
|
4575
4461
|
return typeof res.cancelled === "number" ? res.cancelled : 0;
|
|
4576
4462
|
} catch (err) {
|
|
4577
4463
|
const errText = err instanceof Error ? err.message : String(err);
|
|
4578
|
-
const errId =
|
|
4464
|
+
const errId = createHash6("sha256").update(errText).digest("hex").slice(0, 12);
|
|
4579
4465
|
log(`[kanban] notice cancel failed for agent_id=${agentId} error_id=${errId}`);
|
|
4580
4466
|
return null;
|
|
4581
4467
|
}
|
|
@@ -4981,7 +4867,7 @@ function deriveScheduledTaskNotify(task) {
|
|
|
4981
4867
|
}
|
|
4982
4868
|
|
|
4983
4869
|
// src/lib/manager/scheduler/runs.ts
|
|
4984
|
-
import { createHash as
|
|
4870
|
+
import { createHash as createHash7 } from "crypto";
|
|
4985
4871
|
async function startRun(opts) {
|
|
4986
4872
|
try {
|
|
4987
4873
|
const res = await api.post(
|
|
@@ -4996,7 +4882,7 @@ async function startRun(opts) {
|
|
|
4996
4882
|
};
|
|
4997
4883
|
} catch (err) {
|
|
4998
4884
|
const errText = err instanceof Error ? err.message : String(err);
|
|
4999
|
-
const errId =
|
|
4885
|
+
const errId = createHash7("sha256").update(errText).digest("hex").slice(0, 12);
|
|
5000
4886
|
log(`[runs] start failed for agent_id=${opts.agent_id} source_type=${opts.source_type} error_id=${errId}`);
|
|
5001
4887
|
return { run_id: null, kanban_item_id: null };
|
|
5002
4888
|
}
|
|
@@ -5013,7 +4899,7 @@ async function finishRun(runId, outcome, options = {}) {
|
|
|
5013
4899
|
});
|
|
5014
4900
|
} catch (err) {
|
|
5015
4901
|
const errText = err instanceof Error ? err.message : String(err);
|
|
5016
|
-
const errId =
|
|
4902
|
+
const errId = createHash7("sha256").update(errText).digest("hex").slice(0, 12);
|
|
5017
4903
|
log(`[runs] finish failed for run_id=${runId} outcome=${outcome} error_id=${errId}`);
|
|
5018
4904
|
}
|
|
5019
4905
|
}
|
|
@@ -5030,7 +4916,7 @@ async function fetchPriorScheduledRuns(agentId, taskId) {
|
|
|
5030
4916
|
return rows.filter((r) => typeof r.output_text === "string" && r.output_text.length > 0).map((r) => ({ startedAt: r.started_at, output: r.output_text }));
|
|
5031
4917
|
} catch (err) {
|
|
5032
4918
|
const errText = err instanceof Error ? err.message : String(err);
|
|
5033
|
-
const errId =
|
|
4919
|
+
const errId = createHash7("sha256").update(errText).digest("hex").slice(0, 12);
|
|
5034
4920
|
log(`[runs] prior-runs lookup failed for task_id=${taskId} error_id=${errId}`);
|
|
5035
4921
|
return [];
|
|
5036
4922
|
}
|
|
@@ -5079,10 +4965,10 @@ function closeScheduledRunsForCode(codeName, outcome, reason) {
|
|
|
5079
4965
|
}
|
|
5080
4966
|
|
|
5081
4967
|
// src/lib/manager/scheduler/kanban-route.ts
|
|
5082
|
-
import { createHash as
|
|
4968
|
+
import { createHash as createHash8 } from "crypto";
|
|
5083
4969
|
import { writeFileSync as writeFileSync8, renameSync } from "fs";
|
|
5084
|
-
import { homedir as
|
|
5085
|
-
import { join as
|
|
4970
|
+
import { homedir as homedir7 } from "os";
|
|
4971
|
+
import { join as join17 } from "path";
|
|
5086
4972
|
|
|
5087
4973
|
// src/lib/manager/delivery/scheduled-output.ts
|
|
5088
4974
|
async function deliverScheduledTaskOutput(agentCodeName, agentId, rawTarget, body, taskId) {
|
|
@@ -5386,7 +5272,7 @@ function resolveScheduledSlackTarget(task) {
|
|
|
5386
5272
|
}
|
|
5387
5273
|
function stampScheduledTurnMarker(codeName, taskId, target) {
|
|
5388
5274
|
try {
|
|
5389
|
-
const file =
|
|
5275
|
+
const file = join17(homedir7(), ".augmented", codeName, SCHEDULED_TURN_MARKER_FILENAME);
|
|
5390
5276
|
const marker = { ts: Date.now(), task_id: taskId, ...target ? { target } : {} };
|
|
5391
5277
|
const tmp = `${file}.tmp`;
|
|
5392
5278
|
writeFileSync8(tmp, JSON.stringify(marker), "utf8");
|
|
@@ -5488,24 +5374,24 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
|
|
|
5488
5374
|
const assertion = parseDeliverAssertion(rawOutput);
|
|
5489
5375
|
if (!assertion.deliver) {
|
|
5490
5376
|
const trimmed = (rawOutput ?? "").trim();
|
|
5491
|
-
const outputHash = trimmed.length === 0 ? "empty" :
|
|
5377
|
+
const outputHash = trimmed.length === 0 ? "empty" : createHash8("sha256").update(trimmed).digest("hex").slice(0, 12);
|
|
5492
5378
|
log(`[claude-scheduler] Suppressed by delivery_policy=conditional for '${codeName}' (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 ${assertion.vacuous ? "deliver marker had a vacuous reason" : "no deliver marker"}; output_len=${trimmed.length} output_hash=${outputHash}`);
|
|
5493
5379
|
if (delivery?.mode === "announce" && delivery.to) {
|
|
5494
5380
|
await reportDeliveryStatus(agentId, delivery.taskId, { status: "skipped", error_code: "SUPPRESSED_BY_POLICY" });
|
|
5495
5381
|
}
|
|
5496
5382
|
return { ok: true };
|
|
5497
5383
|
}
|
|
5498
|
-
const reasonHash =
|
|
5384
|
+
const reasonHash = createHash8("sha256").update(assertion.reason ?? "").digest("hex").slice(0, 12);
|
|
5499
5385
|
log(`[claude-scheduler] Delivering conditional run for '${codeName}' (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 agent asserted a concrete trigger (reason_len=${(assertion.reason ?? "").length} reason_hash=${reasonHash})`);
|
|
5500
5386
|
rawOutput = assertion.deliverable;
|
|
5501
5387
|
}
|
|
5502
5388
|
const classification = classifyOutput(rawOutput);
|
|
5503
5389
|
if (classification.action === "suppress") {
|
|
5504
5390
|
const trimmed = (rawOutput ?? "").trim();
|
|
5505
|
-
const outputHash = trimmed.length === 0 ? "empty" :
|
|
5391
|
+
const outputHash = trimmed.length === 0 ? "empty" : createHash8("sha256").update(trimmed).digest("hex").slice(0, 12);
|
|
5506
5392
|
log(`[claude-scheduler] Suppressing delivery for '${codeName}' (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 output_len=${trimmed.length} output_hash=${outputHash}`);
|
|
5507
5393
|
if (classification.suppressedNotes) {
|
|
5508
|
-
const notesHash =
|
|
5394
|
+
const notesHash = createHash8("sha256").update(classification.suppressedNotes).digest("hex").slice(0, 12);
|
|
5509
5395
|
log(`[claude-scheduler] Suppressed notes for '${codeName}' (task=${delivery?.taskId ?? "n/a"}) \u2014 notes_len=${classification.suppressedNotes.length} notes_hash=${notesHash}`);
|
|
5510
5396
|
}
|
|
5511
5397
|
if (delivery?.mode === "announce" && delivery.to) {
|
|
@@ -5571,11 +5457,11 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
|
|
|
5571
5457
|
}
|
|
5572
5458
|
|
|
5573
5459
|
// src/lib/manager/scheduler/execution.ts
|
|
5574
|
-
import { createHash as
|
|
5575
|
-
import { homedir as
|
|
5576
|
-
import { join as
|
|
5460
|
+
import { createHash as createHash9 } from "crypto";
|
|
5461
|
+
import { homedir as homedir8 } from "os";
|
|
5462
|
+
import { join as join18 } from "path";
|
|
5577
5463
|
function claudePidFilePath() {
|
|
5578
|
-
return
|
|
5464
|
+
return join18(homedir8(), ".augmented", "manager-claude-pids.json");
|
|
5579
5465
|
}
|
|
5580
5466
|
var inFlightClaudePids = /* @__PURE__ */ new Map();
|
|
5581
5467
|
function registerClaudeSpawn(record) {
|
|
@@ -5595,10 +5481,10 @@ function unregisterClaudeSpawn(pid) {
|
|
|
5595
5481
|
}
|
|
5596
5482
|
async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData) {
|
|
5597
5483
|
const codeName = agent.code_name;
|
|
5598
|
-
const stableTasksHash =
|
|
5599
|
-
const boardHash = boardItems.length > 0 ?
|
|
5484
|
+
const stableTasksHash = createHash9("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
|
|
5485
|
+
const boardHash = boardItems.length > 0 ? createHash9("sha256").update(JSON.stringify(boardItems.map((b) => ({ id: b.id, title: b.title, status: b.status, priority: b.priority, deliverable: b.deliverable })))).digest("hex").slice(0, 16) : "empty";
|
|
5600
5486
|
const resolvedModels = resolveModelChain(refreshData);
|
|
5601
|
-
const modelsHash =
|
|
5487
|
+
const modelsHash = createHash9("sha256").update(JSON.stringify(resolvedModels)).digest("hex").slice(0, 16);
|
|
5602
5488
|
const combinedHash = `${stableTasksHash}:${boardHash}:${modelsHash}`;
|
|
5603
5489
|
const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
|
|
5604
5490
|
if (combinedHash !== prevHash) {
|
|
@@ -5635,355 +5521,8 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
|
|
|
5635
5521
|
}
|
|
5636
5522
|
}
|
|
5637
5523
|
|
|
5638
|
-
// src/lib/opencode-session.ts
|
|
5639
|
-
import { spawn, execSync } from "child_process";
|
|
5640
|
-
import { createServer } from "net";
|
|
5641
|
-
import { randomBytes } from "crypto";
|
|
5642
|
-
import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync16, writeFileSync as writeFileSync9, rmSync as rmSync4, chmodSync as chmodSync2 } from "fs";
|
|
5643
|
-
import { homedir as homedir10, userInfo } from "os";
|
|
5644
|
-
import { join as join20, dirname as dirname6 } from "path";
|
|
5645
|
-
var OPENCODE_BIN = process.env["AGT_OPENCODE_BIN"]?.trim() || "opencode";
|
|
5646
|
-
var sessions = /* @__PURE__ */ new Map();
|
|
5647
|
-
var bridges = /* @__PURE__ */ new Map();
|
|
5648
|
-
function opencodeTmuxSession(codeName) {
|
|
5649
|
-
return `agt-oc-${codeName}`;
|
|
5650
|
-
}
|
|
5651
|
-
function opencodePaneLogPath(codeName) {
|
|
5652
|
-
return join20(homedir10(), ".augmented", codeName, "opencode-serve.log");
|
|
5653
|
-
}
|
|
5654
|
-
function opencodeTranscriptPath(codeName) {
|
|
5655
|
-
return join20(dirname6(opencodePaneLogPath(codeName)), "opencode-transcript.json");
|
|
5656
|
-
}
|
|
5657
|
-
var TRANSCRIPT_REFRESH_MS = 3e3;
|
|
5658
|
-
var TRANSCRIPT_MAX_MESSAGES = 100;
|
|
5659
|
-
var transcriptTimers = /* @__PURE__ */ new Map();
|
|
5660
|
-
function pickNewestSession(sessions2) {
|
|
5661
|
-
let newest = null;
|
|
5662
|
-
let newestT = Number.NEGATIVE_INFINITY;
|
|
5663
|
-
for (const s of sessions2) {
|
|
5664
|
-
const t = s.updated ?? s.created ?? 0;
|
|
5665
|
-
if (t >= newestT) {
|
|
5666
|
-
newestT = t;
|
|
5667
|
-
newest = s;
|
|
5668
|
-
}
|
|
5669
|
-
}
|
|
5670
|
-
return newest;
|
|
5671
|
-
}
|
|
5672
|
-
async function refreshOpencodeTranscript(codeName) {
|
|
5673
|
-
const session = sessions.get(codeName);
|
|
5674
|
-
if (!session || session.status !== "running" || !session.port || !session.password) return;
|
|
5675
|
-
const client2 = new HttpOpencodeClient({
|
|
5676
|
-
baseUrl: baseUrlFor(session.port),
|
|
5677
|
-
password: session.password,
|
|
5678
|
-
requestTimeoutMs: 8e3
|
|
5679
|
-
});
|
|
5680
|
-
let transcript;
|
|
5681
|
-
try {
|
|
5682
|
-
const newest = pickNewestSession(await client2.listSessions());
|
|
5683
|
-
transcript = newest ? buildOpencodeTranscript({
|
|
5684
|
-
sessionId: newest.id,
|
|
5685
|
-
sessionTitle: newest.title ?? null,
|
|
5686
|
-
messages: await client2.getStructuredMessages(newest.id),
|
|
5687
|
-
capturedAt: Date.now(),
|
|
5688
|
-
redact: redactForDiskLog,
|
|
5689
|
-
maxMessages: TRANSCRIPT_MAX_MESSAGES
|
|
5690
|
-
}) : emptyOpencodeTranscript(Date.now());
|
|
5691
|
-
} catch {
|
|
5692
|
-
return;
|
|
5693
|
-
}
|
|
5694
|
-
try {
|
|
5695
|
-
const target = opencodeTranscriptPath(codeName);
|
|
5696
|
-
mkdirSync7(dirname6(target), { recursive: true });
|
|
5697
|
-
writeFileSync9(target, JSON.stringify(transcript), { mode: 384 });
|
|
5698
|
-
try {
|
|
5699
|
-
chmodSync2(target, 384);
|
|
5700
|
-
} catch {
|
|
5701
|
-
}
|
|
5702
|
-
} catch {
|
|
5703
|
-
}
|
|
5704
|
-
}
|
|
5705
|
-
function startTranscriptRefresher(codeName) {
|
|
5706
|
-
if (transcriptTimers.has(codeName)) return;
|
|
5707
|
-
const timer = setInterval(() => {
|
|
5708
|
-
void refreshOpencodeTranscript(codeName);
|
|
5709
|
-
}, TRANSCRIPT_REFRESH_MS);
|
|
5710
|
-
timer.unref?.();
|
|
5711
|
-
transcriptTimers.set(codeName, timer);
|
|
5712
|
-
void refreshOpencodeTranscript(codeName);
|
|
5713
|
-
}
|
|
5714
|
-
function stopTranscriptRefresher(codeName) {
|
|
5715
|
-
const timer = transcriptTimers.get(codeName);
|
|
5716
|
-
if (timer) {
|
|
5717
|
-
clearInterval(timer);
|
|
5718
|
-
transcriptTimers.delete(codeName);
|
|
5719
|
-
}
|
|
5720
|
-
}
|
|
5721
|
-
function readProvisionedOpencodeModel(agentDir) {
|
|
5722
|
-
return readOpencodeModelString(join20(agentDir, "provision", "opencode.json"));
|
|
5723
|
-
}
|
|
5724
|
-
function readOpencodeModelString(configPath) {
|
|
5725
|
-
try {
|
|
5726
|
-
const parsed = JSON.parse(readFileSync16(configPath, "utf-8"));
|
|
5727
|
-
return typeof parsed.model === "string" ? parsed.model : null;
|
|
5728
|
-
} catch {
|
|
5729
|
-
return null;
|
|
5730
|
-
}
|
|
5731
|
-
}
|
|
5732
|
-
function readOpencodeModelFromConfigDir(configDir) {
|
|
5733
|
-
return parseOpencodeModelRef(readOpencodeModelString(join20(configDir, "opencode.json")));
|
|
5734
|
-
}
|
|
5735
|
-
function materializeEnvPlaceholders(raw, env) {
|
|
5736
|
-
return raw.replace(/\{env:([A-Za-z_][A-Za-z0-9_]*)\}/g, (whole, name) => {
|
|
5737
|
-
const v = env[name];
|
|
5738
|
-
return typeof v === "string" && v.length > 0 ? v : whole;
|
|
5739
|
-
});
|
|
5740
|
-
}
|
|
5741
|
-
var MATERIALIZED_CONFIG_BASENAME = "opencode.jsonc";
|
|
5742
|
-
function writeMaterializedOpencodeConfig(codeName, projectDir, serveEnv, log2) {
|
|
5743
|
-
const target = join20(projectDir, MATERIALIZED_CONFIG_BASENAME);
|
|
5744
|
-
let raw;
|
|
5745
|
-
try {
|
|
5746
|
-
raw = readFileSync16(join20(projectDir, "opencode.json"), "utf-8");
|
|
5747
|
-
} catch {
|
|
5748
|
-
try {
|
|
5749
|
-
if (existsSync10(target)) rmSync4(target);
|
|
5750
|
-
} catch {
|
|
5751
|
-
}
|
|
5752
|
-
return true;
|
|
5753
|
-
}
|
|
5754
|
-
try {
|
|
5755
|
-
writeFileSync9(target, materializeEnvPlaceholders(raw, serveEnv), { mode: 384 });
|
|
5756
|
-
} catch (err) {
|
|
5757
|
-
log2(`[opencode-session] failed to write materialized opencode.jsonc for '${codeName}': ${err.message}`);
|
|
5758
|
-
return false;
|
|
5759
|
-
}
|
|
5760
|
-
try {
|
|
5761
|
-
chmodSync2(target, 384);
|
|
5762
|
-
} catch {
|
|
5763
|
-
}
|
|
5764
|
-
return true;
|
|
5765
|
-
}
|
|
5766
|
-
function baseUrlFor(port) {
|
|
5767
|
-
return `http://127.0.0.1:${port}`;
|
|
5768
|
-
}
|
|
5769
|
-
function findFreePort() {
|
|
5770
|
-
return new Promise((resolve, reject) => {
|
|
5771
|
-
const srv = createServer();
|
|
5772
|
-
srv.on("error", reject);
|
|
5773
|
-
srv.listen(0, "127.0.0.1", () => {
|
|
5774
|
-
const addr = srv.address();
|
|
5775
|
-
if (addr && typeof addr === "object") {
|
|
5776
|
-
const { port } = addr;
|
|
5777
|
-
srv.close(() => resolve(port));
|
|
5778
|
-
} else {
|
|
5779
|
-
srv.close(() => reject(new Error("could not allocate a port")));
|
|
5780
|
-
}
|
|
5781
|
-
});
|
|
5782
|
-
});
|
|
5783
|
-
}
|
|
5784
|
-
async function startOpencodeSession(config2) {
|
|
5785
|
-
const { codeName, log: log2 } = config2;
|
|
5786
|
-
const existing = sessions.get(codeName);
|
|
5787
|
-
if (existing && existing.status === "running") return existing;
|
|
5788
|
-
const restartCount = existing?.restartCount ?? 0;
|
|
5789
|
-
if (existing?.status === "crashed" && existing.startedAt) {
|
|
5790
|
-
const backoffMs = Math.min(5e3 * Math.pow(2, restartCount), 6e4);
|
|
5791
|
-
if (Date.now() - existing.startedAt < backoffMs) return existing;
|
|
5792
|
-
}
|
|
5793
|
-
if (config2.isolated) {
|
|
5794
|
-
log2(
|
|
5795
|
-
`[opencode-session] refusing to spawn '${codeName}': Docker isolation requested but the opencode container runtime is not implemented yet (ADR-0047). Not running unisolated on a multi-tenant host.`
|
|
5796
|
-
);
|
|
5797
|
-
const blocked = {
|
|
5798
|
-
codeName,
|
|
5799
|
-
startedAt: Date.now(),
|
|
5800
|
-
restartCount: restartCount + 1,
|
|
5801
|
-
status: "crashed",
|
|
5802
|
-
port: null,
|
|
5803
|
-
password: null,
|
|
5804
|
-
lastFailureTail: "opencode isolation not implemented (ADR-0047)",
|
|
5805
|
-
model: null
|
|
5806
|
-
};
|
|
5807
|
-
sessions.set(codeName, blocked);
|
|
5808
|
-
return blocked;
|
|
5809
|
-
}
|
|
5810
|
-
const session = {
|
|
5811
|
-
codeName,
|
|
5812
|
-
startedAt: null,
|
|
5813
|
-
restartCount,
|
|
5814
|
-
status: "starting",
|
|
5815
|
-
port: null,
|
|
5816
|
-
password: null,
|
|
5817
|
-
lastFailureTail: existing?.lastFailureTail ?? null,
|
|
5818
|
-
// ENG-7931: parse the resolved model from the provisioned opencode.json
|
|
5819
|
-
// (config.projectDir IS the provision dir the serve reads) so the bridge can
|
|
5820
|
-
// pass it explicitly on session-create + prompt.
|
|
5821
|
-
model: readOpencodeModelFromConfigDir(config2.projectDir)
|
|
5822
|
-
};
|
|
5823
|
-
sessions.set(codeName, session);
|
|
5824
|
-
try {
|
|
5825
|
-
await spawnServe(config2, session);
|
|
5826
|
-
} catch (err) {
|
|
5827
|
-
log2(`[opencode-session] failed to start '${codeName}': ${err.message}`);
|
|
5828
|
-
session.status = "crashed";
|
|
5829
|
-
session.startedAt = Date.now();
|
|
5830
|
-
session.restartCount++;
|
|
5831
|
-
}
|
|
5832
|
-
return session;
|
|
5833
|
-
}
|
|
5834
|
-
async function spawnServe(config2, session) {
|
|
5835
|
-
const { codeName, projectDir, log: log2 } = config2;
|
|
5836
|
-
if (!existsSync10(join20(projectDir, "opencode.json"))) {
|
|
5837
|
-
log2(`[opencode-session] warning: no opencode.json in ${projectDir} for '${codeName}' (provisioning may not have run)`);
|
|
5838
|
-
}
|
|
5839
|
-
const tmuxSession = opencodeTmuxSession(codeName);
|
|
5840
|
-
const port = await findFreePort();
|
|
5841
|
-
const password = randomBytes(24).toString("base64url");
|
|
5842
|
-
try {
|
|
5843
|
-
execSync(`tmux kill-session -t ${tmuxSession} 2>/dev/null`, { stdio: "ignore" });
|
|
5844
|
-
} catch {
|
|
5845
|
-
}
|
|
5846
|
-
mkdirSync7(join20(homedir10(), ".augmented", codeName), { recursive: true });
|
|
5847
|
-
const serveEnv = {
|
|
5848
|
-
...process.env,
|
|
5849
|
-
...readAgentProviderEnv(codeName),
|
|
5850
|
-
...stripUndefined(config2.serveEnv ?? {}),
|
|
5851
|
-
OPENCODE_SERVER_PASSWORD: password,
|
|
5852
|
-
HOME: process.env.HOME?.trim() || homedir10(),
|
|
5853
|
-
USER: process.env.USER?.trim() || userInfo().username
|
|
5854
|
-
};
|
|
5855
|
-
if (config2.runId) serveEnv["AGT_RUN_ID"] = config2.runId;
|
|
5856
|
-
if (config2.agentTimezone) serveEnv["TZ"] = config2.agentTimezone;
|
|
5857
|
-
if (!writeMaterializedOpencodeConfig(codeName, projectDir, serveEnv, log2)) {
|
|
5858
|
-
throw new Error("failed to write materialized opencode.jsonc (serve would 401 on the {env:\u2026} template)");
|
|
5859
|
-
}
|
|
5860
|
-
const serveCmd = `${OPENCODE_BIN} serve --hostname 127.0.0.1 --port ${port} --print-logs`;
|
|
5861
|
-
log2(`[opencode-session] starting '${tmuxSession}' for '${codeName}' on 127.0.0.1:${port}`);
|
|
5862
|
-
const child = spawn(
|
|
5863
|
-
"tmux",
|
|
5864
|
-
["new-session", "-d", "-s", tmuxSession, "-c", projectDir, serveCmd],
|
|
5865
|
-
{ cwd: projectDir, stdio: ["ignore", "pipe", "pipe"], env: serveEnv }
|
|
5866
|
-
);
|
|
5867
|
-
child.on("close", (code) => {
|
|
5868
|
-
if (code !== 0) {
|
|
5869
|
-
log2(`[opencode-session] failed to create tmux session for '${codeName}' (exit ${code})`);
|
|
5870
|
-
session.status = "crashed";
|
|
5871
|
-
session.startedAt = Date.now();
|
|
5872
|
-
session.restartCount++;
|
|
5873
|
-
return;
|
|
5874
|
-
}
|
|
5875
|
-
log2(`[opencode-session] tmux session '${tmuxSession}' created for '${codeName}'`);
|
|
5876
|
-
setupPaneLog(tmuxSession, codeName, log2);
|
|
5877
|
-
});
|
|
5878
|
-
child.on("error", (err) => {
|
|
5879
|
-
log2(`[opencode-session] failed to start tmux for '${codeName}': ${err.message}`);
|
|
5880
|
-
session.status = "crashed";
|
|
5881
|
-
session.startedAt = Date.now();
|
|
5882
|
-
session.restartCount++;
|
|
5883
|
-
});
|
|
5884
|
-
session.port = port;
|
|
5885
|
-
session.password = password;
|
|
5886
|
-
session.startedAt = Date.now();
|
|
5887
|
-
session.status = "running";
|
|
5888
|
-
session.restartCount = 0;
|
|
5889
|
-
bridges.delete(codeName);
|
|
5890
|
-
stopTranscriptRefresher(codeName);
|
|
5891
|
-
startTranscriptRefresher(codeName);
|
|
5892
|
-
}
|
|
5893
|
-
function setupPaneLog(tmuxSession, codeName, log2) {
|
|
5894
|
-
const logPath = opencodePaneLogPath(codeName);
|
|
5895
|
-
try {
|
|
5896
|
-
execSync(`tmux pipe-pane -t ${tmuxSession} -o 'cat >> ${logPath}'`, { stdio: "ignore" });
|
|
5897
|
-
} catch (err) {
|
|
5898
|
-
log2(`[opencode-session] could not attach pane log for '${codeName}': ${err.message}`);
|
|
5899
|
-
}
|
|
5900
|
-
}
|
|
5901
|
-
function readOpencodePaneLogTail(codeName, lines = 40) {
|
|
5902
|
-
const logPath = opencodePaneLogPath(codeName);
|
|
5903
|
-
if (!existsSync10(logPath)) return null;
|
|
5904
|
-
try {
|
|
5905
|
-
const all = readFileSync16(logPath, "utf8").split("\n");
|
|
5906
|
-
return all.slice(-lines).join("\n");
|
|
5907
|
-
} catch {
|
|
5908
|
-
return null;
|
|
5909
|
-
}
|
|
5910
|
-
}
|
|
5911
|
-
function isOpencodeSessionHealthy(codeName) {
|
|
5912
|
-
const tmuxSession = opencodeTmuxSession(codeName);
|
|
5913
|
-
try {
|
|
5914
|
-
execSync(`tmux has-session -t ${tmuxSession} 2>/dev/null`, { stdio: "ignore" });
|
|
5915
|
-
return true;
|
|
5916
|
-
} catch {
|
|
5917
|
-
return false;
|
|
5918
|
-
}
|
|
5919
|
-
}
|
|
5920
|
-
async function injectOpencodeMessage(codeName, msg, opts = {}) {
|
|
5921
|
-
const session = sessions.get(codeName);
|
|
5922
|
-
if (!session || session.status !== "running" || !session.port || !session.password) {
|
|
5923
|
-
return { status: "declined", reason: "server_not_running" };
|
|
5924
|
-
}
|
|
5925
|
-
const bridge = getBridge(codeName, session.port, session.password);
|
|
5926
|
-
return bridge.handleInbound(msg, { gate: opts.gate, awaitReply: opts.awaitReply });
|
|
5927
|
-
}
|
|
5928
|
-
function getBridge(codeName, port, password) {
|
|
5929
|
-
const cached = bridges.get(codeName);
|
|
5930
|
-
if (cached && cached.port === port && cached.password === password) return cached.bridge;
|
|
5931
|
-
const client2 = new HttpOpencodeClient({ baseUrl: baseUrlFor(port), password });
|
|
5932
|
-
const model = sessions.get(codeName)?.model ?? null;
|
|
5933
|
-
const bridge = new OpencodeInboundBridge({
|
|
5934
|
-
client: client2,
|
|
5935
|
-
sessionDefaults: model ? { model } : void 0
|
|
5936
|
-
});
|
|
5937
|
-
bridges.set(codeName, { port, password, bridge });
|
|
5938
|
-
return bridge;
|
|
5939
|
-
}
|
|
5940
|
-
function stopOpencodeSession(codeName, log2) {
|
|
5941
|
-
const tmuxSession = opencodeTmuxSession(codeName);
|
|
5942
|
-
try {
|
|
5943
|
-
execSync(`tmux kill-session -t ${tmuxSession} 2>/dev/null`, { stdio: "ignore" });
|
|
5944
|
-
log2(`[opencode-session] stopped '${tmuxSession}' for '${codeName}'`);
|
|
5945
|
-
} catch {
|
|
5946
|
-
}
|
|
5947
|
-
stopTranscriptRefresher(codeName);
|
|
5948
|
-
bridges.delete(codeName);
|
|
5949
|
-
const session = sessions.get(codeName);
|
|
5950
|
-
if (session) {
|
|
5951
|
-
session.status = "stopped";
|
|
5952
|
-
session.port = null;
|
|
5953
|
-
session.password = null;
|
|
5954
|
-
}
|
|
5955
|
-
}
|
|
5956
|
-
function stripUndefined(env) {
|
|
5957
|
-
const out = {};
|
|
5958
|
-
for (const [k, v] of Object.entries(env)) if (v !== void 0) out[k] = v;
|
|
5959
|
-
return out;
|
|
5960
|
-
}
|
|
5961
|
-
var PROVIDER_KEY_RE = /^[A-Z][A-Z0-9_]*_API_KEY$/;
|
|
5962
|
-
function readAgentProviderEnv(codeName, dir) {
|
|
5963
|
-
const file = join20(dir ?? join20(homedir10(), ".augmented", codeName), ".env");
|
|
5964
|
-
const out = {};
|
|
5965
|
-
try {
|
|
5966
|
-
if (!existsSync10(file)) return out;
|
|
5967
|
-
for (const raw of readFileSync16(file, "utf-8").split("\n")) {
|
|
5968
|
-
const line = raw.trim();
|
|
5969
|
-
if (!line || line.startsWith("#")) continue;
|
|
5970
|
-
const eq = line.indexOf("=");
|
|
5971
|
-
if (eq <= 0) continue;
|
|
5972
|
-
const key = line.slice(0, eq).trim();
|
|
5973
|
-
if (!PROVIDER_KEY_RE.test(key)) continue;
|
|
5974
|
-
let val = line.slice(eq + 1).trim();
|
|
5975
|
-
if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
|
|
5976
|
-
val = val.slice(1, -1);
|
|
5977
|
-
}
|
|
5978
|
-
out[key] = val;
|
|
5979
|
-
}
|
|
5980
|
-
} catch {
|
|
5981
|
-
}
|
|
5982
|
-
return out;
|
|
5983
|
-
}
|
|
5984
|
-
|
|
5985
5524
|
// src/lib/opencode-slack-ingest.ts
|
|
5986
|
-
import { createHash as
|
|
5525
|
+
import { createHash as createHash10 } from "crypto";
|
|
5987
5526
|
|
|
5988
5527
|
// ../../packages/core/dist/channels/slack-rich-text.js
|
|
5989
5528
|
var MAX_DEPTH = 12;
|
|
@@ -6919,7 +6458,7 @@ function startSlackIngest(config2) {
|
|
|
6919
6458
|
// src/lib/opencode-slack-ingest.ts
|
|
6920
6459
|
var ingests = /* @__PURE__ */ new Map();
|
|
6921
6460
|
function fingerprint(params) {
|
|
6922
|
-
return
|
|
6461
|
+
return createHash10("sha256").update(
|
|
6923
6462
|
JSON.stringify({
|
|
6924
6463
|
appToken: params.appToken,
|
|
6925
6464
|
botToken: params.botToken,
|
|
@@ -7000,7 +6539,7 @@ function stopAllOpencodeSlackIngests(log2) {
|
|
|
7000
6539
|
}
|
|
7001
6540
|
|
|
7002
6541
|
// src/lib/manager/opencode-scheduler.ts
|
|
7003
|
-
import { createHash as
|
|
6542
|
+
import { createHash as createHash11 } from "crypto";
|
|
7004
6543
|
var MAX_OPENCODE_SCHED_CONCURRENCY = 2;
|
|
7005
6544
|
var opencodeSchedulerStates = /* @__PURE__ */ new Map();
|
|
7006
6545
|
var inFlightOpencodeTasks = /* @__PURE__ */ new Set();
|
|
@@ -7014,7 +6553,7 @@ function shouldDeliver(task, reply) {
|
|
|
7014
6553
|
}
|
|
7015
6554
|
async function syncAndCheckOpencodeScheduler(agent, tasks, refreshData) {
|
|
7016
6555
|
const codeName = agent.code_name;
|
|
7017
|
-
const tasksHash =
|
|
6556
|
+
const tasksHash = createHash11("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
|
|
7018
6557
|
if (knownOpencodeTaskHashes.get(agent.agent_id) !== tasksHash) {
|
|
7019
6558
|
const taskInputs = tasks.map((t) => buildSchedulerTaskInput(t));
|
|
7020
6559
|
const state8 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
|
|
@@ -7092,10 +6631,10 @@ async function fireOpencodeScheduledTask(agent, task) {
|
|
|
7092
6631
|
}
|
|
7093
6632
|
|
|
7094
6633
|
// src/lib/opencode-telegram-ingest.ts
|
|
7095
|
-
import { createHash as
|
|
7096
|
-
import { existsSync as
|
|
6634
|
+
import { createHash as createHash12 } from "crypto";
|
|
6635
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync15, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync9 } from "fs";
|
|
7097
6636
|
import { randomUUID } from "crypto";
|
|
7098
|
-
import { join as
|
|
6637
|
+
import { join as join19 } from "path";
|
|
7099
6638
|
|
|
7100
6639
|
// src/lib/telegram-ingest.ts
|
|
7101
6640
|
import https2 from "https";
|
|
@@ -7628,7 +7167,7 @@ function anySignal(signals) {
|
|
|
7628
7167
|
// src/lib/opencode-telegram-ingest.ts
|
|
7629
7168
|
var ingests2 = /* @__PURE__ */ new Map();
|
|
7630
7169
|
function fingerprint2(params) {
|
|
7631
|
-
return
|
|
7170
|
+
return createHash12("sha256").update(
|
|
7632
7171
|
JSON.stringify({
|
|
7633
7172
|
botToken: params.botToken,
|
|
7634
7173
|
allowedChats: [...params.allowedChats].sort(),
|
|
@@ -7643,7 +7182,7 @@ function createFileOffsetStore(codeName, log2, currentBotId) {
|
|
|
7643
7182
|
let filePath;
|
|
7644
7183
|
try {
|
|
7645
7184
|
dir = getFramework("opencode").getAgentDir(codeName);
|
|
7646
|
-
filePath =
|
|
7185
|
+
filePath = join19(dir, "telegram-getupdates-offset-opencode.json");
|
|
7647
7186
|
} catch {
|
|
7648
7187
|
dir = null;
|
|
7649
7188
|
filePath = null;
|
|
@@ -7652,7 +7191,7 @@ function createFileOffsetStore(codeName, log2, currentBotId) {
|
|
|
7652
7191
|
load() {
|
|
7653
7192
|
if (!filePath) return 0;
|
|
7654
7193
|
try {
|
|
7655
|
-
const parsed = JSON.parse(
|
|
7194
|
+
const parsed = JSON.parse(readFileSync15(filePath, "utf-8"));
|
|
7656
7195
|
if (currentBotId != null && typeof parsed?.bot_id === "number" && parsed.bot_id !== currentBotId) {
|
|
7657
7196
|
log2(`[telegram-ingest:${codeName}] offset cursor belongs to a different bot; ignoring (bot swap)`);
|
|
7658
7197
|
return 0;
|
|
@@ -7670,8 +7209,8 @@ function createFileOffsetStore(codeName, log2, currentBotId) {
|
|
|
7670
7209
|
if (!filePath || !dir) return;
|
|
7671
7210
|
const tmpPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
|
|
7672
7211
|
try {
|
|
7673
|
-
|
|
7674
|
-
|
|
7212
|
+
mkdirSync6(dir, { recursive: true, mode: 448 });
|
|
7213
|
+
writeFileSync9(
|
|
7675
7214
|
tmpPath,
|
|
7676
7215
|
JSON.stringify({
|
|
7677
7216
|
offset,
|
|
@@ -7685,7 +7224,7 @@ function createFileOffsetStore(codeName, log2, currentBotId) {
|
|
|
7685
7224
|
} catch (err) {
|
|
7686
7225
|
log2(`[telegram-ingest:${codeName}] offset persist failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
7687
7226
|
try {
|
|
7688
|
-
if (
|
|
7227
|
+
if (existsSync9(tmpPath)) unlinkSync(tmpPath);
|
|
7689
7228
|
} catch {
|
|
7690
7229
|
}
|
|
7691
7230
|
}
|
|
@@ -7902,24 +7441,24 @@ function partitionActionableByPoison(actionable, states, config2) {
|
|
|
7902
7441
|
}
|
|
7903
7442
|
|
|
7904
7443
|
// src/lib/restart-flags.ts
|
|
7905
|
-
import { existsSync as
|
|
7906
|
-
import { homedir as
|
|
7907
|
-
import { join as
|
|
7444
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync7, readdirSync as readdirSync4, readFileSync as readFileSync16, renameSync as renameSync3, rmSync as rmSync4, writeFileSync as writeFileSync10 } from "fs";
|
|
7445
|
+
import { homedir as homedir9 } from "os";
|
|
7446
|
+
import { join as join20 } from "path";
|
|
7908
7447
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
7909
7448
|
function restartFlagsDir() {
|
|
7910
|
-
return
|
|
7449
|
+
return join20(homedir9(), ".augmented", "restart-flags");
|
|
7911
7450
|
}
|
|
7912
7451
|
function flagPath(codeName) {
|
|
7913
|
-
return
|
|
7452
|
+
return join20(restartFlagsDir(), `${codeName}.flag`);
|
|
7914
7453
|
}
|
|
7915
7454
|
function readRestartFlags() {
|
|
7916
7455
|
const dir = restartFlagsDir();
|
|
7917
|
-
if (!
|
|
7456
|
+
if (!existsSync10(dir)) return [];
|
|
7918
7457
|
const out = [];
|
|
7919
7458
|
for (const entry of readdirSync4(dir)) {
|
|
7920
7459
|
if (!entry.endsWith(".flag")) continue;
|
|
7921
7460
|
try {
|
|
7922
|
-
const raw =
|
|
7461
|
+
const raw = readFileSync16(join20(dir, entry), "utf8");
|
|
7923
7462
|
const parsed = JSON.parse(raw);
|
|
7924
7463
|
if (typeof parsed.codeName !== "string" || parsed.codeName.length === 0) {
|
|
7925
7464
|
parsed.codeName = entry.replace(/\.flag$/, "");
|
|
@@ -7937,8 +7476,8 @@ function readRestartFlags() {
|
|
|
7937
7476
|
}
|
|
7938
7477
|
function deleteRestartFlag(codeName) {
|
|
7939
7478
|
const path = flagPath(codeName);
|
|
7940
|
-
if (
|
|
7941
|
-
|
|
7479
|
+
if (existsSync10(path)) {
|
|
7480
|
+
rmSync4(path, { force: true });
|
|
7942
7481
|
}
|
|
7943
7482
|
}
|
|
7944
7483
|
|
|
@@ -9183,15 +8722,15 @@ var runningChannelSecretHashes = /* @__PURE__ */ new Map();
|
|
|
9183
8722
|
var sessionLaunchManagedStructure = /* @__PURE__ */ new Map();
|
|
9184
8723
|
function projectMcpHash(_codeName, projectDir) {
|
|
9185
8724
|
try {
|
|
9186
|
-
const raw =
|
|
9187
|
-
return
|
|
8725
|
+
const raw = readFileSync17(join21(projectDir, ".mcp.json"), "utf-8");
|
|
8726
|
+
return createHash13("sha256").update(canonicalJson(JSON.parse(raw))).digest("hex");
|
|
9188
8727
|
} catch {
|
|
9189
8728
|
return null;
|
|
9190
8729
|
}
|
|
9191
8730
|
}
|
|
9192
8731
|
function projectMcpKeys(_codeName, projectDir) {
|
|
9193
8732
|
try {
|
|
9194
|
-
const raw =
|
|
8733
|
+
const raw = readFileSync17(join21(projectDir, ".mcp.json"), "utf-8");
|
|
9195
8734
|
const parsed = JSON.parse(raw);
|
|
9196
8735
|
const servers = parsed.mcpServers;
|
|
9197
8736
|
if (!servers || typeof servers !== "object") return /* @__PURE__ */ new Set();
|
|
@@ -9209,7 +8748,7 @@ function seedSessionLaunchBaselines(codeName, projectDir) {
|
|
|
9209
8748
|
else runningMcpServerKeys.delete(codeName);
|
|
9210
8749
|
let launchStructure = null;
|
|
9211
8750
|
try {
|
|
9212
|
-
const raw =
|
|
8751
|
+
const raw = readFileSync17(join21(projectDir, ".mcp.json"), "utf-8");
|
|
9213
8752
|
launchStructure = managedMcpStructureHashFromFile(
|
|
9214
8753
|
JSON.parse(raw),
|
|
9215
8754
|
isManagedMcpServerKey
|
|
@@ -9309,7 +8848,7 @@ async function runAgentSessionToolBindProbes(agent, integrations, projectDir, op
|
|
|
9309
8848
|
if (result && result.rebindCandidates.length > 0 && hostFlagStore().getBoolean("session-tool-rebind")) {
|
|
9310
8849
|
let mcpJsonForRebind = null;
|
|
9311
8850
|
try {
|
|
9312
|
-
mcpJsonForRebind = JSON.parse(
|
|
8851
|
+
mcpJsonForRebind = JSON.parse(readFileSync17(join21(projectDir, ".mcp.json"), "utf-8"));
|
|
9313
8852
|
} catch {
|
|
9314
8853
|
mcpJsonForRebind = null;
|
|
9315
8854
|
}
|
|
@@ -9438,7 +8977,7 @@ function checkMcpConfigDriftAndScheduleRestart(codeName, projectDir) {
|
|
|
9438
8977
|
function projectChannelSecretHash(projectDir) {
|
|
9439
8978
|
try {
|
|
9440
8979
|
const entries = parseEnvIntegrations(
|
|
9441
|
-
|
|
8980
|
+
readFileSync17(join21(projectDir, ".env.integrations"), "utf-8")
|
|
9442
8981
|
);
|
|
9443
8982
|
return channelSecretValueHash(entries, CHANNEL_SECRET_ENV_KEYS);
|
|
9444
8983
|
} catch {
|
|
@@ -9532,7 +9071,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
|
|
|
9532
9071
|
var lastVersionCheckAt = 0;
|
|
9533
9072
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
9534
9073
|
var lastResponsivenessProbeAt = 0;
|
|
9535
|
-
var agtCliVersion = true ? "0.28.
|
|
9074
|
+
var agtCliVersion = true ? "0.28.361" : "dev";
|
|
9536
9075
|
function resolveBrewPath(execFileSync2) {
|
|
9537
9076
|
try {
|
|
9538
9077
|
const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -9545,7 +9084,7 @@ function resolveBrewPath(execFileSync2) {
|
|
|
9545
9084
|
"/usr/local/bin/brew"
|
|
9546
9085
|
];
|
|
9547
9086
|
for (const path of fallbacks) {
|
|
9548
|
-
if (
|
|
9087
|
+
if (existsSync11(path)) return path;
|
|
9549
9088
|
}
|
|
9550
9089
|
return null;
|
|
9551
9090
|
}
|
|
@@ -9555,7 +9094,7 @@ function claudeBinaryInstalled(execFileSync2) {
|
|
|
9555
9094
|
"/opt/homebrew/bin/claude",
|
|
9556
9095
|
"/usr/local/bin/claude"
|
|
9557
9096
|
];
|
|
9558
|
-
if (canonical.some((path) =>
|
|
9097
|
+
if (canonical.some((path) => existsSync11(path))) return true;
|
|
9559
9098
|
try {
|
|
9560
9099
|
execFileSync2("which", ["claude"], { timeout: 5e3 });
|
|
9561
9100
|
return true;
|
|
@@ -9591,7 +9130,7 @@ async function ensureToolkitCli(toolkitSlug) {
|
|
|
9591
9130
|
}
|
|
9592
9131
|
const { binary, installer, package: pkg, script } = integration.cli_tool;
|
|
9593
9132
|
const resolvedInstaller = installer ?? "manual";
|
|
9594
|
-
const { execFileSync: execFileSync2, execSync
|
|
9133
|
+
const { execFileSync: execFileSync2, execSync } = await import("child_process");
|
|
9595
9134
|
try {
|
|
9596
9135
|
execFileSync2("which", [binary], { timeout: 5e3, stdio: "pipe" });
|
|
9597
9136
|
toolkitCliEnsured.add(toolkitSlug);
|
|
@@ -9627,7 +9166,7 @@ async function ensureToolkitCli(toolkitSlug) {
|
|
|
9627
9166
|
toolkitCliEnsured.add(toolkitSlug);
|
|
9628
9167
|
return;
|
|
9629
9168
|
}
|
|
9630
|
-
brewBinDir =
|
|
9169
|
+
brewBinDir = dirname5(brewPath);
|
|
9631
9170
|
const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
|
|
9632
9171
|
log(`[toolkit-install] ${toolkitSlug}: installing via brew (${pkg})\u2026`);
|
|
9633
9172
|
if (isRoot) {
|
|
@@ -9642,7 +9181,7 @@ async function ensureToolkitCli(toolkitSlug) {
|
|
|
9642
9181
|
return;
|
|
9643
9182
|
}
|
|
9644
9183
|
log(`[toolkit-install] ${toolkitSlug}: running declared install script\u2026`);
|
|
9645
|
-
|
|
9184
|
+
execSync(script, { timeout: 18e4, stdio: "pipe" });
|
|
9646
9185
|
}
|
|
9647
9186
|
} catch (err) {
|
|
9648
9187
|
const e = err;
|
|
@@ -9666,8 +9205,8 @@ async function ensureToolkitCli(toolkitSlug) {
|
|
|
9666
9205
|
}
|
|
9667
9206
|
function runAsync(cmd, args, opts) {
|
|
9668
9207
|
return new Promise((resolve, reject) => {
|
|
9669
|
-
import("child_process").then(({ spawn
|
|
9670
|
-
const child =
|
|
9208
|
+
import("child_process").then(({ spawn }) => {
|
|
9209
|
+
const child = spawn(cmd, args, { stdio: ["ignore", "pipe", "pipe"], cwd: opts.cwd });
|
|
9671
9210
|
let stdout = "";
|
|
9672
9211
|
let stderr = "";
|
|
9673
9212
|
let settled = false;
|
|
@@ -9710,8 +9249,8 @@ function claudeManagedSettingsPath() {
|
|
|
9710
9249
|
function ensureClaudeManagedSettings(path = claudeManagedSettingsPath()) {
|
|
9711
9250
|
try {
|
|
9712
9251
|
let settings = {};
|
|
9713
|
-
if (
|
|
9714
|
-
const raw =
|
|
9252
|
+
if (existsSync11(path)) {
|
|
9253
|
+
const raw = readFileSync17(path, "utf-8").trim();
|
|
9715
9254
|
if (raw) {
|
|
9716
9255
|
let parsed;
|
|
9717
9256
|
try {
|
|
@@ -9727,8 +9266,8 @@ function ensureClaudeManagedSettings(path = claudeManagedSettingsPath()) {
|
|
|
9727
9266
|
}
|
|
9728
9267
|
if (settings.channelsEnabled === true) return "ok";
|
|
9729
9268
|
settings.channelsEnabled = true;
|
|
9730
|
-
|
|
9731
|
-
|
|
9269
|
+
mkdirSync8(dirname5(path), { recursive: true });
|
|
9270
|
+
writeFileSync11(path, `${JSON.stringify(settings, null, 2)}
|
|
9732
9271
|
`);
|
|
9733
9272
|
log(`[managed-settings] set channelsEnabled:true in ${path} (ENG-5786 \u2014 unblocks Claude Code channels)`);
|
|
9734
9273
|
return "ok";
|
|
@@ -9766,7 +9305,7 @@ async function ensureOpencodeBinary() {
|
|
|
9766
9305
|
try {
|
|
9767
9306
|
const prefix = execFileSync2("npm", ["prefix", "-g"], { encoding: "utf-8", timeout: 1e4 }).trim();
|
|
9768
9307
|
if (prefix) {
|
|
9769
|
-
const npmBin =
|
|
9308
|
+
const npmBin = join21(prefix, "bin");
|
|
9770
9309
|
const current = (process.env.PATH ?? "").split(pathDelimiter);
|
|
9771
9310
|
if (!current.includes(npmBin)) {
|
|
9772
9311
|
process.env.PATH = [npmBin, ...current.filter(Boolean)].join(pathDelimiter);
|
|
@@ -9823,11 +9362,11 @@ async function ensureFrameworkBinary(frameworkId) {
|
|
|
9823
9362
|
log(`Claude Code install failed: ${err.message}`);
|
|
9824
9363
|
return;
|
|
9825
9364
|
}
|
|
9826
|
-
const brewBinDir =
|
|
9365
|
+
const brewBinDir = dirname5(brewPath);
|
|
9827
9366
|
if (!process.env.PATH?.split(":").includes(brewBinDir)) {
|
|
9828
9367
|
process.env.PATH = `${brewBinDir}:${process.env.PATH ?? ""}`;
|
|
9829
9368
|
}
|
|
9830
|
-
if (
|
|
9369
|
+
if (existsSync11("/home/linuxbrew/.linuxbrew/bin/claude")) {
|
|
9831
9370
|
log("Claude Code installed successfully");
|
|
9832
9371
|
} else {
|
|
9833
9372
|
log("Claude Code install completed but binary not found at expected path \u2014 check brew logs");
|
|
@@ -9883,7 +9422,7 @@ ${r.stderr}`;
|
|
|
9883
9422
|
}
|
|
9884
9423
|
var UPDATE_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
9885
9424
|
function selfUpdateAppliedMarkerPath() {
|
|
9886
|
-
return
|
|
9425
|
+
return join21(homedir10(), ".augmented", ".last-self-update-applied");
|
|
9887
9426
|
}
|
|
9888
9427
|
var selfUpdateUpToDateLogged = false;
|
|
9889
9428
|
var selfUpdatePinnedLogged = false;
|
|
@@ -9909,7 +9448,7 @@ async function checkAndUpdateCli(opts) {
|
|
|
9909
9448
|
const isNpmGlobal = !isBrewFormula && resolvedPath.includes("node_modules");
|
|
9910
9449
|
if (!isBrewFormula && !isNpmGlobal) return "noop";
|
|
9911
9450
|
const { readFileSync: readF, writeFileSync: writeF } = await import("fs");
|
|
9912
|
-
const markerPath =
|
|
9451
|
+
const markerPath = join21(homedir10(), ".augmented", ".last-update-check");
|
|
9913
9452
|
if (!force) {
|
|
9914
9453
|
try {
|
|
9915
9454
|
const lastCheck = parseInt(readF(markerPath, "utf-8").trim(), 10);
|
|
@@ -10254,14 +9793,14 @@ async function checkClaudeAuth() {
|
|
|
10254
9793
|
}
|
|
10255
9794
|
var evalEmptyMcpConfigPath = null;
|
|
10256
9795
|
function ensureEvalEmptyMcpConfig() {
|
|
10257
|
-
if (evalEmptyMcpConfigPath &&
|
|
10258
|
-
const dir =
|
|
9796
|
+
if (evalEmptyMcpConfigPath && existsSync11(evalEmptyMcpConfigPath)) return evalEmptyMcpConfigPath;
|
|
9797
|
+
const dir = join21(homedir10(), ".augmented");
|
|
10259
9798
|
try {
|
|
10260
|
-
|
|
9799
|
+
mkdirSync8(dir, { recursive: true });
|
|
10261
9800
|
} catch {
|
|
10262
9801
|
}
|
|
10263
|
-
const p =
|
|
10264
|
-
|
|
9802
|
+
const p = join21(dir, ".eval-empty-mcp.json");
|
|
9803
|
+
writeFileSync11(p, JSON.stringify({ mcpServers: {} }));
|
|
10265
9804
|
evalEmptyMcpConfigPath = p;
|
|
10266
9805
|
return p;
|
|
10267
9806
|
}
|
|
@@ -10286,7 +9825,7 @@ async function runEvalClaude(prompt, model) {
|
|
|
10286
9825
|
""
|
|
10287
9826
|
];
|
|
10288
9827
|
const { stdout } = await execFilePromiseLong(resolveClaudeBinary(), args, {
|
|
10289
|
-
cwd:
|
|
9828
|
+
cwd: homedir10(),
|
|
10290
9829
|
timeout: 12e4,
|
|
10291
9830
|
stdin: "ignore",
|
|
10292
9831
|
env: childEnv,
|
|
@@ -10352,10 +9891,10 @@ function resolveConversationEvalBackend() {
|
|
|
10352
9891
|
return conversationEvalBackend;
|
|
10353
9892
|
}
|
|
10354
9893
|
function getStateFile() {
|
|
10355
|
-
return
|
|
9894
|
+
return join21(config?.configDir ?? join21(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
|
|
10356
9895
|
}
|
|
10357
9896
|
function channelHashCacheDir() {
|
|
10358
|
-
return config?.configDir ??
|
|
9897
|
+
return config?.configDir ?? join21(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
10359
9898
|
}
|
|
10360
9899
|
function loadChannelHashCache2() {
|
|
10361
9900
|
loadChannelHashCache(agentState.knownChannelConfigHashes, channelHashCacheDir());
|
|
@@ -10407,7 +9946,7 @@ function removeDeliveryBaselineEntries(agentId) {
|
|
|
10407
9946
|
var _channelQuarantineStore = null;
|
|
10408
9947
|
function channelQuarantineStore() {
|
|
10409
9948
|
if (!_channelQuarantineStore) {
|
|
10410
|
-
const dir = config?.configDir ??
|
|
9949
|
+
const dir = config?.configDir ?? join21(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
10411
9950
|
_channelQuarantineStore = new ChannelQuarantineStore(defaultQuarantinePath(dir));
|
|
10412
9951
|
}
|
|
10413
9952
|
return _channelQuarantineStore;
|
|
@@ -10415,7 +9954,7 @@ function channelQuarantineStore() {
|
|
|
10415
9954
|
var _hostFlagStore = null;
|
|
10416
9955
|
function hostFlagStore() {
|
|
10417
9956
|
if (!_hostFlagStore) {
|
|
10418
|
-
const dir = config?.configDir ??
|
|
9957
|
+
const dir = config?.configDir ?? join21(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
10419
9958
|
_hostFlagStore = new HostFlagStore({ cachePath: defaultFlagsCachePath(dir), log });
|
|
10420
9959
|
}
|
|
10421
9960
|
return _hostFlagStore;
|
|
@@ -10482,13 +10021,13 @@ function parseSkillFrontmatter(content) {
|
|
|
10482
10021
|
return out;
|
|
10483
10022
|
}
|
|
10484
10023
|
async function refreshSkillsIndexInClaudeMd(configDir, codeName, log2) {
|
|
10485
|
-
const { readdirSync: readdirSync6, readFileSync: rfs, existsSync: ex, writeFileSync:
|
|
10486
|
-
const skillsDir =
|
|
10487
|
-
const claudeMdPath =
|
|
10024
|
+
const { readdirSync: readdirSync6, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync12 } = await import("fs");
|
|
10025
|
+
const skillsDir = join21(configDir, codeName, "project", ".claude", "skills");
|
|
10026
|
+
const claudeMdPath = join21(configDir, codeName, "project", "CLAUDE.md");
|
|
10488
10027
|
if (!ex(skillsDir) || !ex(claudeMdPath)) return;
|
|
10489
10028
|
const entries = [];
|
|
10490
10029
|
for (const dir of readdirSync6(skillsDir).sort()) {
|
|
10491
|
-
const skillFile =
|
|
10030
|
+
const skillFile = join21(skillsDir, dir, "SKILL.md");
|
|
10492
10031
|
if (!ex(skillFile)) continue;
|
|
10493
10032
|
try {
|
|
10494
10033
|
const { name, description } = parseSkillFrontmatter(rfs(skillFile, "utf-8"));
|
|
@@ -10530,7 +10069,7 @@ ${SKILLS_INDEX_END}`;
|
|
|
10530
10069
|
next = current.trimEnd() + "\n\n" + section + "\n";
|
|
10531
10070
|
}
|
|
10532
10071
|
if (next !== current) {
|
|
10533
|
-
|
|
10072
|
+
writeFileSync12(claudeMdPath, next, "utf-8");
|
|
10534
10073
|
log2(`Refreshed skills index in CLAUDE.md for '${codeName}' (${entries.length} skills)`);
|
|
10535
10074
|
}
|
|
10536
10075
|
}
|
|
@@ -10551,7 +10090,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
|
|
|
10551
10090
|
if (codeNames.length === 0) return;
|
|
10552
10091
|
void (async () => {
|
|
10553
10092
|
try {
|
|
10554
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
10093
|
+
const { collectDiagnostics } = await import("../persistent-session-7VMIE4G4.js");
|
|
10555
10094
|
await api.post("/host/heartbeat", {
|
|
10556
10095
|
host_id: hostId,
|
|
10557
10096
|
agent_diagnostics: collectDiagnostics(codeNames)
|
|
@@ -10650,7 +10189,7 @@ async function pollCycle() {
|
|
|
10650
10189
|
}
|
|
10651
10190
|
try {
|
|
10652
10191
|
const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
|
|
10653
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
10192
|
+
const { collectDiagnostics } = await import("../persistent-session-7VMIE4G4.js");
|
|
10654
10193
|
const diagCodeNames = [...agentState.persistentSessionAgents];
|
|
10655
10194
|
const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
|
|
10656
10195
|
let tailscaleHostname;
|
|
@@ -10671,8 +10210,8 @@ async function pollCycle() {
|
|
|
10671
10210
|
}
|
|
10672
10211
|
let osUsername;
|
|
10673
10212
|
try {
|
|
10674
|
-
const { userInfo
|
|
10675
|
-
osUsername =
|
|
10213
|
+
const { userInfo } = await import("os");
|
|
10214
|
+
osUsername = userInfo().username;
|
|
10676
10215
|
} catch {
|
|
10677
10216
|
}
|
|
10678
10217
|
let claudeAuth = null;
|
|
@@ -10680,7 +10219,7 @@ async function pollCycle() {
|
|
|
10680
10219
|
claudeAuth = await detectClaudeAuth();
|
|
10681
10220
|
} catch (err) {
|
|
10682
10221
|
const errText = err instanceof Error ? err.message : String(err);
|
|
10683
|
-
const errId =
|
|
10222
|
+
const errId = createHash13("sha256").update(errText).digest("hex").slice(0, 12);
|
|
10684
10223
|
log(`Claude auth detection failed (error_id=${errId})`);
|
|
10685
10224
|
}
|
|
10686
10225
|
const hostHasClaudeCode = state6.agents.some(
|
|
@@ -10805,7 +10344,7 @@ async function pollCycle() {
|
|
|
10805
10344
|
const {
|
|
10806
10345
|
collectResponsivenessProbes,
|
|
10807
10346
|
getResponsivenessIntervalMs
|
|
10808
|
-
} = await import("../responsiveness-probe-
|
|
10347
|
+
} = await import("../responsiveness-probe-XJ7DQX4M.js");
|
|
10809
10348
|
const probeIntervalMs = getResponsivenessIntervalMs();
|
|
10810
10349
|
if (now - lastResponsivenessProbeAt > probeIntervalMs) {
|
|
10811
10350
|
const probeCodeNames = [...agentState.persistentSessionAgents];
|
|
@@ -10837,7 +10376,7 @@ async function pollCycle() {
|
|
|
10837
10376
|
collectResponsivenessProbes,
|
|
10838
10377
|
livePendingInboundOldestAgeSeconds,
|
|
10839
10378
|
parkPendingInbound
|
|
10840
|
-
} = await import("../responsiveness-probe-
|
|
10379
|
+
} = await import("../responsiveness-probe-XJ7DQX4M.js");
|
|
10841
10380
|
const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-HYOOQV4A.js");
|
|
10842
10381
|
const wedgeNow = /* @__PURE__ */ new Date();
|
|
10843
10382
|
const liveAgents = agentState.persistentSessionAgents;
|
|
@@ -10926,13 +10465,13 @@ async function pollCycle() {
|
|
|
10926
10465
|
);
|
|
10927
10466
|
if (hostFlagStore().getBoolean("wedge-transient-notice")) {
|
|
10928
10467
|
try {
|
|
10929
|
-
const paneTail =
|
|
10468
|
+
const paneTail = readFileSync17(paneLogPath(codeName), "utf8").slice(-65536);
|
|
10930
10469
|
const transient = detectTransientApiErrorInLog(paneTail);
|
|
10931
10470
|
if (transient) {
|
|
10932
|
-
const wedgeHome =
|
|
10933
|
-
if (
|
|
10471
|
+
const wedgeHome = join21(homedir10(), ".augmented", codeName);
|
|
10472
|
+
if (existsSync11(wedgeHome)) {
|
|
10934
10473
|
atomicWriteFileSync(
|
|
10935
|
-
|
|
10474
|
+
join21(wedgeHome, "watchdog-give-up.json"),
|
|
10936
10475
|
JSON.stringify({
|
|
10937
10476
|
gave_up_at: wedgeNow.toISOString(),
|
|
10938
10477
|
reason: "transient_overload"
|
|
@@ -11181,7 +10720,7 @@ async function pollCycle() {
|
|
|
11181
10720
|
} catch {
|
|
11182
10721
|
}
|
|
11183
10722
|
killAgentChannelProcesses(prev.codeName, { log });
|
|
11184
|
-
const agentDir =
|
|
10723
|
+
const agentDir = join21(adapter.getAgentDir(prev.codeName), "provision");
|
|
11185
10724
|
await cleanupAgentFiles(prev.codeName, agentDir);
|
|
11186
10725
|
clearAgentCaches(prev.agentId, prev.codeName);
|
|
11187
10726
|
}
|
|
@@ -11268,10 +10807,10 @@ async function pollCycle() {
|
|
|
11268
10807
|
// pending-inbound marker. Best-effort: a write failure is logged by
|
|
11269
10808
|
// the watchdog, never fails the poll cycle.
|
|
11270
10809
|
signalGiveUp: (codeName) => {
|
|
11271
|
-
const dir =
|
|
11272
|
-
if (!
|
|
10810
|
+
const dir = join21(homedir10(), ".augmented", codeName);
|
|
10811
|
+
if (!existsSync11(dir)) return;
|
|
11273
10812
|
atomicWriteFileSync(
|
|
11274
|
-
|
|
10813
|
+
join21(dir, "watchdog-give-up.json"),
|
|
11275
10814
|
JSON.stringify({ gave_up_at: (/* @__PURE__ */ new Date()).toISOString() })
|
|
11276
10815
|
);
|
|
11277
10816
|
}
|
|
@@ -11410,7 +10949,7 @@ async function processAgent(agent, agentStates) {
|
|
|
11410
10949
|
}
|
|
11411
10950
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
11412
10951
|
const adapter = resolveAgentFramework(agent.code_name);
|
|
11413
|
-
let agentDir =
|
|
10952
|
+
let agentDir = join21(adapter.getAgentDir(agent.code_name), "provision");
|
|
11414
10953
|
if (agent.status === "draft" || agent.status === "paused") {
|
|
11415
10954
|
if (previousKnownStatus !== agent.status) {
|
|
11416
10955
|
log(`Agent '${agent.code_name}' is ${agent.status}, skipping provisioning`);
|
|
@@ -11456,7 +10995,7 @@ async function processAgent(agent, agentStates) {
|
|
|
11456
10995
|
const residuals = {
|
|
11457
10996
|
gatewayRunning: false,
|
|
11458
10997
|
portAllocated: false,
|
|
11459
|
-
provisionDirExists:
|
|
10998
|
+
provisionDirExists: existsSync11(agentDir)
|
|
11460
10999
|
};
|
|
11461
11000
|
if (!hasRevokedResiduals(residuals)) {
|
|
11462
11001
|
agentStates.push({
|
|
@@ -11594,7 +11133,7 @@ async function processAgent(agent, agentStates) {
|
|
|
11594
11133
|
const frameworkId = refreshData.agent.framework ?? DEFAULT_FRAMEWORK;
|
|
11595
11134
|
agentFrameworkCache.set(agent.code_name, frameworkId);
|
|
11596
11135
|
const frameworkAdapter = getFramework(frameworkId);
|
|
11597
|
-
agentDir =
|
|
11136
|
+
agentDir = join21(frameworkAdapter.getAgentDir(agent.code_name), "provision");
|
|
11598
11137
|
cacheAgentDeliveryMetadata(agent.code_name, refreshData);
|
|
11599
11138
|
agentRestartTimezoneInputs.set(agent.code_name, {
|
|
11600
11139
|
agentTimezone: typeof refreshData.agent.timezone === "string" ? refreshData.agent.timezone : null,
|
|
@@ -11639,9 +11178,9 @@ async function processAgent(agent, agentStates) {
|
|
|
11639
11178
|
try {
|
|
11640
11179
|
const artifacts = generateArtifacts(agent, refreshData, frameworkAdapter);
|
|
11641
11180
|
const changedFiles = [];
|
|
11642
|
-
|
|
11181
|
+
mkdirSync8(agentDir, { recursive: true });
|
|
11643
11182
|
for (const artifact of artifacts) {
|
|
11644
|
-
const filePath =
|
|
11183
|
+
const filePath = join21(agentDir, artifact.relativePath);
|
|
11645
11184
|
let existingHash;
|
|
11646
11185
|
let newHash;
|
|
11647
11186
|
let writeContent = artifact.content;
|
|
@@ -11660,8 +11199,8 @@ async function processAgent(agent, agentStates) {
|
|
|
11660
11199
|
};
|
|
11661
11200
|
newHash = sha256(stripDynamicSections(artifact.content));
|
|
11662
11201
|
try {
|
|
11663
|
-
const projectClaudeMd =
|
|
11664
|
-
const existing =
|
|
11202
|
+
const projectClaudeMd = join21(config.configDir, agent.code_name, "project", "CLAUDE.md");
|
|
11203
|
+
const existing = readFileSync17(projectClaudeMd, "utf-8");
|
|
11665
11204
|
existingHash = sha256(stripDynamicSections(existing));
|
|
11666
11205
|
} catch {
|
|
11667
11206
|
existingHash = null;
|
|
@@ -11679,7 +11218,7 @@ async function processAgent(agent, agentStates) {
|
|
|
11679
11218
|
const generatorKeys = Object.keys(generatorServers);
|
|
11680
11219
|
let existingRaw = "";
|
|
11681
11220
|
try {
|
|
11682
|
-
existingRaw =
|
|
11221
|
+
existingRaw = readFileSync17(filePath, "utf-8");
|
|
11683
11222
|
} catch {
|
|
11684
11223
|
}
|
|
11685
11224
|
const existingServers = parseMcp(existingRaw);
|
|
@@ -11701,26 +11240,26 @@ async function processAgent(agent, agentStates) {
|
|
|
11701
11240
|
}
|
|
11702
11241
|
}
|
|
11703
11242
|
if (changedFiles.length > 0) {
|
|
11704
|
-
const isFirst = !
|
|
11243
|
+
const isFirst = !existsSync11(join21(agentDir, "CHARTER.md"));
|
|
11705
11244
|
const verb = isFirst ? "Provisioning" : "Updating";
|
|
11706
11245
|
const fileNames = changedFiles.map((f) => f.relativePath).join(", ");
|
|
11707
11246
|
log(`${verb} '${agent.code_name}': ${fileNames}`);
|
|
11708
11247
|
for (const file of changedFiles) {
|
|
11709
|
-
const filePath =
|
|
11710
|
-
|
|
11248
|
+
const filePath = join21(agentDir, file.relativePath);
|
|
11249
|
+
mkdirSync8(dirname5(filePath), { recursive: true });
|
|
11711
11250
|
if (file.relativePath === ".mcp.json") {
|
|
11712
11251
|
safeWriteJsonAtomic(filePath, file.content, { mode: 384 });
|
|
11713
11252
|
} else {
|
|
11714
|
-
|
|
11253
|
+
writeFileSync11(filePath, file.content);
|
|
11715
11254
|
}
|
|
11716
11255
|
}
|
|
11717
11256
|
try {
|
|
11718
|
-
const provSkillsDir =
|
|
11719
|
-
if (
|
|
11257
|
+
const provSkillsDir = join21(agentDir, ".claude", "skills");
|
|
11258
|
+
if (existsSync11(provSkillsDir)) {
|
|
11720
11259
|
for (const folder of readdirSync5(provSkillsDir)) {
|
|
11721
11260
|
if (folder.startsWith("knowledge-")) {
|
|
11722
11261
|
try {
|
|
11723
|
-
|
|
11262
|
+
rmSync5(join21(provSkillsDir, folder), { recursive: true });
|
|
11724
11263
|
} catch {
|
|
11725
11264
|
}
|
|
11726
11265
|
}
|
|
@@ -11733,7 +11272,7 @@ async function processAgent(agent, agentStates) {
|
|
|
11733
11272
|
const trackedFiles2 = frameworkAdapter.driftTrackedFiles();
|
|
11734
11273
|
const hashes = /* @__PURE__ */ new Map();
|
|
11735
11274
|
for (const file of trackedFiles2) {
|
|
11736
|
-
const h = hashFile(
|
|
11275
|
+
const h = hashFile(join21(agentDir, file));
|
|
11737
11276
|
if (h) hashes.set(file, h);
|
|
11738
11277
|
}
|
|
11739
11278
|
agentState.writtenHashes.set(agent.agent_id, hashes);
|
|
@@ -11751,14 +11290,14 @@ async function processAgent(agent, agentStates) {
|
|
|
11751
11290
|
}
|
|
11752
11291
|
if (Array.isArray(refreshData.workflows)) {
|
|
11753
11292
|
try {
|
|
11754
|
-
const provWorkflowsDir =
|
|
11755
|
-
if (
|
|
11293
|
+
const provWorkflowsDir = join21(agentDir, ".claude", "workflows");
|
|
11294
|
+
if (existsSync11(provWorkflowsDir)) {
|
|
11756
11295
|
const expected = new Set(refreshData.workflows.map((w) => `${w.name}.js`));
|
|
11757
11296
|
for (const file of readdirSync5(provWorkflowsDir)) {
|
|
11758
11297
|
if (!file.endsWith(".js")) continue;
|
|
11759
11298
|
if (expected.has(file)) continue;
|
|
11760
11299
|
try {
|
|
11761
|
-
|
|
11300
|
+
rmSync5(join21(provWorkflowsDir, file));
|
|
11762
11301
|
} catch {
|
|
11763
11302
|
}
|
|
11764
11303
|
}
|
|
@@ -11837,10 +11376,10 @@ async function processAgent(agent, agentStates) {
|
|
|
11837
11376
|
}
|
|
11838
11377
|
let lastDriftCheckAt = now;
|
|
11839
11378
|
const written = agentState.writtenHashes.get(agent.agent_id);
|
|
11840
|
-
if (written &&
|
|
11379
|
+
if (written && existsSync11(agentDir)) {
|
|
11841
11380
|
const driftedFiles = [];
|
|
11842
11381
|
for (const [file, expectedHash] of written) {
|
|
11843
|
-
const localHash = hashFile(
|
|
11382
|
+
const localHash = hashFile(join21(agentDir, file));
|
|
11844
11383
|
if (localHash && localHash !== expectedHash) {
|
|
11845
11384
|
driftedFiles.push(file);
|
|
11846
11385
|
}
|
|
@@ -11851,7 +11390,7 @@ async function processAgent(agent, agentStates) {
|
|
|
11851
11390
|
try {
|
|
11852
11391
|
const localHashes = {};
|
|
11853
11392
|
for (const file of driftedFiles) {
|
|
11854
|
-
localHashes[file] = hashFile(
|
|
11393
|
+
localHashes[file] = hashFile(join21(agentDir, file));
|
|
11855
11394
|
}
|
|
11856
11395
|
await api.post("/host/drift", {
|
|
11857
11396
|
agent_id: agent.agent_id,
|
|
@@ -12038,15 +11577,15 @@ async function processAgent(agent, agentStates) {
|
|
|
12038
11577
|
const addedChannels = [...restartDecision.added];
|
|
12039
11578
|
const writeDmNoticeMarkers = isChannelAddRestart ? () => {
|
|
12040
11579
|
try {
|
|
12041
|
-
const agentAugmentedDir =
|
|
12042
|
-
|
|
11580
|
+
const agentAugmentedDir = join21(homedir10(), ".augmented", agent.code_name);
|
|
11581
|
+
mkdirSync8(agentAugmentedDir, { recursive: true });
|
|
12043
11582
|
const markerJson = JSON.stringify({
|
|
12044
11583
|
version: 1,
|
|
12045
11584
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12046
11585
|
added: addedChannels
|
|
12047
11586
|
});
|
|
12048
11587
|
for (const file of ["slack-channel-add-restart.json", "telegram-channel-add-restart.json"]) {
|
|
12049
|
-
atomicWriteFileSync(
|
|
11588
|
+
atomicWriteFileSync(join21(agentAugmentedDir, file), markerJson);
|
|
12050
11589
|
}
|
|
12051
11590
|
} catch (err) {
|
|
12052
11591
|
log(`[hot-reload] channel-add DM-notice marker write failed for '${agent.code_name}' (non-fatal): ${err.message}`);
|
|
@@ -12122,7 +11661,7 @@ async function processAgent(agent, agentStates) {
|
|
|
12122
11661
|
const behaviourSubset = extractMsTeamsBehaviourSubset(
|
|
12123
11662
|
msteamsEntry?.config
|
|
12124
11663
|
);
|
|
12125
|
-
const behaviourHash =
|
|
11664
|
+
const behaviourHash = createHash13("sha256").update(canonicalJson(behaviourSubset)).digest("hex");
|
|
12126
11665
|
const prevBehaviourHash = agentState.knownMsTeamsBehaviourHashes.get(agent.agent_id);
|
|
12127
11666
|
const msteamsBehaviourRestrictive = isMsTeamsBehaviourRestrictive(behaviourSubset);
|
|
12128
11667
|
const behaviourDecision = decideSenderPolicyRestart({
|
|
@@ -12178,7 +11717,7 @@ async function processAgent(agent, agentStates) {
|
|
|
12178
11717
|
const slackBehaviourSubset = extractSlackBehaviourSubset(
|
|
12179
11718
|
slackEntry?.config
|
|
12180
11719
|
);
|
|
12181
|
-
const slackBehaviourHash =
|
|
11720
|
+
const slackBehaviourHash = createHash13("sha256").update(canonicalJson(slackBehaviourSubset)).digest("hex");
|
|
12182
11721
|
const prevSlackBehaviourHash = agentState.knownSlackBehaviourHashes.get(agent.agent_id);
|
|
12183
11722
|
const slackBehaviourRestrictive = isSlackBehaviourRestrictive(slackBehaviourSubset);
|
|
12184
11723
|
const slackBehaviourDecision = decideSenderPolicyRestart({
|
|
@@ -12235,24 +11774,24 @@ async function processAgent(agent, agentStates) {
|
|
|
12235
11774
|
if (agentSessionMode === "persistent" && (agentFrameworkCache.get(agent.code_name) ?? DEFAULT_FRAMEWORK) === "claude-code") {
|
|
12236
11775
|
try {
|
|
12237
11776
|
const agentProvisionDir = agentDir;
|
|
12238
|
-
const projectDir =
|
|
12239
|
-
|
|
12240
|
-
|
|
12241
|
-
const provisionMcpPath =
|
|
12242
|
-
const projectMcpPath =
|
|
11777
|
+
const projectDir = join21(homedir10(), ".augmented", agent.code_name, "project");
|
|
11778
|
+
mkdirSync8(agentProvisionDir, { recursive: true });
|
|
11779
|
+
mkdirSync8(projectDir, { recursive: true });
|
|
11780
|
+
const provisionMcpPath = join21(agentProvisionDir, ".mcp.json");
|
|
11781
|
+
const projectMcpPath = join21(projectDir, ".mcp.json");
|
|
12243
11782
|
let mcpConfig = { mcpServers: {} };
|
|
12244
11783
|
try {
|
|
12245
|
-
mcpConfig = JSON.parse(
|
|
11784
|
+
mcpConfig = JSON.parse(readFileSync17(provisionMcpPath, "utf-8"));
|
|
12246
11785
|
if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
|
|
12247
11786
|
} catch {
|
|
12248
11787
|
}
|
|
12249
|
-
const localDirectChatChannel =
|
|
11788
|
+
const localDirectChatChannel = join21(homedir10(), ".augmented", "_mcp", "direct-chat-channel.js");
|
|
12250
11789
|
const directChatTeamSettings = refreshData.team?.settings;
|
|
12251
11790
|
const directChatTz = (() => {
|
|
12252
11791
|
const tz = directChatTeamSettings?.["timezone"];
|
|
12253
11792
|
return typeof tz === "string" && tz.trim() !== "" ? tz.trim() : void 0;
|
|
12254
11793
|
})();
|
|
12255
|
-
if (
|
|
11794
|
+
if (existsSync11(localDirectChatChannel)) {
|
|
12256
11795
|
const directChatEnv = {
|
|
12257
11796
|
AGT_HOST: requireHost(),
|
|
12258
11797
|
// ENG-5901 Track D: templated — the manager exports the real
|
|
@@ -12272,7 +11811,7 @@ async function processAgent(agent, agentStates) {
|
|
|
12272
11811
|
// ~/.augmented/<codeName>/.current-turn-initiator.json. Note getAgentDir
|
|
12273
11812
|
// returns the agent root (NOT the /provision subdir `agentDir` points at),
|
|
12274
11813
|
// so it byte-matches the broker readers' path.
|
|
12275
|
-
AGT_TURN_INITIATOR_FILE:
|
|
11814
|
+
AGT_TURN_INITIATOR_FILE: join21(
|
|
12276
11815
|
frameworkAdapter.getAgentDir(agent.code_name),
|
|
12277
11816
|
".current-turn-initiator.json"
|
|
12278
11817
|
)
|
|
@@ -12292,10 +11831,10 @@ async function processAgent(agent, agentStates) {
|
|
|
12292
11831
|
log(`Channel credentials written for '${agent.code_name}/direct-chat'`);
|
|
12293
11832
|
}
|
|
12294
11833
|
}
|
|
12295
|
-
const staleChannelsPath =
|
|
12296
|
-
if (
|
|
11834
|
+
const staleChannelsPath = join21(projectDir, ".mcp-channels.json");
|
|
11835
|
+
if (existsSync11(staleChannelsPath)) {
|
|
12297
11836
|
try {
|
|
12298
|
-
|
|
11837
|
+
rmSync5(staleChannelsPath, { force: true });
|
|
12299
11838
|
} catch {
|
|
12300
11839
|
}
|
|
12301
11840
|
}
|
|
@@ -12382,7 +11921,7 @@ async function processAgent(agent, agentStates) {
|
|
|
12382
11921
|
}
|
|
12383
11922
|
if (hostFlagStore().getBoolean("connectivity-probe")) {
|
|
12384
11923
|
try {
|
|
12385
|
-
const probeProjectDir =
|
|
11924
|
+
const probeProjectDir = join21(homedir10(), ".augmented", agent.code_name, "project");
|
|
12386
11925
|
await runAgentConnectivityProbes(agent, integrations, probeProjectDir);
|
|
12387
11926
|
} catch (err) {
|
|
12388
11927
|
log(`Connectivity probe failed for '${agent.code_name}': ${err.message}`);
|
|
@@ -12393,7 +11932,7 @@ async function processAgent(agent, agentStates) {
|
|
|
12393
11932
|
const forceDue = attemptsLeft > 0;
|
|
12394
11933
|
let probeRan = false;
|
|
12395
11934
|
try {
|
|
12396
|
-
const probeProjectDir =
|
|
11935
|
+
const probeProjectDir = join21(homedir10(), ".augmented", agent.code_name, "project");
|
|
12397
11936
|
probeRan = await runAgentSessionToolBindProbes(agent, integrations, probeProjectDir, { forceDue });
|
|
12398
11937
|
} catch (err) {
|
|
12399
11938
|
log(`Session-tool-bind probe failed for '${agent.code_name}': ${err.message}`);
|
|
@@ -12406,9 +11945,9 @@ async function processAgent(agent, agentStates) {
|
|
|
12406
11945
|
}
|
|
12407
11946
|
if (frameworkAdapter.removeMcpServer && frameworkAdapter.getMcpPath) {
|
|
12408
11947
|
const mcpPath = frameworkAdapter.getMcpPath(agent.code_name);
|
|
12409
|
-
if (mcpPath &&
|
|
11948
|
+
if (mcpPath && existsSync11(mcpPath)) {
|
|
12410
11949
|
try {
|
|
12411
|
-
const cfg = JSON.parse(
|
|
11950
|
+
const cfg = JSON.parse(readFileSync17(mcpPath, "utf-8"));
|
|
12412
11951
|
const expectedRemoteKeys = new Set(
|
|
12413
11952
|
integrations.map((i) => i.definition_id)
|
|
12414
11953
|
);
|
|
@@ -12452,11 +11991,11 @@ async function processAgent(agent, agentStates) {
|
|
|
12452
11991
|
recordConfigChurnEvent(agent.agent_id, agent.code_name, FLAP_CHANNEL_INTEGRATIONS, intMembership);
|
|
12453
11992
|
}
|
|
12454
11993
|
if (intHash !== prevIntHash) {
|
|
12455
|
-
const projectDir =
|
|
12456
|
-
const envIntPath =
|
|
11994
|
+
const projectDir = join21(homedir10(), ".augmented", agent.code_name, "project");
|
|
11995
|
+
const envIntPath = join21(projectDir, ".env.integrations");
|
|
12457
11996
|
let preWriteEnv;
|
|
12458
11997
|
try {
|
|
12459
|
-
preWriteEnv =
|
|
11998
|
+
preWriteEnv = readFileSync17(envIntPath, "utf-8");
|
|
12460
11999
|
} catch {
|
|
12461
12000
|
preWriteEnv = void 0;
|
|
12462
12001
|
}
|
|
@@ -12468,9 +12007,9 @@ async function processAgent(agent, agentStates) {
|
|
|
12468
12007
|
let rotationHandled = true;
|
|
12469
12008
|
if (fw === "claude-code" && isSessionHealthy(agent.code_name)) {
|
|
12470
12009
|
try {
|
|
12471
|
-
const projectMcpPath =
|
|
12472
|
-
const postWriteEnv =
|
|
12473
|
-
const mcpContent =
|
|
12010
|
+
const projectMcpPath = join21(projectDir, ".mcp.json");
|
|
12011
|
+
const postWriteEnv = readFileSync17(envIntPath, "utf-8");
|
|
12012
|
+
const mcpContent = readFileSync17(projectMcpPath, "utf-8");
|
|
12474
12013
|
const changedVars = diffEnvIntegrations(preWriteEnv, postWriteEnv);
|
|
12475
12014
|
const mcpJsonForReap = JSON.parse(mcpContent);
|
|
12476
12015
|
const affectedServerKeys = findMcpServersUsingVars(mcpJsonForReap, changedVars);
|
|
@@ -12547,10 +12086,10 @@ async function processAgent(agent, agentStates) {
|
|
|
12547
12086
|
desiredEntries.push({ serverId, url, headers: mcpHeaders, name: tk.toolkit_name });
|
|
12548
12087
|
}
|
|
12549
12088
|
const hashBasis = desiredEntries.slice().sort((a, b) => a.serverId.localeCompare(b.serverId)).map((e) => {
|
|
12550
|
-
const headersHash =
|
|
12089
|
+
const headersHash = createHash13("sha256").update(canonicalJson(e.headers ?? {})).digest("hex").slice(0, 16);
|
|
12551
12090
|
return `${e.serverId}|${e.url}|${headersHash}`;
|
|
12552
12091
|
}).join("\n");
|
|
12553
|
-
const mcpHash =
|
|
12092
|
+
const mcpHash = createHash13("sha256").update(hashBasis).digest("hex").slice(0, 16);
|
|
12554
12093
|
const prevMcpHash = agentState.knownManagedMcpHashes.get(agent.agent_id);
|
|
12555
12094
|
const structureHash = managedMcpStructureHash(desiredEntries);
|
|
12556
12095
|
const prevStructureHash = agentState.knownManagedMcpStructure.get(agent.agent_id);
|
|
@@ -12565,15 +12104,15 @@ async function processAgent(agent, agentStates) {
|
|
|
12565
12104
|
if (mcpHash !== prevMcpHash) {
|
|
12566
12105
|
for (const e of desiredEntries) {
|
|
12567
12106
|
frameworkAdapter.writeMcpServer(agent.code_name, e.serverId, { url: e.url, headers: e.headers });
|
|
12568
|
-
const urlHash =
|
|
12107
|
+
const urlHash = createHash13("sha256").update(e.url).digest("hex").slice(0, 12);
|
|
12569
12108
|
log(`[managed-toolkit] ${agent.code_name}: wrote '${e.name}' (serverId=${e.serverId}, url_hash=${urlHash})`);
|
|
12570
12109
|
}
|
|
12571
12110
|
if (frameworkAdapter.removeMcpServer && frameworkAdapter.getMcpPath) {
|
|
12572
12111
|
const mcpPath = frameworkAdapter.getMcpPath(agent.code_name);
|
|
12573
12112
|
if (mcpPath) {
|
|
12574
12113
|
try {
|
|
12575
|
-
const { readFileSync:
|
|
12576
|
-
const mcpConfig = JSON.parse(
|
|
12114
|
+
const { readFileSync: readFileSync18 } = await import("fs");
|
|
12115
|
+
const mcpConfig = JSON.parse(readFileSync18(mcpPath, "utf-8"));
|
|
12577
12116
|
if (mcpConfig.mcpServers) {
|
|
12578
12117
|
for (const key of Object.keys(mcpConfig.mcpServers)) {
|
|
12579
12118
|
if (isManagedMcpServerKey(key) && !expectedServerIds.has(key)) {
|
|
@@ -12674,7 +12213,7 @@ async function processAgent(agent, agentStates) {
|
|
|
12674
12213
|
if (frameworkAdapter.installSkillFiles) {
|
|
12675
12214
|
const currentIntegrationSkillIds = /* @__PURE__ */ new Set();
|
|
12676
12215
|
const installedIntegrationSkills = [];
|
|
12677
|
-
const { createHash:
|
|
12216
|
+
const { createHash: createHash14 } = await import("crypto");
|
|
12678
12217
|
const refreshAny = refreshData;
|
|
12679
12218
|
const contexts = refreshAny.integration_contexts ?? refreshAny.plugin_contexts ?? [];
|
|
12680
12219
|
const contextBySlug = /* @__PURE__ */ new Map();
|
|
@@ -12703,7 +12242,7 @@ async function processAgent(agent, agentStates) {
|
|
|
12703
12242
|
)
|
|
12704
12243
|
}));
|
|
12705
12244
|
const bundle = buildIntegrationBundle(renderedScopes);
|
|
12706
|
-
const contentHash =
|
|
12245
|
+
const contentHash = createHash14("sha256").update(bundleFingerprint(bundle.files)).digest("hex").slice(0, 12);
|
|
12707
12246
|
const hashKey = `plugin-skill:${agent.agent_id}:${integrationSkillId}`;
|
|
12708
12247
|
if (agentState.knownSkillHashes.get(hashKey) === contentHash) continue;
|
|
12709
12248
|
frameworkAdapter.installSkillFiles(agent.code_name, integrationSkillId, bundle.files);
|
|
@@ -12715,19 +12254,19 @@ async function processAgent(agent, agentStates) {
|
|
|
12715
12254
|
}
|
|
12716
12255
|
}
|
|
12717
12256
|
try {
|
|
12718
|
-
const { readdirSync: readdirSync6, rmSync:
|
|
12719
|
-
const { homedir:
|
|
12257
|
+
const { readdirSync: readdirSync6, rmSync: rmSync6 } = await import("fs");
|
|
12258
|
+
const { homedir: homedir11 } = await import("os");
|
|
12720
12259
|
const frameworkId2 = frameworkAdapter.id;
|
|
12721
12260
|
const candidateSkillDirs = [
|
|
12722
12261
|
// Claude Code — framework runtime tree
|
|
12723
|
-
|
|
12262
|
+
join21(homedir11(), ".augmented", agent.code_name, "skills"),
|
|
12724
12263
|
// Claude Code — project tree
|
|
12725
|
-
|
|
12264
|
+
join21(homedir11(), ".augmented", agent.code_name, "project", ".claude", "skills"),
|
|
12726
12265
|
// Defensive: legacy provision-side path, not currently an
|
|
12727
12266
|
// install target but cheap to sweep.
|
|
12728
|
-
|
|
12267
|
+
join21(agentDir, ".claude", "skills")
|
|
12729
12268
|
];
|
|
12730
|
-
const existingDirs = candidateSkillDirs.filter((d) =>
|
|
12269
|
+
const existingDirs = candidateSkillDirs.filter((d) => existsSync11(d));
|
|
12731
12270
|
const discoveredEntries = /* @__PURE__ */ new Set();
|
|
12732
12271
|
for (const dir of existingDirs) {
|
|
12733
12272
|
try {
|
|
@@ -12741,9 +12280,9 @@ async function processAgent(agent, agentStates) {
|
|
|
12741
12280
|
}
|
|
12742
12281
|
const removeSkillFolder = (entry, reason) => {
|
|
12743
12282
|
for (const dir of existingDirs) {
|
|
12744
|
-
const p =
|
|
12745
|
-
if (
|
|
12746
|
-
|
|
12283
|
+
const p = join21(dir, entry);
|
|
12284
|
+
if (existsSync11(p)) {
|
|
12285
|
+
rmSync6(p, { recursive: true, force: true });
|
|
12747
12286
|
}
|
|
12748
12287
|
}
|
|
12749
12288
|
log(`Removed ${reason} '${entry}' for '${agent.code_name}' (framework=${frameworkId2})`);
|
|
@@ -12761,7 +12300,7 @@ async function processAgent(agent, agentStates) {
|
|
|
12761
12300
|
const sharedSkillsPayload = refreshAny.shared_skills;
|
|
12762
12301
|
const desiredResolved = globalSkillsPayload !== void 0 || sharedSkillsPayload !== void 0;
|
|
12763
12302
|
const manifestPath = managedSkillManifestPath(
|
|
12764
|
-
|
|
12303
|
+
join21(homedir10(), ".augmented", agent.code_name)
|
|
12765
12304
|
);
|
|
12766
12305
|
const prevIds = /* @__PURE__ */ new Set([
|
|
12767
12306
|
...agentState.knownGlobalSkillIds.get(agent.agent_id) ?? /* @__PURE__ */ new Set(),
|
|
@@ -12770,7 +12309,7 @@ async function processAgent(agent, agentStates) {
|
|
|
12770
12309
|
const plan = planGlobalSkillSync(
|
|
12771
12310
|
[...globalSkillsPayload ?? [], ...sharedSkillsPayload ?? []],
|
|
12772
12311
|
prevIds,
|
|
12773
|
-
(content) =>
|
|
12312
|
+
(content) => createHash14("sha256").update(content).digest("hex").slice(0, 12),
|
|
12774
12313
|
(skillId) => agentState.knownSkillHashes.get(`global-skill:${agent.agent_id}:${skillId}`),
|
|
12775
12314
|
{ desiredResolved }
|
|
12776
12315
|
);
|
|
@@ -12781,16 +12320,16 @@ async function processAgent(agent, agentStates) {
|
|
|
12781
12320
|
}
|
|
12782
12321
|
if (plan.removes.length) {
|
|
12783
12322
|
const globalSkillDirs = [
|
|
12784
|
-
|
|
12785
|
-
|
|
12786
|
-
|
|
12323
|
+
join21(homedir10(), ".augmented", agent.code_name, "skills"),
|
|
12324
|
+
join21(homedir10(), ".augmented", agent.code_name, "project", ".claude", "skills"),
|
|
12325
|
+
join21(agentDir, ".claude", "skills")
|
|
12787
12326
|
];
|
|
12788
12327
|
for (const id of plan.removes) {
|
|
12789
12328
|
let prunedAny = false;
|
|
12790
12329
|
for (const dir of globalSkillDirs) {
|
|
12791
|
-
const p =
|
|
12792
|
-
if (
|
|
12793
|
-
|
|
12330
|
+
const p = join21(dir, id);
|
|
12331
|
+
if (existsSync11(p) && existsSync11(join21(p, "SKILL.md"))) {
|
|
12332
|
+
rmSync5(p, { recursive: true, force: true });
|
|
12794
12333
|
prunedAny = true;
|
|
12795
12334
|
}
|
|
12796
12335
|
}
|
|
@@ -12821,7 +12360,7 @@ async function processAgent(agent, agentStates) {
|
|
|
12821
12360
|
const slug = hook.integration_slug ?? hook.plugin_slug;
|
|
12822
12361
|
if (!slug) continue;
|
|
12823
12362
|
try {
|
|
12824
|
-
const scriptHash =
|
|
12363
|
+
const scriptHash = createHash14("sha256").update(hook.script).digest("hex").slice(0, 12);
|
|
12825
12364
|
const hookKey = `${agent.agent_id}:${frameworkAdapter.id}:plugin-hook:${slug}:on_install`;
|
|
12826
12365
|
if (agentState.knownSkillHashes.get(hookKey) === scriptHash) continue;
|
|
12827
12366
|
const result = await frameworkAdapter.executePluginHook({
|
|
@@ -12836,9 +12375,9 @@ async function processAgent(agent, agentStates) {
|
|
|
12836
12375
|
} else if (result.timedOut) {
|
|
12837
12376
|
log(`Integration hook on_install '${slug}' TIMED OUT for '${agent.code_name}' after ${result.durationMs}ms`);
|
|
12838
12377
|
} else {
|
|
12839
|
-
const stderrHash =
|
|
12378
|
+
const stderrHash = createHash14("sha256").update(result.stderr).digest("hex").slice(0, 12);
|
|
12840
12379
|
const missingCmd = result.exitCode === 127 ? extractCommandNotFound(result.stderr) : null;
|
|
12841
|
-
const missingCmdHash = missingCmd ?
|
|
12380
|
+
const missingCmdHash = missingCmd ? createHash14("sha256").update(missingCmd).digest("hex").slice(0, 8) : null;
|
|
12842
12381
|
log(
|
|
12843
12382
|
`Integration hook on_install '${slug}' exited ${result.exitCode} for '${agent.code_name}' ` + (missingCmdHash ? `[missing_command_hash=${missingCmdHash}] ` : "") + `[stderr_hash=${stderrHash} stderr_len=${result.stderr.length}]`
|
|
12844
12383
|
);
|
|
@@ -12995,8 +12534,8 @@ async function processAgent(agent, agentStates) {
|
|
|
12995
12534
|
const sess = getSessionState(agent.code_name);
|
|
12996
12535
|
let mcpJsonParsed = null;
|
|
12997
12536
|
try {
|
|
12998
|
-
const mcpPath =
|
|
12999
|
-
mcpJsonParsed = JSON.parse(
|
|
12537
|
+
const mcpPath = join21(getProjectDir(agent.code_name), ".mcp.json");
|
|
12538
|
+
mcpJsonParsed = JSON.parse(readFileSync17(mcpPath, "utf-8"));
|
|
13000
12539
|
} catch {
|
|
13001
12540
|
}
|
|
13002
12541
|
reapMissingMcpSessions({
|
|
@@ -13325,10 +12864,10 @@ Retried to the limit after repeated stalls \u2014 needs a look.`).catch(() => {
|
|
|
13325
12864
|
}
|
|
13326
12865
|
}
|
|
13327
12866
|
const trackedFiles = frameworkAdapter.driftTrackedFiles();
|
|
13328
|
-
if (trackedFiles.length > 0 &&
|
|
12867
|
+
if (trackedFiles.length > 0 && existsSync11(agentDir)) {
|
|
13329
12868
|
const hashes = /* @__PURE__ */ new Map();
|
|
13330
12869
|
for (const file of trackedFiles) {
|
|
13331
|
-
const h = hashFile(
|
|
12870
|
+
const h = hashFile(join21(agentDir, file));
|
|
13332
12871
|
if (h) hashes.set(file, h);
|
|
13333
12872
|
}
|
|
13334
12873
|
agentState.writtenHashes.set(agent.agent_id, hashes);
|
|
@@ -13343,7 +12882,7 @@ Retried to the limit after repeated stalls \u2014 needs a look.`).catch(() => {
|
|
|
13343
12882
|
refreshData.agent.onboarding_state
|
|
13344
12883
|
);
|
|
13345
12884
|
const obStep = obState.step;
|
|
13346
|
-
const markerPath =
|
|
12885
|
+
const markerPath = join21(homedir10(), ".augmented", agent.code_name, "onboarding-drive.json");
|
|
13347
12886
|
const marker = readOnboardingDriveMarker(markerPath);
|
|
13348
12887
|
const decision = decideOnboardingDrive(obStep, marker, Date.now(), obState.generation ?? 0);
|
|
13349
12888
|
if (decision.clearMarker) {
|
|
@@ -13413,7 +12952,7 @@ async function ensureOpencodeRuntime(agent, refreshData, agentTimezone) {
|
|
|
13413
12952
|
}
|
|
13414
12953
|
stopOpencodeSlackIngest(codeName, log);
|
|
13415
12954
|
stopOpencodeTelegramIngest(codeName, log);
|
|
13416
|
-
const opencodeProjectDir =
|
|
12955
|
+
const opencodeProjectDir = join21(getFramework("opencode").getAgentDir(codeName), "provision");
|
|
13417
12956
|
const openRouterRaw = refreshData.openrouter ?? null;
|
|
13418
12957
|
const serveEnv = {
|
|
13419
12958
|
AGT_HOST: requireHost(),
|
|
@@ -13453,8 +12992,8 @@ async function ensureOpencodeRuntime(agent, refreshData, agentTimezone) {
|
|
|
13453
12992
|
async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
13454
12993
|
const codeName = agent.code_name;
|
|
13455
12994
|
const projectDir = getProjectDir(codeName);
|
|
13456
|
-
const mcpConfigPath =
|
|
13457
|
-
const claudeMdPath =
|
|
12995
|
+
const mcpConfigPath = join21(projectDir, ".mcp.json");
|
|
12996
|
+
const claudeMdPath = join21(projectDir, "CLAUDE.md");
|
|
13458
12997
|
if (restartBreaker.isTripped(codeName)) {
|
|
13459
12998
|
const trip = restartBreaker.getTrip(codeName);
|
|
13460
12999
|
return {
|
|
@@ -13612,7 +13151,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
13612
13151
|
const ctx = getLastFailureContext(codeName);
|
|
13613
13152
|
const recovery = prepareForRespawn(codeName);
|
|
13614
13153
|
const tailSummary = !ctx.tail ? "" : KNOWN_SAFE_TAIL_SIGNATURES.has(ctx.signature) ? `; last pane output (${PANE_TAIL_PREVIEW_LINES} of ~20 lines):
|
|
13615
|
-
${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${
|
|
13154
|
+
${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash13("sha256").update(ctx.tail).digest("hex").slice(0, 12)} (raw at ~/.augmented/${codeName}/pane.log)`;
|
|
13616
13155
|
const sigSummary = ctx.signature !== "unknown" ? `; signature=${ctx.signature}` : "";
|
|
13617
13156
|
const recoverySummary = recovery ? `; recovery=${recovery}` : "";
|
|
13618
13157
|
log(
|
|
@@ -13626,7 +13165,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash14("sha256")
|
|
|
13626
13165
|
);
|
|
13627
13166
|
getHostId().then((hostId) => {
|
|
13628
13167
|
if (!hostId) return;
|
|
13629
|
-
const paneTailHash = zombie.paneTail ? `sha256:${
|
|
13168
|
+
const paneTailHash = zombie.paneTail ? `sha256:${createHash13("sha256").update(zombie.paneTail).digest("hex").slice(0, 12)}` : null;
|
|
13630
13169
|
return api.post("/host/events", {
|
|
13631
13170
|
host_id: hostId,
|
|
13632
13171
|
agent_code_name: codeName,
|
|
@@ -13775,7 +13314,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash14("sha256")
|
|
|
13775
13314
|
if (!claudeAuthTupleBySession.has(codeName)) {
|
|
13776
13315
|
claudeAuthTupleBySession.set(codeName, currentAuthTuple);
|
|
13777
13316
|
}
|
|
13778
|
-
const stableTasksHash =
|
|
13317
|
+
const stableTasksHash = createHash13("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
|
|
13779
13318
|
const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
|
|
13780
13319
|
if (stableTasksHash !== prevHash) {
|
|
13781
13320
|
const taskInputs = tasks.map((t) => buildSchedulerTaskInput(t));
|
|
@@ -13992,7 +13531,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
|
|
|
13992
13531
|
void api.post("/host/restart-ack", { host_id: hostId, agent_id: agentId, restart_requested_at: requestedAt }).catch((err) => log(`[restart-lane] ack failed for '${codeName}': ${err.message}`));
|
|
13993
13532
|
void (async () => {
|
|
13994
13533
|
try {
|
|
13995
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
13534
|
+
const { collectDiagnostics } = await import("../persistent-session-7VMIE4G4.js");
|
|
13996
13535
|
await api.post("/host/heartbeat", {
|
|
13997
13536
|
host_id: hostId,
|
|
13998
13537
|
agent_diagnostics: collectDiagnostics([codeName])
|
|
@@ -14042,7 +13581,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
|
|
|
14042
13581
|
}
|
|
14043
13582
|
try {
|
|
14044
13583
|
const hostId = await getHostId();
|
|
14045
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
13584
|
+
const { collectDiagnostics } = await import("../persistent-session-7VMIE4G4.js");
|
|
14046
13585
|
await api.post("/host/heartbeat", {
|
|
14047
13586
|
host_id: hostId,
|
|
14048
13587
|
agent_diagnostics: collectDiagnostics([codeName])
|
|
@@ -14327,9 +13866,9 @@ async function processDirectChatMessage(agent, msg) {
|
|
|
14327
13866
|
const useDoorbell = hostFlagStore().getBoolean("direct-chat-doorbell") || isolationMode(agent.codeName) === "docker";
|
|
14328
13867
|
if (useDoorbell) {
|
|
14329
13868
|
try {
|
|
14330
|
-
const doorbell = directChatDoorbellPath(agent.agentId,
|
|
14331
|
-
|
|
14332
|
-
|
|
13869
|
+
const doorbell = directChatDoorbellPath(agent.agentId, homedir10());
|
|
13870
|
+
mkdirSync8(dirname5(doorbell), { recursive: true });
|
|
13871
|
+
writeFileSync11(doorbell, String(Date.now()));
|
|
14333
13872
|
log(`[direct-chat] Doorbell rung for '${agent.codeName}' (msg=${msg.id}) \u2014 in-session MCP will pull via the cursor`);
|
|
14334
13873
|
return;
|
|
14335
13874
|
} catch (err) {
|
|
@@ -14437,9 +13976,9 @@ ${formatRunMarker(run_id)}` : KANBAN_CHECK_COMMAND;
|
|
|
14437
13976
|
}
|
|
14438
13977
|
if (run_id) openInjectedRunByCode.set(codeName, run_id);
|
|
14439
13978
|
try {
|
|
14440
|
-
const doorbell = directChatDoorbellPath(agentId,
|
|
14441
|
-
|
|
14442
|
-
|
|
13979
|
+
const doorbell = directChatDoorbellPath(agentId, homedir10());
|
|
13980
|
+
mkdirSync8(dirname5(doorbell), { recursive: true });
|
|
13981
|
+
writeFileSync11(doorbell, String(Date.now()));
|
|
14443
13982
|
} catch (err) {
|
|
14444
13983
|
log(`[kanban] doorbell ring failed for '${codeName}': ${err.message} (notice still queued)`);
|
|
14445
13984
|
}
|
|
@@ -14540,7 +14079,7 @@ async function processClaudePairSessions(agents) {
|
|
|
14540
14079
|
killPairSession,
|
|
14541
14080
|
pairTmuxSession,
|
|
14542
14081
|
finalizeClaudePairOnboarding
|
|
14543
|
-
} = await import("../claude-pair-runtime-
|
|
14082
|
+
} = await import("../claude-pair-runtime-LKXINT7K.js");
|
|
14544
14083
|
for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
|
|
14545
14084
|
log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
|
|
14546
14085
|
const killed = await killPairSession(pairTmuxSession(pairId));
|
|
@@ -14575,12 +14114,12 @@ async function processClaudePairSessions(agents) {
|
|
|
14575
14114
|
try {
|
|
14576
14115
|
if (session.status === "initiating") {
|
|
14577
14116
|
log(`[claude-pair] spawning pair session ${pairSession} for '${codeName}'`);
|
|
14578
|
-
const
|
|
14579
|
-
if (!
|
|
14117
|
+
const spawn = await spawnPairSession(pairSession);
|
|
14118
|
+
if (!spawn.ok) {
|
|
14580
14119
|
await reportAndCleanup(session.pair_id, {
|
|
14581
14120
|
status: "failure",
|
|
14582
|
-
error_code:
|
|
14583
|
-
error_message:
|
|
14121
|
+
error_code: spawn.error.kind,
|
|
14122
|
+
error_message: spawn.error.kind === "unknown" ? spawn.error.message : void 0
|
|
14584
14123
|
});
|
|
14585
14124
|
continue;
|
|
14586
14125
|
}
|
|
@@ -14790,8 +14329,8 @@ function parseMemoryFile(raw, fallbackName) {
|
|
|
14790
14329
|
};
|
|
14791
14330
|
}
|
|
14792
14331
|
async function syncMemories(agent, configDir, log2) {
|
|
14793
|
-
const projectDir =
|
|
14794
|
-
const memoryDir =
|
|
14332
|
+
const projectDir = join21(configDir, agent.code_name, "project");
|
|
14333
|
+
const memoryDir = join21(projectDir, "memory");
|
|
14795
14334
|
const isFreshSync = pendingFreshMemorySync.has(agent.agent_id);
|
|
14796
14335
|
if (isFreshSync) {
|
|
14797
14336
|
log2(`[memory-sync] Fresh-sync requested for '${agent.code_name}' \u2014 pulling DB first`);
|
|
@@ -14802,15 +14341,15 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
14802
14341
|
}
|
|
14803
14342
|
pendingFreshMemorySync.delete(agent.agent_id);
|
|
14804
14343
|
}
|
|
14805
|
-
if (
|
|
14344
|
+
if (existsSync11(memoryDir)) {
|
|
14806
14345
|
const prevHashes = memoryFileHashes.get(agent.agent_id) ?? /* @__PURE__ */ new Map();
|
|
14807
14346
|
const currentHashes = /* @__PURE__ */ new Map();
|
|
14808
14347
|
const changedMemories = [];
|
|
14809
14348
|
for (const file of readdirSync5(memoryDir)) {
|
|
14810
14349
|
if (!file.endsWith(".md")) continue;
|
|
14811
14350
|
try {
|
|
14812
|
-
const raw =
|
|
14813
|
-
const fileHash =
|
|
14351
|
+
const raw = readFileSync17(join21(memoryDir, file), "utf-8");
|
|
14352
|
+
const fileHash = createHash13("sha256").update(raw).digest("hex").slice(0, 16);
|
|
14814
14353
|
currentHashes.set(file, fileHash);
|
|
14815
14354
|
if (prevHashes.get(file) === fileHash) continue;
|
|
14816
14355
|
const parsed = parseMemoryFile(raw, file.replace(/\.md$/, ""));
|
|
@@ -14834,7 +14373,7 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
14834
14373
|
} catch (err) {
|
|
14835
14374
|
for (const mem of changedMemories) {
|
|
14836
14375
|
for (const [file] of currentHashes) {
|
|
14837
|
-
const parsed = parseMemoryFile(
|
|
14376
|
+
const parsed = parseMemoryFile(readFileSync17(join21(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
|
|
14838
14377
|
if (parsed?.name === mem.name) currentHashes.delete(file);
|
|
14839
14378
|
}
|
|
14840
14379
|
}
|
|
@@ -14847,29 +14386,29 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
14847
14386
|
}
|
|
14848
14387
|
}
|
|
14849
14388
|
async function downloadMemories(agent, memoryDir, log2, { force }) {
|
|
14850
|
-
const localFiles =
|
|
14851
|
-
const localListHash =
|
|
14389
|
+
const localFiles = existsSync11(memoryDir) ? readdirSync5(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
|
|
14390
|
+
const localListHash = createHash13("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
|
|
14852
14391
|
const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
|
|
14853
14392
|
const prevDownload = lastDownloadHash.get(agent.agent_id);
|
|
14854
14393
|
try {
|
|
14855
14394
|
const dbMemories = await api.post("/host/memories", {
|
|
14856
14395
|
agent_id: agent.agent_id
|
|
14857
14396
|
});
|
|
14858
|
-
const responseHash =
|
|
14397
|
+
const responseHash = createHash13("sha256").update(JSON.stringify(dbMemories.memories ?? [])).digest("hex").slice(0, 16);
|
|
14859
14398
|
if (!force && prevDownload && prevLocalHash === localListHash && lastDownloadHash.get(agent.agent_id) === responseHash) {
|
|
14860
14399
|
return true;
|
|
14861
14400
|
}
|
|
14862
14401
|
lastDownloadHash.set(agent.agent_id, responseHash);
|
|
14863
14402
|
lastLocalFileHash.set(agent.agent_id, localListHash);
|
|
14864
14403
|
if (dbMemories.memories?.length) {
|
|
14865
|
-
|
|
14404
|
+
mkdirSync8(memoryDir, { recursive: true });
|
|
14866
14405
|
let written = 0;
|
|
14867
14406
|
let overwritten = 0;
|
|
14868
14407
|
for (let i = 0; i < dbMemories.memories.length; i++) {
|
|
14869
14408
|
const mem = dbMemories.memories[i];
|
|
14870
14409
|
const rawSlug = mem.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").slice(0, 60);
|
|
14871
14410
|
const slug = rawSlug || `memory-${i}`;
|
|
14872
|
-
const filePath =
|
|
14411
|
+
const filePath = join21(memoryDir, `${slug}.md`);
|
|
14873
14412
|
const desired = `---
|
|
14874
14413
|
name: ${JSON.stringify(mem.name)}
|
|
14875
14414
|
type: ${mem.type}
|
|
@@ -14878,23 +14417,23 @@ description: ${JSON.stringify(mem.content.slice(0, 200))}
|
|
|
14878
14417
|
|
|
14879
14418
|
${mem.content}
|
|
14880
14419
|
`;
|
|
14881
|
-
if (
|
|
14420
|
+
if (existsSync11(filePath)) {
|
|
14882
14421
|
let existing = "";
|
|
14883
14422
|
try {
|
|
14884
|
-
existing =
|
|
14423
|
+
existing = readFileSync17(filePath, "utf-8");
|
|
14885
14424
|
} catch {
|
|
14886
14425
|
}
|
|
14887
14426
|
if (existing === desired) continue;
|
|
14888
|
-
|
|
14427
|
+
writeFileSync11(filePath, desired);
|
|
14889
14428
|
overwritten++;
|
|
14890
14429
|
} else {
|
|
14891
|
-
|
|
14430
|
+
writeFileSync11(filePath, desired);
|
|
14892
14431
|
written++;
|
|
14893
14432
|
}
|
|
14894
14433
|
}
|
|
14895
14434
|
if (written > 0 || overwritten > 0) {
|
|
14896
14435
|
const updatedFiles = readdirSync5(memoryDir).filter((f) => f.endsWith(".md")).sort();
|
|
14897
|
-
lastLocalFileHash.set(agent.agent_id,
|
|
14436
|
+
lastLocalFileHash.set(agent.agent_id, createHash13("sha256").update(updatedFiles.join(",")).digest("hex").slice(0, 16));
|
|
14898
14437
|
log2(`Memory download for '${agent.code_name}': wrote ${written} new, overwrote ${overwritten} stale`);
|
|
14899
14438
|
}
|
|
14900
14439
|
}
|
|
@@ -14905,9 +14444,9 @@ ${mem.content}
|
|
|
14905
14444
|
}
|
|
14906
14445
|
}
|
|
14907
14446
|
async function cleanupAgentFiles(codeName, agentDir) {
|
|
14908
|
-
if (
|
|
14447
|
+
if (existsSync11(agentDir)) {
|
|
14909
14448
|
try {
|
|
14910
|
-
|
|
14449
|
+
rmSync5(agentDir, { recursive: true, force: true });
|
|
14911
14450
|
log(`Removed provision directory for '${codeName}'`);
|
|
14912
14451
|
} catch (err) {
|
|
14913
14452
|
log(`Failed to remove provision dir for '${codeName}': ${err.message}`);
|
|
@@ -14929,8 +14468,8 @@ var caffeinateProc = null;
|
|
|
14929
14468
|
async function startCaffeinate() {
|
|
14930
14469
|
if (process.platform !== "darwin") return;
|
|
14931
14470
|
try {
|
|
14932
|
-
const { spawn
|
|
14933
|
-
caffeinateProc =
|
|
14471
|
+
const { spawn } = await import("child_process");
|
|
14472
|
+
caffeinateProc = spawn("caffeinate", ["-dims"], {
|
|
14934
14473
|
stdio: "ignore",
|
|
14935
14474
|
detached: false
|
|
14936
14475
|
});
|
|
@@ -15078,8 +14617,8 @@ async function killAllAgtTmuxSessions() {
|
|
|
15078
14617
|
["list-sessions", "-F", "#{session_name}"],
|
|
15079
14618
|
{ timeout: 2e3, stdin: "ignore" }
|
|
15080
14619
|
);
|
|
15081
|
-
const
|
|
15082
|
-
for (const session of
|
|
14620
|
+
const sessions = output.trim().split("\n").filter((s) => s.startsWith("agt-"));
|
|
14621
|
+
for (const session of sessions) {
|
|
15083
14622
|
try {
|
|
15084
14623
|
await execFilePromiseLong("tmux", ["kill-session", "-t", session], {
|
|
15085
14624
|
timeout: 2e3,
|
|
@@ -15089,8 +14628,8 @@ async function killAllAgtTmuxSessions() {
|
|
|
15089
14628
|
} catch {
|
|
15090
14629
|
}
|
|
15091
14630
|
}
|
|
15092
|
-
if (
|
|
15093
|
-
log(`Cleaned up ${
|
|
14631
|
+
if (sessions.length > 0) {
|
|
14632
|
+
log(`Cleaned up ${sessions.length} agt-* tmux session(s)`);
|
|
15094
14633
|
}
|
|
15095
14634
|
} catch {
|
|
15096
14635
|
}
|
|
@@ -15142,8 +14681,8 @@ function startManager(opts) {
|
|
|
15142
14681
|
config = opts;
|
|
15143
14682
|
try {
|
|
15144
14683
|
const stateFile = getStateFile();
|
|
15145
|
-
if (
|
|
15146
|
-
const raw =
|
|
14684
|
+
if (existsSync11(stateFile)) {
|
|
14685
|
+
const raw = readFileSync17(stateFile, "utf-8");
|
|
15147
14686
|
const parsed = JSON.parse(raw);
|
|
15148
14687
|
if (Array.isArray(parsed.agents)) {
|
|
15149
14688
|
state6.agents = parsed.agents;
|
|
@@ -15170,7 +14709,7 @@ function startManager(opts) {
|
|
|
15170
14709
|
log(`[startup] state rehydration failed (continuing with empty state): ${err.message}`);
|
|
15171
14710
|
}
|
|
15172
14711
|
log(
|
|
15173
|
-
`[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${
|
|
14712
|
+
`[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join21(homedir10(), ".augmented", "manager.log")}`
|
|
15174
14713
|
);
|
|
15175
14714
|
deployMcpAssets();
|
|
15176
14715
|
reapOrphanChannelMcps({ log });
|
|
@@ -15191,7 +14730,7 @@ async function reapOrphanedClaudePids() {
|
|
|
15191
14730
|
const looksLikeClaude = (pid) => {
|
|
15192
14731
|
if (process.platform !== "linux") return true;
|
|
15193
14732
|
try {
|
|
15194
|
-
const comm =
|
|
14733
|
+
const comm = readFileSync17(`/proc/${pid}/comm`, "utf-8").trim().toLowerCase();
|
|
15195
14734
|
return comm.includes("claude");
|
|
15196
14735
|
} catch {
|
|
15197
14736
|
return false;
|
|
@@ -15209,16 +14748,16 @@ async function reapOrphanedClaudePids() {
|
|
|
15209
14748
|
},
|
|
15210
14749
|
looksLikeClaude
|
|
15211
14750
|
);
|
|
15212
|
-
for (const
|
|
14751
|
+
for (const spawn of decision.toKill) {
|
|
15213
14752
|
try {
|
|
15214
|
-
process.kill(
|
|
14753
|
+
process.kill(spawn.pid, "SIGKILL");
|
|
15215
14754
|
} catch (err) {
|
|
15216
|
-
log(`[drain] reaper SIGKILL pid=${
|
|
14755
|
+
log(`[drain] reaper SIGKILL pid=${spawn.pid} failed: ${err.message}`);
|
|
15217
14756
|
}
|
|
15218
14757
|
}
|
|
15219
|
-
for (const
|
|
14758
|
+
for (const spawn of decision.pidReusedSkipped) {
|
|
15220
14759
|
log(
|
|
15221
|
-
`[drain] reaper skipped pid=${
|
|
14760
|
+
`[drain] reaper skipped pid=${spawn.pid} \u2014 PID reuse suspected (identity probe rejected)`
|
|
15222
14761
|
);
|
|
15223
14762
|
}
|
|
15224
14763
|
log(formatReaperBootLine({
|
|
@@ -15288,18 +14827,18 @@ function restartRunningChannelMcps(basenames) {
|
|
|
15288
14827
|
}
|
|
15289
14828
|
}
|
|
15290
14829
|
function deployMcpAssets() {
|
|
15291
|
-
const targetDir =
|
|
15292
|
-
|
|
15293
|
-
const moduleDir =
|
|
14830
|
+
const targetDir = join21(homedir10(), ".augmented", "_mcp");
|
|
14831
|
+
mkdirSync8(targetDir, { recursive: true });
|
|
14832
|
+
const moduleDir = dirname5(fileURLToPath(import.meta.url));
|
|
15294
14833
|
let mcpSourceDir = "";
|
|
15295
14834
|
let dir = moduleDir;
|
|
15296
14835
|
for (let i = 0; i < 6; i++) {
|
|
15297
|
-
const candidate =
|
|
15298
|
-
if (
|
|
14836
|
+
const candidate = join21(dir, "dist", "mcp");
|
|
14837
|
+
if (existsSync11(join21(candidate, "index.js"))) {
|
|
15299
14838
|
mcpSourceDir = candidate;
|
|
15300
14839
|
break;
|
|
15301
14840
|
}
|
|
15302
|
-
const parent =
|
|
14841
|
+
const parent = dirname5(dir);
|
|
15303
14842
|
if (parent === dir) break;
|
|
15304
14843
|
dir = parent;
|
|
15305
14844
|
}
|
|
@@ -15310,8 +14849,8 @@ function deployMcpAssets() {
|
|
|
15310
14849
|
const changedBasenames = [];
|
|
15311
14850
|
const fileHash = (p) => {
|
|
15312
14851
|
try {
|
|
15313
|
-
if (!
|
|
15314
|
-
return
|
|
14852
|
+
if (!existsSync11(p)) return null;
|
|
14853
|
+
return createHash13("sha256").update(readFileSync17(p)).digest("hex");
|
|
15315
14854
|
} catch {
|
|
15316
14855
|
return null;
|
|
15317
14856
|
}
|
|
@@ -15375,9 +14914,9 @@ function deployMcpAssets() {
|
|
|
15375
14914
|
// needs restarting to pick up a token rotation.
|
|
15376
14915
|
"xero.js"
|
|
15377
14916
|
]) {
|
|
15378
|
-
const src =
|
|
15379
|
-
const dst =
|
|
15380
|
-
if (!
|
|
14917
|
+
const src = join21(mcpSourceDir, file);
|
|
14918
|
+
const dst = join21(targetDir, file);
|
|
14919
|
+
if (!existsSync11(src)) continue;
|
|
15381
14920
|
const before = fileHash(dst);
|
|
15382
14921
|
try {
|
|
15383
14922
|
copyFileSync(src, dst);
|
|
@@ -15394,23 +14933,23 @@ function deployMcpAssets() {
|
|
|
15394
14933
|
log(`[manager] Bundle(s) updated: ${changedBasenames.join(", ")} \u2014 signalling running instances to restart`);
|
|
15395
14934
|
restartRunningChannelMcps(changedBasenames);
|
|
15396
14935
|
}
|
|
15397
|
-
const localMcpPath =
|
|
14936
|
+
const localMcpPath = join21(targetDir, "index.js");
|
|
15398
14937
|
try {
|
|
15399
|
-
const agentsDir =
|
|
15400
|
-
if (
|
|
14938
|
+
const agentsDir = join21(homedir10(), ".augmented", "agents");
|
|
14939
|
+
if (existsSync11(agentsDir)) {
|
|
15401
14940
|
for (const entry of readdirSync5(agentsDir, { withFileTypes: true })) {
|
|
15402
14941
|
if (!entry.isDirectory()) continue;
|
|
15403
14942
|
for (const subdir of ["provision", "project"]) {
|
|
15404
|
-
const mcpJsonPath =
|
|
14943
|
+
const mcpJsonPath = join21(agentsDir, entry.name, subdir, ".mcp.json");
|
|
15405
14944
|
try {
|
|
15406
|
-
const raw =
|
|
14945
|
+
const raw = readFileSync17(mcpJsonPath, "utf-8");
|
|
15407
14946
|
if (!raw.includes("@integrity-labs/augmented-mcp")) continue;
|
|
15408
14947
|
const mcpConfig = JSON.parse(raw);
|
|
15409
14948
|
const augServer = mcpConfig.mcpServers?.["augmented"];
|
|
15410
14949
|
if (!augServer) continue;
|
|
15411
14950
|
augServer.command = "node";
|
|
15412
14951
|
augServer.args = [localMcpPath];
|
|
15413
|
-
|
|
14952
|
+
writeFileSync11(mcpJsonPath, JSON.stringify(mcpConfig, null, 2));
|
|
15414
14953
|
log(`[manager] Patched ${entry.name}/${subdir}/.mcp.json: npx \u2192 node`);
|
|
15415
14954
|
} catch {
|
|
15416
14955
|
}
|