@amsterdamdatalabs/adl-agent-control-linux-x64 0.1.7 → 0.1.9
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/bin/adl +2 -2
- package/bin/git +89 -8
- package/bin/lean-ctx-observe-strip +76 -3
- package/bin/reconcile +175 -5
- package/bin/validate-manifest +19 -1
- package/package.json +1 -1
- package/packages/agent-hooks/src/deploy/deploy.ts +98 -18
- package/packages/agent-hooks/src/deploy/doctor.ts +61 -11
- package/packages/agent-hooks/src/deploy/json-merge.ts +430 -18
- package/packages/agent-hooks/src/deploy/lock.ts +36 -2
- package/packages/agent-hooks/src/lean-ctx/env.ts +17 -0
- package/packages/agent-hooks/src/lean-ctx/mcp.ts +4 -2
- package/packages/agent-settings/assets/lean-ctx/config.toml +3 -0
- package/packages/agent-settings/assets/lean-ctx/gitignore +4 -0
- package/packages/agent-settings/assets/lean-ctx/layout.toml +2 -0
- package/packages/agent-settings/src/deploy/agents-deploy.ts +10 -5
- package/packages/agent-settings/src/deploy/doctor.ts +39 -3
- package/packages/agent-settings/src/deploy/lean-ctx-deploy.ts +104 -12
- package/packages/agent-settings/src/deploy/lean-ctx-merge.ts +580 -0
- package/packages/agent-settings/src/deploy/lock.ts +4 -1
- package/packages/agent-settings/src/deploy/mcp-deploy.ts +9 -6
- package/packages/agent-settings/src/deploy/settings.ts +6 -3
- package/packages/agent-skills/dist/deploy.d.ts +2 -0
- package/packages/agent-skills/dist/deploy.d.ts.map +1 -1
- package/packages/agent-skills/dist/deploy.js +15 -8
- package/packages/agent-skills/dist/deploy.js.map +1 -1
- package/packages/agent-skills/dist/manifest.d.ts +1 -0
- package/packages/agent-skills/dist/manifest.d.ts.map +1 -1
- package/packages/agent-skills/dist/manifest.js +6 -2
- package/packages/agent-skills/dist/manifest.js.map +1 -1
- package/packages/agent-skills/src/deploy.ts +15 -8
- package/packages/agent-skills/src/manifest.ts +5 -2
- package/packages/azdo/src/azdo-repo-doctor.ts +412 -95
- package/packages/azdo/src/lib/graph-identity.ts +190 -3
- package/packages/fleet/jobs/git-maintain/src/main.ts +305 -45
- package/packages/fleet/manifest.json +2 -0
- package/packages/fleet/manifest.schema.json +9 -0
- package/packages/repo-controls/README.md +13 -6
- package/packages/repo-controls/assets/adl-config.default.toml +1 -0
- package/packages/repo-controls/assets/version-bump.sh +6 -1
- package/packages/repo-controls/src/cli.ts +6 -1
- package/packages/repo-controls/src/install.ts +88 -6
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
# >>> adl managed (do not edit within this block) >>>
|
|
1
2
|
# lean-ctx layout pin (GL #623) — managed by lean-ctx, do not edit.
|
|
2
3
|
# Marks this install as committed to the XDG four-dir layout so a stray
|
|
3
4
|
# ~/.lean-ctx never re-collapses config/data/state/cache. Remove via
|
|
4
5
|
# `lean-ctx doctor` only if you intentionally revert to a single-dir layout.
|
|
5
6
|
mode = "xdg"
|
|
7
|
+
# <<< adl managed <<<
|
|
@@ -23,6 +23,8 @@ export interface DeployAgentsOptions {
|
|
|
23
23
|
readonly targetRepo: string;
|
|
24
24
|
readonly profile?: DeployProfile;
|
|
25
25
|
readonly agents?: readonly AgentDef[];
|
|
26
|
+
/** Computes the exact same written/unchanged/removed/conflicts result without writing anything (independent review, 2026-09-29, finding 6). */
|
|
27
|
+
readonly dryRun?: boolean;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
export interface AgentConflict {
|
|
@@ -41,6 +43,7 @@ export interface DeployAgentsResult {
|
|
|
41
43
|
|
|
42
44
|
export function deployAgents(options: DeployAgentsOptions): DeployAgentsResult {
|
|
43
45
|
const { assetsDir, targetRepo } = options;
|
|
46
|
+
const dryRun = options.dryRun === true;
|
|
44
47
|
|
|
45
48
|
if (!existsSync(assetsDir) || !statSync(assetsDir).isDirectory()) {
|
|
46
49
|
throw new Error(`agent-settings agents assets directory not found: ${assetsDir}`);
|
|
@@ -89,8 +92,10 @@ export function deployAgents(options: DeployAgentsOptions): DeployAgentsResult {
|
|
|
89
92
|
if (exists && readFileSync(absPath, "utf8") === content) {
|
|
90
93
|
unchanged.push(relPath);
|
|
91
94
|
} else {
|
|
92
|
-
|
|
93
|
-
|
|
95
|
+
if (!dryRun) {
|
|
96
|
+
mkdirSync(join(targetRepo, surface.folder), { recursive: true });
|
|
97
|
+
writeFileSync(absPath, content);
|
|
98
|
+
}
|
|
94
99
|
written.push(relPath);
|
|
95
100
|
}
|
|
96
101
|
kept.push(def.name);
|
|
@@ -101,21 +106,21 @@ export function deployAgents(options: DeployAgentsOptions): DeployAgentsResult {
|
|
|
101
106
|
if (kept.includes(name)) continue;
|
|
102
107
|
const relPath = `${surface.folder}/${name}.${ext}`;
|
|
103
108
|
const absPath = join(targetRepo, relPath);
|
|
104
|
-
if (existsSync(absPath)) unlinkSync(absPath);
|
|
109
|
+
if (!dryRun && existsSync(absPath)) unlinkSync(absPath);
|
|
105
110
|
removed.push(relPath);
|
|
106
111
|
}
|
|
107
112
|
|
|
108
113
|
newAgentEntries[surface.folder] = kept.sort();
|
|
109
114
|
}
|
|
110
115
|
|
|
111
|
-
writeLock(targetRepo, { schema: 1, mcp: lock.mcp, agents: newAgentEntries, leanCtx: lock.leanCtx });
|
|
116
|
+
if (!dryRun) writeLock(targetRepo, { schema: 1, mcp: lock.mcp, agents: newAgentEntries, leanCtx: lock.leanCtx });
|
|
112
117
|
|
|
113
118
|
// Once anything was actually taken over, this package's own footprint in
|
|
114
119
|
// the legacy lock's `files` section for these exact agent paths is stale:
|
|
115
120
|
// ownership has fully moved to .agents/agent-settings.lock.json just
|
|
116
121
|
// written above. A legacy lock present but untouched by any takeover (no
|
|
117
122
|
// hash matched, or this repo never had one) is left exactly as found.
|
|
118
|
-
if (anyLegacyTakeover && legacyDoc !== undefined && legacyLockPath !== undefined) {
|
|
123
|
+
if (!dryRun && anyLegacyTakeover && legacyDoc !== undefined && legacyLockPath !== undefined) {
|
|
119
124
|
stripLegacyOwnership(legacyDoc, legacyLockPath, { files: legacyFileRemovals });
|
|
120
125
|
}
|
|
121
126
|
|
|
@@ -12,6 +12,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
import { extensionFor, renderAgent } from "./agent-render.js";
|
|
14
14
|
import { loadAgentSources, type AgentDef } from "./agent-toml.js";
|
|
15
|
+
import { resolveConfigTomlWrite, resolveGitignoreWrite, resolveLeanCtxWrite } from "./lean-ctx-merge.js";
|
|
15
16
|
import { agentOwned, leanCtxOwned, mcpServerOwned, readLock, type SettingsLock } from "./lock.js";
|
|
16
17
|
import { readDeployedMcpServerNames, readDeployedMcpServerValue } from "./mcp-inspect.js";
|
|
17
18
|
import { renderMcpJsonEntry } from "./mcp-render.js";
|
|
@@ -175,13 +176,48 @@ export function doctorLeanCtx(options: DoctorLeanCtxOptions): DoctorResult {
|
|
|
175
176
|
issues.push({ severity: "error", path: file.target, reason: ownedByUs ? "deploy-written lean-ctx file is missing from the target repo" : "expected lean-ctx file has not been deployed" });
|
|
176
177
|
continue;
|
|
177
178
|
}
|
|
178
|
-
|
|
179
|
+
// Independent review, 2026-09-30, finding 6: .gitignore is exempted
|
|
180
|
+
// from this early conflict the same way deploy itself now is — a
|
|
181
|
+
// markerless, never-adl-written .agents/.gitignore is not a hard
|
|
182
|
+
// conflict; resolveGitignoreWrite's own append-not-conflict migration
|
|
183
|
+
// decides it below instead (mirrors lean-ctx-deploy.ts's own guard).
|
|
184
|
+
if (!ownedByUs && file.asset !== "gitignore") {
|
|
179
185
|
issues.push({ severity: "error", path: file.target, reason: "a user-owned file conflicts with a lean-ctx asset path; not managed by deploy" });
|
|
180
186
|
continue;
|
|
181
187
|
}
|
|
182
188
|
const expected = readFileSync(assetAbs, "utf8");
|
|
183
|
-
|
|
184
|
-
|
|
189
|
+
const current = readFileSync(targetAbs, "utf8");
|
|
190
|
+
// Same merge-contract analysis deploy itself uses (lean-ctx-merge.ts):
|
|
191
|
+
// a user addition outside the managed block alone is not drift; a
|
|
192
|
+
// changed/removed/malformed managed block, or a duplicate key, is.
|
|
193
|
+
if (current !== expected) {
|
|
194
|
+
const outcome =
|
|
195
|
+
file.asset === "config.toml"
|
|
196
|
+
? resolveConfigTomlWrite(expected, current, ownedByUs)
|
|
197
|
+
: file.asset === "gitignore"
|
|
198
|
+
? resolveGitignoreWrite(expected, current, ownedByUs)
|
|
199
|
+
: resolveLeanCtxWrite(expected, current, ownedByUs);
|
|
200
|
+
if (outcome.action === "write") {
|
|
201
|
+
// Tarun, 2026-09-30 (merge-contract correction, same day):
|
|
202
|
+
// "adl-owned entries SELF-HEAL" — when the drift is specifically
|
|
203
|
+
// an adl-owned scalar restored to adl's own value, name it
|
|
204
|
+
// explicitly here too, the same way a healed hook is named
|
|
205
|
+
// ("restored … local changes replaced"), instead of the generic
|
|
206
|
+
// "modified since deploy" wording.
|
|
207
|
+
if (outcome.restoredScalars !== undefined && outcome.restoredScalars.length > 0) {
|
|
208
|
+
for (const scalar of outcome.restoredScalars) {
|
|
209
|
+
issues.push({
|
|
210
|
+
severity: "error",
|
|
211
|
+
path: file.target,
|
|
212
|
+
reason: `restored adl value: ${scalar.key} = ${JSON.stringify(scalar.value)} (was ${JSON.stringify(scalar.previous)}); run deploy to apply`,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
} else {
|
|
216
|
+
issues.push({ severity: "error", path: file.target, reason: "deploy-written lean-ctx file was modified since deploy" });
|
|
217
|
+
}
|
|
218
|
+
} else if (outcome.action === "conflict") {
|
|
219
|
+
issues.push({ severity: "error", path: file.target, reason: outcome.reason });
|
|
220
|
+
}
|
|
185
221
|
}
|
|
186
222
|
}
|
|
187
223
|
|
|
@@ -1,9 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Writes the repo-local lean-ctx config files (config.toml, layout.toml)
|
|
3
|
-
* and .agents/.gitignore from assets/lean-ctx/, per profile.leanCtx
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* and .agents/.gitignore from assets/lean-ctx/, per profile.leanCtx. A
|
|
4
|
+
* fresh write (nothing at the target yet) is still a verbatim byte copy —
|
|
5
|
+
* no per-surface rendering — reproducing the asset exactly (the asset
|
|
6
|
+
* itself is a complete BEGIN/END-marked managed block; see
|
|
7
|
+
* lean-ctx-merge.ts).
|
|
8
|
+
*
|
|
9
|
+
* Merge contract (Tarun, 2026-09-29, merge contract; mechanism corrected
|
|
10
|
+
* by an independent review the same day — supersedes the original "L3,
|
|
11
|
+
* Tarun 2026-09-28" whole-file-verbatim rule, and this comment's own
|
|
12
|
+
* earlier per-key/array-entry description, both below): adl owns a single
|
|
13
|
+
* marked managed block per file and it SELF-HEALS as a whole the moment
|
|
14
|
+
* its content drifts from the asset. Everything OUTSIDE the markers is the
|
|
15
|
+
* user's, preserved byte-for-byte, never parsed or rewritten — see
|
|
16
|
+
* `lean-ctx-merge.ts`'s own header for exactly why (a full-file TOML parse
|
|
17
|
+
* both rejected valid user TOML and silently discarded a user's entire
|
|
18
|
+
* file on any parse failure; pure marker-text splicing cannot do either).
|
|
19
|
+
* `doctorLeanCtx` (doctor.ts) shares the same `resolveLeanCtxWrite`
|
|
20
|
+
* analysis, so "is this drift" is answered in exactly one place.
|
|
21
|
+
*
|
|
22
|
+
* A markerless file the lock already records as adl-written is a one-time
|
|
23
|
+
* MIGRATION target (wrapped in markers if its known prior content is still
|
|
24
|
+
* found verbatim; a CONFLICT, left untouched, otherwise) — never silently
|
|
25
|
+
* discarded. Malformed markers, and a key declared both inside the managed
|
|
26
|
+
* block and outside it, are conflicts too.
|
|
7
27
|
*
|
|
8
28
|
* Same ownership rule as mcp/agents (lock.ts): a pre-existing file at a
|
|
9
29
|
* target path the lock does not record is a conflict, left untouched and
|
|
@@ -12,11 +32,15 @@
|
|
|
12
32
|
*
|
|
13
33
|
* Fails loud: a missing assets dir/target repo, a profile with no leanCtx
|
|
14
34
|
* section, or a missing source asset file all throw. There is no
|
|
15
|
-
* partial-success return value.
|
|
35
|
+
* partial-success return value. A resolveLeanCtxWrite CONFLICT is reported
|
|
36
|
+
* in the ordinary `conflicts` array (like any other), not a throw — the
|
|
37
|
+
* caller (apps/cli's `adl install`) is the one that turns a non-empty
|
|
38
|
+
* conflicts list into a loud, non-zero-exit failure.
|
|
16
39
|
*/
|
|
17
40
|
import { existsSync, mkdirSync, readFileSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
18
41
|
import { dirname, join } from "node:path";
|
|
19
42
|
import { legacyFileTakeover, legacyTakeoverForGitignore, type LegacyLockDoc, readLegacyLock, stripLegacyOwnership } from "./legacy-lock.js";
|
|
43
|
+
import { resolveConfigTomlWrite, resolveGitignoreWrite, resolveLeanCtxWrite } from "./lean-ctx-merge.js";
|
|
20
44
|
import { leanCtxOwned, readLock, writeLock } from "./lock.js";
|
|
21
45
|
import { type DeployProfile, loadProfile } from "./profile.js";
|
|
22
46
|
|
|
@@ -24,6 +48,8 @@ export interface DeployLeanCtxOptions {
|
|
|
24
48
|
readonly assetsDir: string; // packages/agent-settings/assets/lean-ctx
|
|
25
49
|
readonly targetRepo: string;
|
|
26
50
|
readonly profile?: DeployProfile;
|
|
51
|
+
/** Computes the exact same written/unchanged/removed/conflicts result without writing anything (target files, lock, or legacy lock) — independent review, 2026-09-29, finding 6. */
|
|
52
|
+
readonly dryRun?: boolean;
|
|
27
53
|
}
|
|
28
54
|
|
|
29
55
|
export interface LeanCtxConflict {
|
|
@@ -31,16 +57,26 @@ export interface LeanCtxConflict {
|
|
|
31
57
|
readonly reason: string;
|
|
32
58
|
}
|
|
33
59
|
|
|
60
|
+
/** One adl-owned scalar restored to adl's own value this run (2026-09-30, Tarun's merge-contract correction: "adl-owned entries SELF-HEAL" — named explicitly, the same way a healed hook is named, never silent). */
|
|
61
|
+
export interface RestoredLeanCtxScalar {
|
|
62
|
+
readonly target: string;
|
|
63
|
+
readonly key: string;
|
|
64
|
+
readonly value: unknown;
|
|
65
|
+
readonly previous: unknown;
|
|
66
|
+
}
|
|
67
|
+
|
|
34
68
|
export interface DeployLeanCtxResult {
|
|
35
69
|
readonly written: readonly string[];
|
|
36
70
|
readonly unchanged: readonly string[];
|
|
37
71
|
readonly removed: readonly string[];
|
|
38
72
|
readonly conflicts: readonly LeanCtxConflict[];
|
|
39
73
|
readonly lockPath: string;
|
|
74
|
+
readonly restored: readonly RestoredLeanCtxScalar[];
|
|
40
75
|
}
|
|
41
76
|
|
|
42
77
|
export function deployLeanCtx(options: DeployLeanCtxOptions): DeployLeanCtxResult {
|
|
43
78
|
const { assetsDir, targetRepo } = options;
|
|
79
|
+
const dryRun = options.dryRun === true;
|
|
44
80
|
|
|
45
81
|
if (!existsSync(assetsDir) || !statSync(assetsDir).isDirectory()) {
|
|
46
82
|
throw new Error(`agent-settings lean-ctx assets directory not found: ${assetsDir}`);
|
|
@@ -61,6 +97,7 @@ export function deployLeanCtx(options: DeployLeanCtxOptions): DeployLeanCtxResul
|
|
|
61
97
|
const unchanged: string[] = [];
|
|
62
98
|
const removed: string[] = [];
|
|
63
99
|
const conflicts: LeanCtxConflict[] = [];
|
|
100
|
+
const restored: RestoredLeanCtxScalar[] = [];
|
|
64
101
|
const newLeanCtxEntries: Record<string, boolean> = {};
|
|
65
102
|
const kept: string[] = [];
|
|
66
103
|
const legacyFileRemovals: string[] = [];
|
|
@@ -76,6 +113,15 @@ export function deployLeanCtx(options: DeployLeanCtxOptions): DeployLeanCtxResul
|
|
|
76
113
|
const targetAbs = join(targetRepo, file.target);
|
|
77
114
|
const exists = existsSync(targetAbs);
|
|
78
115
|
let managedByUs = leanCtxOwned(lock, file.target);
|
|
116
|
+
// Set only when THIS run's legacy hash check (below) is what makes
|
|
117
|
+
// managedByUs true — that check already verified the file's exact
|
|
118
|
+
// bytes against the OLD engine's own lock, so unlike leanCtxOwned
|
|
119
|
+
// (our own lock's unverified "we wrote this at some point" record),
|
|
120
|
+
// there is no risk of undetected foreign/user content mixed in, and
|
|
121
|
+
// the file can be overwritten wholesale — the same as a fresh write,
|
|
122
|
+
// never through resolveLeanCtxWrite's cautious migration path (which
|
|
123
|
+
// exists precisely for the case this check has already ruled out).
|
|
124
|
+
let legacyVerifiedClean = false;
|
|
79
125
|
|
|
80
126
|
if (exists && !managedByUs) {
|
|
81
127
|
const currentContent = readFileSync(targetAbs, "utf8");
|
|
@@ -84,26 +130,71 @@ export function deployLeanCtx(options: DeployLeanCtxOptions): DeployLeanCtxResul
|
|
|
84
130
|
// sha256), so fall back to that comparison for whichever target it is.
|
|
85
131
|
if (legacyFileTakeover(currentContent, legacyDoc, file.target)) {
|
|
86
132
|
managedByUs = true;
|
|
133
|
+
legacyVerifiedClean = true;
|
|
87
134
|
legacyFileRemovals.push(file.target);
|
|
88
135
|
anyLegacyTakeover = true;
|
|
89
136
|
} else if (legacyTakeoverForGitignore(currentContent, legacyDoc, file.target)) {
|
|
90
137
|
managedByUs = true;
|
|
138
|
+
legacyVerifiedClean = true;
|
|
91
139
|
legacyGitignoreRemovals.push(file.target);
|
|
92
140
|
anyLegacyTakeover = true;
|
|
93
141
|
}
|
|
94
142
|
}
|
|
95
143
|
|
|
96
|
-
|
|
144
|
+
// Independent review, 2026-09-30, finding 6: this guard used to apply
|
|
145
|
+
// uniformly, so a user-authored .agents/.gitignore with no markers at
|
|
146
|
+
// all (never written by us — managedByUs false) hit a hard conflict
|
|
147
|
+
// right here, before resolveGitignoreWrite ever got a chance to run
|
|
148
|
+
// its own append-not-conflict migration. .gitignore is deliberately
|
|
149
|
+
// exempted: append is always safe there (a stray, harmless duplicate
|
|
150
|
+
// ignore line at worst), unlike config.toml/layout.toml where
|
|
151
|
+
// guessing at a foreign file's structure is not.
|
|
152
|
+
if (exists && !managedByUs && file.asset !== "gitignore") {
|
|
97
153
|
conflicts.push({ target: file.target, reason: "a user-owned file already exists at this path; deploy left it untouched" });
|
|
98
154
|
continue;
|
|
99
155
|
}
|
|
100
156
|
|
|
101
|
-
if (exists
|
|
157
|
+
if (!exists || legacyVerifiedClean) {
|
|
158
|
+
if (!dryRun) {
|
|
159
|
+
mkdirSync(dirname(targetAbs), { recursive: true });
|
|
160
|
+
writeFileSync(targetAbs, content);
|
|
161
|
+
}
|
|
162
|
+
written.push(file.target);
|
|
163
|
+
newLeanCtxEntries[file.target] = true;
|
|
164
|
+
kept.push(file.target);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const currentContent = readFileSync(targetAbs, "utf8");
|
|
169
|
+
if (currentContent === content) {
|
|
170
|
+
unchanged.push(file.target);
|
|
171
|
+
newLeanCtxEntries[file.target] = true;
|
|
172
|
+
kept.push(file.target);
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const outcome =
|
|
177
|
+
file.asset === "config.toml"
|
|
178
|
+
? resolveConfigTomlWrite(content, currentContent, managedByUs)
|
|
179
|
+
: file.asset === "gitignore"
|
|
180
|
+
? resolveGitignoreWrite(content, currentContent, managedByUs)
|
|
181
|
+
: resolveLeanCtxWrite(content, currentContent, managedByUs);
|
|
182
|
+
if (outcome.action === "conflict") {
|
|
183
|
+
// Still tracked as ours going forward (a fixed-up file can migrate
|
|
184
|
+
// or self-heal on a later run) but never written to now.
|
|
185
|
+
conflicts.push({ target: file.target, reason: outcome.reason });
|
|
186
|
+
newLeanCtxEntries[file.target] = true;
|
|
187
|
+
kept.push(file.target);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (outcome.action === "unchanged") {
|
|
102
191
|
unchanged.push(file.target);
|
|
103
192
|
} else {
|
|
104
|
-
|
|
105
|
-
writeFileSync(targetAbs, content);
|
|
193
|
+
if (!dryRun) writeFileSync(targetAbs, outcome.text);
|
|
106
194
|
written.push(file.target);
|
|
195
|
+
for (const scalar of outcome.restoredScalars ?? []) {
|
|
196
|
+
restored.push({ target: file.target, key: scalar.key, value: scalar.value, previous: scalar.previous });
|
|
197
|
+
}
|
|
107
198
|
}
|
|
108
199
|
newLeanCtxEntries[file.target] = true;
|
|
109
200
|
kept.push(file.target);
|
|
@@ -112,11 +203,11 @@ export function deployLeanCtx(options: DeployLeanCtxOptions): DeployLeanCtxResul
|
|
|
112
203
|
for (const target of Object.keys(lock.leanCtx)) {
|
|
113
204
|
if (kept.includes(target)) continue;
|
|
114
205
|
const targetAbs = join(targetRepo, target);
|
|
115
|
-
if (existsSync(targetAbs)) unlinkSync(targetAbs);
|
|
206
|
+
if (!dryRun && existsSync(targetAbs)) unlinkSync(targetAbs);
|
|
116
207
|
removed.push(target);
|
|
117
208
|
}
|
|
118
209
|
|
|
119
|
-
writeLock(targetRepo, { schema: 1, mcp: lock.mcp, agents: lock.agents, leanCtx: newLeanCtxEntries });
|
|
210
|
+
if (!dryRun) writeLock(targetRepo, { schema: 1, mcp: lock.mcp, agents: lock.agents, leanCtx: newLeanCtxEntries });
|
|
120
211
|
|
|
121
212
|
// Once anything was actually taken over, this package's own footprint in
|
|
122
213
|
// the legacy lock (these exact `files` entries and/or the `.agents/.gitignore`
|
|
@@ -124,7 +215,7 @@ export function deployLeanCtx(options: DeployLeanCtxOptions): DeployLeanCtxResul
|
|
|
124
215
|
// .agents/agent-settings.lock.json just written above. A legacy lock
|
|
125
216
|
// present but untouched by any takeover (no hash matched, or this repo
|
|
126
217
|
// never had one) is left exactly as found.
|
|
127
|
-
if (anyLegacyTakeover && legacyDoc !== undefined && legacyLockPath !== undefined) {
|
|
218
|
+
if (!dryRun && anyLegacyTakeover && legacyDoc !== undefined && legacyLockPath !== undefined) {
|
|
128
219
|
stripLegacyOwnership(legacyDoc, legacyLockPath, { files: legacyFileRemovals, gitignore: legacyGitignoreRemovals });
|
|
129
220
|
}
|
|
130
221
|
|
|
@@ -134,5 +225,6 @@ export function deployLeanCtx(options: DeployLeanCtxOptions): DeployLeanCtxResul
|
|
|
134
225
|
removed: removed.sort(),
|
|
135
226
|
conflicts: conflicts.sort((a, b) => a.target.localeCompare(b.target)),
|
|
136
227
|
lockPath: join(targetRepo, ".agents/agent-settings.lock.json"),
|
|
228
|
+
restored,
|
|
137
229
|
};
|
|
138
230
|
}
|