@salaros/ai-harness 0.4.0 → 0.4.1
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/README.md +1 -1
- package/package.json +1 -1
- package/scripts/install-policy.js +13 -7
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ If the repository already has agent files of its own, the first install keeps th
|
|
|
45
45
|
| File | What the first install does |
|
|
46
46
|
| --- | --- |
|
|
47
47
|
| `AGENTS.md`, `docs/README.md` | Writes the harness's version and appends yours under `## This project`, for you to fold in |
|
|
48
|
-
| `CLAUDE.md` | Adds `@AGENTS.md` at the top if it's missing |
|
|
48
|
+
| `CLAUDE.md` | Adds `@AGENTS.md` at the top if it's missing (on every update, too) |
|
|
49
49
|
| `.claude/settings.json` | Merges by key: replaces the harness's hooks, keeps your permissions and hooks (on every update, too) |
|
|
50
50
|
| `.mcp.json` | Adds the harness's MCP servers; yours win where both define one |
|
|
51
51
|
| `.gitignore` | Appends the harness's patterns you don't have, under a comment |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salaros/ai-harness",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Installs and updates the agent harness from its upstream repository: hooks, skills, agents and the documentation chain, merged into an existing repository without touching its own work.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"ai-harness": "scripts/update-harness.js"
|
|
@@ -141,7 +141,6 @@ const unionMerge = (from, ours, up) => ({ text: mergeRows(from, ours, up), confl
|
|
|
141
141
|
// null to keep the file as it is. A later run has the receipt, so each runs once per file.
|
|
142
142
|
const WITHOUT_BASE = {
|
|
143
143
|
reconcile: appendProject,
|
|
144
|
-
import: addImport,
|
|
145
144
|
ignore: appendPatterns,
|
|
146
145
|
keyed: (ours, theirs) => {
|
|
147
146
|
const merged = mergeJson(ours, theirs, (o, t) => mergeKeys(o, t, 2));
|
|
@@ -179,12 +178,18 @@ function demoteHeadings(text) {
|
|
|
179
178
|
return lines.map((line, i) => level[i] ? "#".repeat(Math.min(6, level[i] + 3 - top)) + line.slice(level[i]) : line).join("\n");
|
|
180
179
|
}
|
|
181
180
|
|
|
182
|
-
// CLAUDE.md is how Claude Code reaches AGENTS.md
|
|
183
|
-
//
|
|
181
|
+
// CLAUDE.md is how Claude Code reaches AGENTS.md, so its import line is not something to merge: it is
|
|
182
|
+
// there or the harness is unreachable, whatever else the file says. The line is added on top of
|
|
183
|
+
// whatever the rest of the decision left, which covers both ways it goes missing: a project that
|
|
184
|
+
// wrote its own CLAUDE.md before it had the harness, and one that has a receipt but dropped the line
|
|
185
|
+
// since. Adding it to a file left full of conflict markers helps nobody, so that one is passed
|
|
186
|
+
// through; the run is already exiting 1 over it.
|
|
184
187
|
const IMPORT = "@AGENTS.md";
|
|
185
|
-
function
|
|
186
|
-
if (
|
|
187
|
-
|
|
188
|
+
function ensureImport(done, raw, crlf) {
|
|
189
|
+
if (done.bucket === "conflicted") return done;
|
|
190
|
+
const text = lib.toLf(done.write === undefined ? raw : done.write);
|
|
191
|
+
if (text.split("\n").some(l => l.trim() === IMPORT)) return done;
|
|
192
|
+
return { outcome: "import added", bucket: "merged", write: lib.asFound(`${IMPORT}\n\n${text}`, crlf) };
|
|
188
193
|
}
|
|
189
194
|
|
|
190
195
|
// A .gitignore is a set of patterns, so the upstream's that this one lacks go at the end, under a
|
|
@@ -267,7 +272,8 @@ function merging(policy) {
|
|
|
267
272
|
const held = reads.held();
|
|
268
273
|
if (Buffer.isBuffer(facts.theirs)) return decideBinary({ ...facts, held }, reads);
|
|
269
274
|
// A union table has no lines to conflict over, and no base means the project's rows win.
|
|
270
|
-
|
|
275
|
+
const done = decideText({ ...facts, policy, raw: held }, policy === "union" ? { ...reads, merge: unionMerge } : reads);
|
|
276
|
+
return policy === "import" ? ensureImport(done, held, lib.isCrlf(held)) : done;
|
|
271
277
|
};
|
|
272
278
|
}
|
|
273
279
|
|