@cleocode/caamp 2026.8.1 → 2026.8.2
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/{chunk-EH5U4PRC.js → chunk-3IQUGSIV.js} +302 -106
- package/dist/chunk-3IQUGSIV.js.map +1 -0
- package/dist/{chunk-QUAT7JH6.js → chunk-6KBUDJZI.js} +38 -85
- package/dist/chunk-6KBUDJZI.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +447 -15
- package/dist/index.js +25 -3
- package/dist/index.js.map +1 -1
- package/dist/{injector-3TOVIDBO.js → injector-6YGSK3B6.js} +6 -2
- package/package.json +7 -7
- package/dist/chunk-EH5U4PRC.js.map +0 -1
- package/dist/chunk-QUAT7JH6.js.map +0 -1
- /package/dist/{injector-3TOVIDBO.js.map → injector-6YGSK3B6.js.map} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
getAgentsHome,
|
|
2
3
|
resolveProviderSkillsDir,
|
|
3
4
|
resolveProvidersRegistryPath,
|
|
4
5
|
resolveRegistryTemplatePath
|
|
@@ -6,13 +7,80 @@ import {
|
|
|
6
7
|
|
|
7
8
|
// src/core/instructions/injector.ts
|
|
8
9
|
import { existsSync } from "fs";
|
|
9
|
-
import {
|
|
10
|
+
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
10
11
|
import { homedir } from "os";
|
|
11
|
-
import {
|
|
12
|
+
import { join as join2 } from "path";
|
|
13
|
+
import { writeFileAtomic } from "@cleocode/core/tools/fs.js";
|
|
14
|
+
|
|
15
|
+
// src/core/fs/atomic.ts
|
|
16
|
+
import { mkdir, open, readFile, rm, stat, writeFile } from "fs/promises";
|
|
17
|
+
import { dirname } from "path";
|
|
18
|
+
var DEFAULT_STALE_LOCK_MS = 3e4;
|
|
19
|
+
var DEFAULT_LOCK_RETRIES = 400;
|
|
20
|
+
var DEFAULT_LOCK_DELAY_MS = 25;
|
|
21
|
+
function sleep(ms) {
|
|
22
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
23
|
+
}
|
|
24
|
+
async function removeStaleGuard(guardPath, staleMs, expectedToken) {
|
|
25
|
+
try {
|
|
26
|
+
const info = await stat(guardPath);
|
|
27
|
+
if (Date.now() - info.mtimeMs <= staleMs) return false;
|
|
28
|
+
const current = await readFile(guardPath, "utf-8").catch(() => null);
|
|
29
|
+
if (expectedToken !== null && current !== null && current !== expectedToken) return false;
|
|
30
|
+
await rm(guardPath, { force: true });
|
|
31
|
+
return true;
|
|
32
|
+
} catch {
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
async function withFileLock(targetPath, fn, options = {}) {
|
|
37
|
+
const retries = options.retries ?? DEFAULT_LOCK_RETRIES;
|
|
38
|
+
const delayMs = options.delayMs ?? DEFAULT_LOCK_DELAY_MS;
|
|
39
|
+
const staleMs = options.staleMs ?? DEFAULT_STALE_LOCK_MS;
|
|
40
|
+
const guardPath = `${targetPath}.lock`;
|
|
41
|
+
const token = `${process.pid}:${Date.now()}:${Math.random().toString(36).slice(2, 12)}`;
|
|
42
|
+
await mkdir(dirname(targetPath), { recursive: true });
|
|
43
|
+
let acquired = false;
|
|
44
|
+
for (let attempt = 0; attempt < retries && !acquired; attempt += 1) {
|
|
45
|
+
try {
|
|
46
|
+
const handle = await open(guardPath, "wx");
|
|
47
|
+
await handle.close();
|
|
48
|
+
await writeFile(guardPath, token, "utf-8");
|
|
49
|
+
acquired = true;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
const code = error.code;
|
|
52
|
+
if (code !== "EEXIST") throw error;
|
|
53
|
+
const observed = await readFile(guardPath, "utf-8").catch(() => null);
|
|
54
|
+
if (await removeStaleGuard(guardPath, staleMs, observed)) continue;
|
|
55
|
+
await sleep(delayMs);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (!acquired) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`Timed out acquiring lock for ${targetPath} after ${retries} attempts (~${Math.round(retries * delayMs / 1e3)}s)`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
return await fn();
|
|
65
|
+
} finally {
|
|
66
|
+
const current = await readFile(guardPath, "utf-8").catch(() => null);
|
|
67
|
+
if (current === null || current === token) {
|
|
68
|
+
await rm(guardPath, { force: true }).catch(() => {
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function assertNotTornRead(filePath, content, sizeOnDisk) {
|
|
74
|
+
if (content.length === 0 && sizeOnDisk > 0) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`Refusing to rewrite ${filePath}: read 0 bytes but the file is ${sizeOnDisk} bytes on disk (torn read from a concurrent non-atomic writer).`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
12
80
|
|
|
13
81
|
// src/core/registry/providers.ts
|
|
14
82
|
import { readFileSync } from "fs";
|
|
15
|
-
import { dirname, join } from "path";
|
|
83
|
+
import { dirname as dirname2, join } from "path";
|
|
16
84
|
import { fileURLToPath } from "url";
|
|
17
85
|
var DEFAULT_SKILLS_CAPABILITY = {
|
|
18
86
|
agentsGlobalPath: null,
|
|
@@ -91,7 +159,7 @@ function resolveCapabilities(raw) {
|
|
|
91
159
|
return { mcp, harness, skills, hooks, spawn };
|
|
92
160
|
}
|
|
93
161
|
function findRegistryPath() {
|
|
94
|
-
const thisDir =
|
|
162
|
+
const thisDir = dirname2(fileURLToPath(import.meta.url));
|
|
95
163
|
return resolveProvidersRegistryPath(thisDir);
|
|
96
164
|
}
|
|
97
165
|
var _registry = null;
|
|
@@ -281,6 +349,102 @@ function providerSupportsById(idOrAlias, capabilityPath) {
|
|
|
281
349
|
return providerSupports(provider, capabilityPath);
|
|
282
350
|
}
|
|
283
351
|
|
|
352
|
+
// src/core/instructions/markers.ts
|
|
353
|
+
import {
|
|
354
|
+
CAAMP_BLOCK_PATTERN_SOURCE,
|
|
355
|
+
CAAMP_DAMAGED_END_PATTERN_SOURCE,
|
|
356
|
+
CAAMP_DAMAGED_START_PATTERN_SOURCE,
|
|
357
|
+
CAAMP_MARKER_END,
|
|
358
|
+
CAAMP_MARKER_START
|
|
359
|
+
} from "@cleocode/contracts/caamp-markers";
|
|
360
|
+
function blockPattern() {
|
|
361
|
+
return new RegExp(CAAMP_BLOCK_PATTERN_SOURCE, "g");
|
|
362
|
+
}
|
|
363
|
+
function normalizeMarkers(content) {
|
|
364
|
+
let repaired = 0;
|
|
365
|
+
const heal = (input, source, canonical) => input.replace(new RegExp(source, "gmi"), (match) => {
|
|
366
|
+
if (match === canonical) return match;
|
|
367
|
+
repaired += 1;
|
|
368
|
+
return canonical;
|
|
369
|
+
});
|
|
370
|
+
let out = heal(content, CAAMP_DAMAGED_START_PATTERN_SOURCE, CAAMP_MARKER_START);
|
|
371
|
+
out = heal(out, CAAMP_DAMAGED_END_PATTERN_SOURCE, CAAMP_MARKER_END);
|
|
372
|
+
return { content: out, repaired };
|
|
373
|
+
}
|
|
374
|
+
function parseBlocks(fileContent) {
|
|
375
|
+
const blocks = [];
|
|
376
|
+
const pattern = blockPattern();
|
|
377
|
+
for (let match = pattern.exec(fileContent); match !== null; match = pattern.exec(fileContent)) {
|
|
378
|
+
const raw = match[0];
|
|
379
|
+
blocks.push({
|
|
380
|
+
raw,
|
|
381
|
+
content: (match[1] ?? "").trim(),
|
|
382
|
+
startIndex: match.index,
|
|
383
|
+
endIndex: match.index + raw.length
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
return blocks;
|
|
387
|
+
}
|
|
388
|
+
function buildBlock(content) {
|
|
389
|
+
return `${CAAMP_MARKER_START}
|
|
390
|
+
${content}
|
|
391
|
+
${CAAMP_MARKER_END}`;
|
|
392
|
+
}
|
|
393
|
+
function tidy(content) {
|
|
394
|
+
const collapsed = content.replace(/\n{3,}/g, "\n\n").trimEnd();
|
|
395
|
+
return collapsed.length > 0 ? `${collapsed}
|
|
396
|
+
` : "";
|
|
397
|
+
}
|
|
398
|
+
function reconcile(existing, desiredContent, insert = "prepend") {
|
|
399
|
+
const { content: healed, repaired } = normalizeMarkers(existing);
|
|
400
|
+
const blocks = parseBlocks(healed);
|
|
401
|
+
const desiredBlock = buildBlock(desiredContent.trim());
|
|
402
|
+
if (blocks.length === 0) {
|
|
403
|
+
const body = healed.trim();
|
|
404
|
+
if (body.length === 0) return { content: tidy(desiredBlock), blocksBefore: 0, repaired };
|
|
405
|
+
return {
|
|
406
|
+
content: insert === "append" ? tidy(`${body}
|
|
407
|
+
|
|
408
|
+
${desiredBlock}`) : tidy(`${desiredBlock}
|
|
409
|
+
|
|
410
|
+
${body}`),
|
|
411
|
+
blocksBefore: 0,
|
|
412
|
+
repaired
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
let out = "";
|
|
416
|
+
let cursor = 0;
|
|
417
|
+
for (const [index, block] of blocks.entries()) {
|
|
418
|
+
out += healed.slice(cursor, block.startIndex);
|
|
419
|
+
cursor = block.endIndex;
|
|
420
|
+
if (index === 0) out += desiredBlock;
|
|
421
|
+
}
|
|
422
|
+
out += healed.slice(cursor);
|
|
423
|
+
return { content: tidy(out), blocksBefore: blocks.length, repaired };
|
|
424
|
+
}
|
|
425
|
+
function mergeBlockBodies(blocks) {
|
|
426
|
+
const seen = /* @__PURE__ */ new Set();
|
|
427
|
+
const lines = [];
|
|
428
|
+
for (const block of blocks) {
|
|
429
|
+
for (const line of block.content.split("\n")) {
|
|
430
|
+
const trimmed = line.trim();
|
|
431
|
+
if (trimmed.length === 0 || seen.has(trimmed)) continue;
|
|
432
|
+
seen.add(trimmed);
|
|
433
|
+
lines.push(trimmed);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return lines.join("\n");
|
|
437
|
+
}
|
|
438
|
+
function repairContent(existing) {
|
|
439
|
+
const { content: healed, repaired } = normalizeMarkers(existing);
|
|
440
|
+
const blocks = parseBlocks(healed);
|
|
441
|
+
if (blocks.length === 0) {
|
|
442
|
+
return { content: healed, blocksBefore: 0, repaired };
|
|
443
|
+
}
|
|
444
|
+
const merged = reconcile(healed, mergeBlockBodies(blocks));
|
|
445
|
+
return { content: merged.content, blocksBefore: blocks.length, repaired };
|
|
446
|
+
}
|
|
447
|
+
|
|
284
448
|
// src/core/instructions/templates.ts
|
|
285
449
|
function buildInjectionContent(template) {
|
|
286
450
|
const lines = [];
|
|
@@ -350,56 +514,51 @@ function groupByInstructFile(providers) {
|
|
|
350
514
|
}
|
|
351
515
|
|
|
352
516
|
// src/core/instructions/injector.ts
|
|
353
|
-
var MARKER_START = "<!-- CAAMP:START -->";
|
|
354
|
-
var MARKER_END = "<!-- CAAMP:END -->";
|
|
355
|
-
var MARKER_PATTERN = /<!-- CAAMP:START -->[\s\S]*?<!-- CAAMP:END -->/g;
|
|
356
|
-
var MARKER_PATTERN_SINGLE = /<!-- CAAMP:START -->[\s\S]*?<!-- CAAMP:END -->/;
|
|
357
517
|
function parseCaampBlocks(fileContent) {
|
|
358
|
-
|
|
359
|
-
const pattern = /<!-- CAAMP:START -->([\s\S]*?)<!-- CAAMP:END -->/g;
|
|
360
|
-
for (let match = pattern.exec(fileContent); match !== null; match = pattern.exec(fileContent)) {
|
|
361
|
-
const raw = match[0];
|
|
362
|
-
const innerContent = match[1] ?? "";
|
|
363
|
-
blocks.push({
|
|
364
|
-
raw,
|
|
365
|
-
content: innerContent.trim(),
|
|
366
|
-
startIndex: match.index,
|
|
367
|
-
endIndex: match.index + raw.length
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
return blocks;
|
|
518
|
+
return parseBlocks(fileContent);
|
|
371
519
|
}
|
|
372
520
|
async function dedupeFile(filePath) {
|
|
373
521
|
if (!existsSync(filePath)) {
|
|
374
|
-
return { filePath, removed: 0, kept: 0, modified: false };
|
|
375
|
-
}
|
|
376
|
-
const fileContent = await readFile(filePath, "utf-8");
|
|
377
|
-
const blocks = parseCaampBlocks(fileContent);
|
|
378
|
-
if (blocks.length === 0) {
|
|
379
|
-
return { filePath, removed: 0, kept: 0, modified: false };
|
|
380
|
-
}
|
|
381
|
-
const lastByContent = /* @__PURE__ */ new Map();
|
|
382
|
-
for (const block of blocks) {
|
|
383
|
-
lastByContent.set(block.content, block);
|
|
384
|
-
}
|
|
385
|
-
const keepSet = new Set(lastByContent.values());
|
|
386
|
-
const removed = blocks.length - keepSet.size;
|
|
387
|
-
if (removed === 0) {
|
|
388
|
-
return { filePath, removed: 0, kept: blocks.length, modified: false };
|
|
522
|
+
return { filePath, removed: 0, kept: 0, modified: false, repaired: 0 };
|
|
389
523
|
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
524
|
+
return withFileLock(filePath, async () => {
|
|
525
|
+
const original = await readFile2(filePath, "utf-8");
|
|
526
|
+
const { content: healed, repaired } = normalizeMarkers(original);
|
|
527
|
+
const blocks = parseBlocks(healed);
|
|
528
|
+
if (blocks.length === 0) {
|
|
529
|
+
if (repaired > 0 && healed !== original) {
|
|
530
|
+
await writeFileAtomic({ path: filePath, content: healed });
|
|
531
|
+
return { filePath, removed: 0, kept: 0, modified: true, repaired };
|
|
532
|
+
}
|
|
533
|
+
return { filePath, removed: 0, kept: 0, modified: false, repaired };
|
|
397
534
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
535
|
+
const lastByContent = /* @__PURE__ */ new Map();
|
|
536
|
+
for (const block of blocks) {
|
|
537
|
+
lastByContent.set(block.content, block);
|
|
538
|
+
}
|
|
539
|
+
const keepSet = new Set(lastByContent.values());
|
|
540
|
+
const removed = blocks.length - keepSet.size;
|
|
541
|
+
let result = "";
|
|
542
|
+
let cursor = 0;
|
|
543
|
+
for (const block of blocks) {
|
|
544
|
+
result += healed.slice(cursor, block.startIndex);
|
|
545
|
+
cursor = block.endIndex;
|
|
546
|
+
if (keepSet.has(block)) {
|
|
547
|
+
result += block.raw;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
result += healed.slice(cursor);
|
|
551
|
+
result = `${result.replace(/\n{3,}/g, "\n\n").trimEnd()}
|
|
552
|
+
`;
|
|
553
|
+
if (removed === 0 && repaired === 0) {
|
|
554
|
+
return { filePath, removed: 0, kept: blocks.length, modified: false, repaired };
|
|
555
|
+
}
|
|
556
|
+
if (result === original) {
|
|
557
|
+
return { filePath, removed: 0, kept: blocks.length, modified: false, repaired };
|
|
558
|
+
}
|
|
559
|
+
await writeFileAtomic({ path: filePath, content: result });
|
|
560
|
+
return { filePath, removed, kept: keepSet.size, modified: true, repaired };
|
|
561
|
+
});
|
|
403
562
|
}
|
|
404
563
|
async function dedupeFiles(filePaths) {
|
|
405
564
|
const results = [];
|
|
@@ -408,76 +567,102 @@ async function dedupeFiles(filePaths) {
|
|
|
408
567
|
}
|
|
409
568
|
return results;
|
|
410
569
|
}
|
|
570
|
+
function instructionFileCascade(projectDir, providers) {
|
|
571
|
+
const paths = [
|
|
572
|
+
join2(getAgentsHome(), "AGENTS.md"),
|
|
573
|
+
join2(projectDir, "AGENTS.md"),
|
|
574
|
+
join2(projectDir, "CLAUDE.md"),
|
|
575
|
+
join2(projectDir, "GEMINI.md")
|
|
576
|
+
];
|
|
577
|
+
for (const provider of providers) {
|
|
578
|
+
paths.push(join2(provider.pathGlobal, provider.instructFile));
|
|
579
|
+
}
|
|
580
|
+
return [...new Set(paths)];
|
|
581
|
+
}
|
|
582
|
+
async function repairInstructionFiles(projectDir, providers) {
|
|
583
|
+
const paths = instructionFileCascade(projectDir, providers).filter((p) => existsSync(p));
|
|
584
|
+
const files = [];
|
|
585
|
+
for (const filePath of paths) {
|
|
586
|
+
files.push(
|
|
587
|
+
await withFileLock(filePath, async () => {
|
|
588
|
+
const original = await readFile2(filePath, "utf-8");
|
|
589
|
+
const { content, blocksBefore, repaired } = repairContent(original);
|
|
590
|
+
const removed = Math.max(0, blocksBefore - 1);
|
|
591
|
+
if (removed === 0 && repaired === 0) {
|
|
592
|
+
return { filePath, removed: 0, kept: blocksBefore, modified: false, repaired: 0 };
|
|
593
|
+
}
|
|
594
|
+
if (content === original) {
|
|
595
|
+
return { filePath, removed: 0, kept: blocksBefore, modified: false, repaired };
|
|
596
|
+
}
|
|
597
|
+
await writeFileAtomic({ path: filePath, content });
|
|
598
|
+
return {
|
|
599
|
+
filePath,
|
|
600
|
+
removed,
|
|
601
|
+
kept: blocksBefore > 0 ? 1 : 0,
|
|
602
|
+
modified: true,
|
|
603
|
+
repaired
|
|
604
|
+
};
|
|
605
|
+
})
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
return {
|
|
609
|
+
files,
|
|
610
|
+
repaired: files.reduce((n, r) => n + r.repaired, 0),
|
|
611
|
+
removed: files.reduce((n, r) => n + r.removed, 0),
|
|
612
|
+
filesModified: files.filter((r) => r.modified).length
|
|
613
|
+
};
|
|
614
|
+
}
|
|
411
615
|
async function checkInjection(filePath, expectedContent) {
|
|
412
616
|
if (!existsSync(filePath)) return "missing";
|
|
413
|
-
const
|
|
414
|
-
|
|
617
|
+
const raw = await readFile2(filePath, "utf-8");
|
|
618
|
+
const { content, repaired } = normalizeMarkers(raw);
|
|
619
|
+
const blocks = parseBlocks(content);
|
|
620
|
+
if (blocks.length === 0) return "none";
|
|
621
|
+
if (blocks.length > 1 || repaired > 0) return "outdated";
|
|
415
622
|
if (expectedContent) {
|
|
416
|
-
|
|
417
|
-
if (blockContent && blockContent.trim() === expectedContent.trim()) {
|
|
418
|
-
return "current";
|
|
419
|
-
}
|
|
420
|
-
return "outdated";
|
|
623
|
+
return blocks[0]?.content === expectedContent.trim() ? "current" : "outdated";
|
|
421
624
|
}
|
|
422
625
|
return "current";
|
|
423
626
|
}
|
|
424
|
-
function extractBlock(content) {
|
|
425
|
-
const match = content.match(MARKER_PATTERN_SINGLE);
|
|
426
|
-
if (!match) return null;
|
|
427
|
-
return match[0].replace(MARKER_START, "").replace(MARKER_END, "").trim();
|
|
428
|
-
}
|
|
429
|
-
function buildBlock(content) {
|
|
430
|
-
return `${MARKER_START}
|
|
431
|
-
${content}
|
|
432
|
-
${MARKER_END}`;
|
|
433
|
-
}
|
|
434
627
|
async function inject(filePath, content) {
|
|
435
|
-
const
|
|
436
|
-
await mkdir(dirname2(filePath), { recursive: true });
|
|
628
|
+
const body = content.trim();
|
|
437
629
|
if (!existsSync(filePath)) {
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
${updated3}` : `${block}
|
|
450
|
-
`;
|
|
451
|
-
await writeFile(filePath, finalContent, "utf-8");
|
|
452
|
-
return "consolidated";
|
|
453
|
-
}
|
|
454
|
-
const existingBlock = extractBlock(existing);
|
|
455
|
-
if (existingBlock !== null && existingBlock.trim() === content.trim()) {
|
|
456
|
-
return "intact";
|
|
630
|
+
return withFileLock(filePath, async () => {
|
|
631
|
+
await writeFileAtomic({ path: filePath, content: `${buildBlock(body)}
|
|
632
|
+
` });
|
|
633
|
+
return "created";
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
return withFileLock(filePath, async () => {
|
|
637
|
+
const existing = await readFile2(filePath, "utf-8");
|
|
638
|
+
if (existing.length === 0) {
|
|
639
|
+
assertNotTornRead(filePath, existing, (await stat2(filePath)).size);
|
|
457
640
|
}
|
|
458
|
-
const
|
|
459
|
-
|
|
641
|
+
const { content: next, blocksBefore, repaired } = reconcile(existing, body);
|
|
642
|
+
if (next === existing) return "intact";
|
|
643
|
+
await writeFileAtomic({ path: filePath, content: next });
|
|
644
|
+
if (blocksBefore === 0) return "added";
|
|
645
|
+
if (repaired > 0) return "repaired";
|
|
646
|
+
if (blocksBefore > 1) return "consolidated";
|
|
460
647
|
return "updated";
|
|
461
|
-
}
|
|
462
|
-
const updated = `${block}
|
|
463
|
-
|
|
464
|
-
${existing}`;
|
|
465
|
-
await writeFile(filePath, updated, "utf-8");
|
|
466
|
-
return "added";
|
|
648
|
+
});
|
|
467
649
|
}
|
|
468
650
|
async function removeInjection(filePath) {
|
|
469
651
|
if (!existsSync(filePath)) return false;
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
652
|
+
return withFileLock(filePath, async () => {
|
|
653
|
+
const original = await readFile2(filePath, "utf-8");
|
|
654
|
+
const { content } = normalizeMarkers(original);
|
|
655
|
+
if (parseBlocks(content).length === 0) return false;
|
|
656
|
+
const cleaned = content.replace(blockPattern(), "").replace(/^\n{2,}/, "\n").trim();
|
|
657
|
+
if (!cleaned) {
|
|
658
|
+
const { rm: rm2 } = await import("fs/promises");
|
|
659
|
+
await rm2(filePath);
|
|
660
|
+
} else {
|
|
661
|
+
await writeFileAtomic({ path: filePath, content: `${cleaned}
|
|
662
|
+
` });
|
|
663
|
+
}
|
|
664
|
+
return true;
|
|
665
|
+
});
|
|
481
666
|
}
|
|
482
667
|
async function checkAllInjections(providers, projectDir, scope, expectedContent) {
|
|
483
668
|
const results = [];
|
|
@@ -608,6 +793,8 @@ async function writeAgentFileToAllProviders(providerIds, options) {
|
|
|
608
793
|
}
|
|
609
794
|
|
|
610
795
|
export {
|
|
796
|
+
withFileLock,
|
|
797
|
+
assertNotTornRead,
|
|
611
798
|
getAllProviders,
|
|
612
799
|
getProvider,
|
|
613
800
|
resolveAlias,
|
|
@@ -629,6 +816,13 @@ export {
|
|
|
629
816
|
buildSkillsMap,
|
|
630
817
|
getProviderCapabilities,
|
|
631
818
|
providerSupportsById,
|
|
819
|
+
blockPattern,
|
|
820
|
+
normalizeMarkers,
|
|
821
|
+
parseBlocks,
|
|
822
|
+
buildBlock,
|
|
823
|
+
reconcile,
|
|
824
|
+
mergeBlockBodies,
|
|
825
|
+
repairContent,
|
|
632
826
|
buildInjectionContent,
|
|
633
827
|
parseInjectionContent,
|
|
634
828
|
generateInjectionContent,
|
|
@@ -637,6 +831,8 @@ export {
|
|
|
637
831
|
parseCaampBlocks,
|
|
638
832
|
dedupeFile,
|
|
639
833
|
dedupeFiles,
|
|
834
|
+
instructionFileCascade,
|
|
835
|
+
repairInstructionFiles,
|
|
640
836
|
checkInjection,
|
|
641
837
|
inject,
|
|
642
838
|
removeInjection,
|
|
@@ -647,4 +843,4 @@ export {
|
|
|
647
843
|
getProviderAgentFolder,
|
|
648
844
|
writeAgentFileToAllProviders
|
|
649
845
|
};
|
|
650
|
-
//# sourceMappingURL=chunk-
|
|
846
|
+
//# sourceMappingURL=chunk-3IQUGSIV.js.map
|