@ateam-ai/mcp 0.3.26 → 0.3.28
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/package.json +1 -1
- package/src/agentDoc.js +17 -9
- package/src/tools.js +36 -24
package/package.json
CHANGED
package/src/agentDoc.js
CHANGED
|
@@ -156,20 +156,28 @@ ${AGENT_DOC_SENTINEL}
|
|
|
156
156
|
* Merge the newly-rendered header with an existing CLAUDE.md, preserving
|
|
157
157
|
* anything below the sentinel (solution-specific notes).
|
|
158
158
|
*
|
|
159
|
+
* Output is deterministic so consecutive merges on the same inputs produce
|
|
160
|
+
* byte-identical output (required for the idempotent-write path in
|
|
161
|
+
* ateam_write_agent_doc).
|
|
162
|
+
*
|
|
159
163
|
* @param {string} freshHeader - Output of renderAgentDocHeader
|
|
160
164
|
* @param {string|null} existing - Current CLAUDE.md contents (or null if new file)
|
|
161
165
|
* @returns {string} merged markdown
|
|
162
166
|
*/
|
|
163
167
|
export function mergeAgentDoc(freshHeader, existing) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
168
|
+
// Normalize freshHeader: strip trailing whitespace, end with exactly "\n".
|
|
169
|
+
// This prevents newline accumulation when the output is read back and merged again.
|
|
170
|
+
const headerNormalized = freshHeader.replace(/\s+$/, "") + "\n";
|
|
171
|
+
|
|
172
|
+
const extractNotes = (src) => {
|
|
173
|
+
if (!src) return "";
|
|
174
|
+
const idx = src.indexOf(AGENT_DOC_SENTINEL);
|
|
175
|
+
const afterSentinel = idx === -1 ? src : src.slice(idx + AGENT_DOC_SENTINEL.length);
|
|
176
|
+
return afterSentinel.trim();
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const notes = extractNotes(existing);
|
|
180
|
+
return notes ? `${headerNormalized}\n${notes}\n` : headerNormalized;
|
|
173
181
|
}
|
|
174
182
|
|
|
175
183
|
// ──────────────────────────────────────────────────────────────────────────
|
package/src/tools.js
CHANGED
|
@@ -1717,22 +1717,21 @@ const handlers = {
|
|
|
1717
1717
|
}
|
|
1718
1718
|
|
|
1719
1719
|
// Auto-seed / refresh the agent onboarding doc. Non-fatal — any failure
|
|
1720
|
-
// here
|
|
1721
|
-
//
|
|
1720
|
+
// here is swallowed so it can't break a successful deploy. The tool is
|
|
1721
|
+
// idempotent: if the rendered doc is byte-identical to what's in the
|
|
1722
|
+
// repo, it returns unchanged:true and writes no commit.
|
|
1722
1723
|
let agent_doc_result = null;
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
phases.push({ phase: "agent_doc", status: "error", error: err.message });
|
|
1735
|
-
}
|
|
1724
|
+
try {
|
|
1725
|
+
agent_doc_result = await handlers.ateam_write_agent_doc({ solution_id: solutionId }, sid);
|
|
1726
|
+
phases.push({
|
|
1727
|
+
phase: "agent_doc",
|
|
1728
|
+
status: agent_doc_result?.unchanged ? "unchanged" : "done",
|
|
1729
|
+
created: agent_doc_result?.created || false,
|
|
1730
|
+
preserved_notes: agent_doc_result?.preserved_notes || false,
|
|
1731
|
+
});
|
|
1732
|
+
} catch (err) {
|
|
1733
|
+
agent_doc_result = { error: err.message };
|
|
1734
|
+
phases.push({ phase: "agent_doc", status: "skipped", reason: err.message });
|
|
1736
1735
|
}
|
|
1737
1736
|
|
|
1738
1737
|
return {
|
|
@@ -2120,17 +2119,29 @@ const handlers = {
|
|
|
2120
2119
|
|
|
2121
2120
|
const freshHeader = renderAgentDocHeader({ solution, skills, connectors });
|
|
2122
2121
|
let existing = null;
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
} catch { /* file doesn't exist yet — treat as fresh create */ }
|
|
2131
|
-
}
|
|
2122
|
+
try {
|
|
2123
|
+
const r = await get(
|
|
2124
|
+
`/deploy/solutions/${solution_id}/github/read?path=${encodeURIComponent("CLAUDE.md")}`,
|
|
2125
|
+
sid,
|
|
2126
|
+
);
|
|
2127
|
+
existing = r?.content || null;
|
|
2128
|
+
} catch { /* file doesn't exist yet — treat as fresh create */ }
|
|
2132
2129
|
const merged = overwrite ? freshHeader : mergeAgentDoc(freshHeader, existing);
|
|
2133
2130
|
|
|
2131
|
+
// Idempotent write: if the merged content is byte-identical to what's
|
|
2132
|
+
// already committed, skip the patch entirely. Prevents a noise commit on
|
|
2133
|
+
// every build_and_run when nothing meaningful changed.
|
|
2134
|
+
if (existing && existing === merged) {
|
|
2135
|
+
return {
|
|
2136
|
+
ok: true,
|
|
2137
|
+
solution_id,
|
|
2138
|
+
unchanged: true,
|
|
2139
|
+
created: false,
|
|
2140
|
+
preserved_notes: existing.includes(AGENT_DOC_SENTINEL),
|
|
2141
|
+
bytes: merged.length,
|
|
2142
|
+
};
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2134
2145
|
const res = await post(
|
|
2135
2146
|
`/deploy/solutions/${solution_id}/github/patch`,
|
|
2136
2147
|
{
|
|
@@ -2143,6 +2154,7 @@ const handlers = {
|
|
|
2143
2154
|
return {
|
|
2144
2155
|
ok: Boolean(res?.ok ?? true),
|
|
2145
2156
|
solution_id,
|
|
2157
|
+
unchanged: false,
|
|
2146
2158
|
created: !existing,
|
|
2147
2159
|
preserved_notes: Boolean(existing && existing.includes(AGENT_DOC_SENTINEL)),
|
|
2148
2160
|
bytes: merged.length,
|