@alessandroraffa/tangyr 1.0.1 → 1.0.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/index.js +135 -18
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -17378,21 +17378,33 @@ function collectProjectScopeFindings(projectRoot, tools, options) {
|
|
|
17378
17378
|
) : void 0;
|
|
17379
17379
|
const probePaths = buildProjectProbes(tool, projectRoot, profile);
|
|
17380
17380
|
for (const { resolvedPath, description, classification } of probePaths) {
|
|
17381
|
-
|
|
17381
|
+
let stat;
|
|
17382
|
+
try {
|
|
17383
|
+
stat = fs11.lstatSync(resolvedPath);
|
|
17384
|
+
} catch {
|
|
17382
17385
|
continue;
|
|
17383
17386
|
}
|
|
17384
|
-
const
|
|
17387
|
+
const type = stat.isSymbolicLink() ? "symlink" : stat.isDirectory() ? "directory" : "file";
|
|
17388
|
+
const ours = type === "file" && carriesTangyrMarker(resolvedPath);
|
|
17385
17389
|
findings.push({
|
|
17386
17390
|
path: resolvedPath,
|
|
17387
17391
|
tool,
|
|
17388
|
-
type
|
|
17389
|
-
classification,
|
|
17390
|
-
description
|
|
17392
|
+
type,
|
|
17393
|
+
classification: ours ? "compatible" : classification,
|
|
17394
|
+
description: ours ? `${description} (written by Tangyr)` : description
|
|
17391
17395
|
});
|
|
17392
17396
|
}
|
|
17393
17397
|
}
|
|
17394
17398
|
return findings;
|
|
17395
17399
|
}
|
|
17400
|
+
function carriesTangyrMarker(filePath) {
|
|
17401
|
+
try {
|
|
17402
|
+
const firstNonEmpty = fs11.readFileSync(filePath, "utf8").split("\n").find((line) => line.trim().length > 0) ?? "";
|
|
17403
|
+
return extractProvenanceMarker(firstNonEmpty) !== null;
|
|
17404
|
+
} catch {
|
|
17405
|
+
return false;
|
|
17406
|
+
}
|
|
17407
|
+
}
|
|
17396
17408
|
function requestedAssessTools(toolFilter) {
|
|
17397
17409
|
return toolFilter ?? [...DEFAULT_ASSESS_TARGETS];
|
|
17398
17410
|
}
|
|
@@ -22182,11 +22194,23 @@ async function runUninstallCommand(options, logger) {
|
|
|
22182
22194
|
}
|
|
22183
22195
|
const claudeRoots = scope === "global" && selectedTools.has("claude-code") ? resolveClaudeRootsForUninstall(manifest, runtime) : [];
|
|
22184
22196
|
let removedCount = 0;
|
|
22197
|
+
const removedParentDirs = /* @__PURE__ */ new Set();
|
|
22185
22198
|
for (const file of useManifestPathRemoval ? manifestArtifacts : []) {
|
|
22186
22199
|
if (isMergeSurfaceKey(file.relativePath)) {
|
|
22187
|
-
|
|
22188
|
-
|
|
22200
|
+
const surfacePath = file.path ?? resolveManifestKeyToPath(
|
|
22201
|
+
file.relativePath,
|
|
22202
|
+
scope,
|
|
22203
|
+
runtime,
|
|
22204
|
+
uninstallProjectRoot
|
|
22189
22205
|
);
|
|
22206
|
+
if (surfacePath && stripTangyrFromMergeSurface(surfacePath, logger)) {
|
|
22207
|
+
removedParentDirs.add(path24.dirname(surfacePath));
|
|
22208
|
+
removedCount++;
|
|
22209
|
+
} else {
|
|
22210
|
+
logger.verbose(
|
|
22211
|
+
` left in place (merge surface, nothing of ours in it): ${surfacePath ?? file.relativePath}`
|
|
22212
|
+
);
|
|
22213
|
+
}
|
|
22190
22214
|
continue;
|
|
22191
22215
|
}
|
|
22192
22216
|
const isClaudeGlobal = file.relativePath.startsWith("claude-code/") && scope === "global";
|
|
@@ -22199,6 +22223,7 @@ async function runUninstallCommand(options, logger) {
|
|
|
22199
22223
|
for (const actualPath of paths) {
|
|
22200
22224
|
if (actualPath && (fs27.existsSync(actualPath) || isSymlink(actualPath))) {
|
|
22201
22225
|
removeManagedPath(actualPath);
|
|
22226
|
+
removedParentDirs.add(path24.dirname(actualPath));
|
|
22202
22227
|
logger.verbose(` removed: ${actualPath}`);
|
|
22203
22228
|
removedCount++;
|
|
22204
22229
|
} else {
|
|
@@ -22220,6 +22245,7 @@ async function runUninstallCommand(options, logger) {
|
|
|
22220
22245
|
continue;
|
|
22221
22246
|
}
|
|
22222
22247
|
removeManagedPath(actualPath);
|
|
22248
|
+
removedParentDirs.add(path24.dirname(actualPath));
|
|
22223
22249
|
logger.verbose(` removed: ${actualPath}`);
|
|
22224
22250
|
removedCount++;
|
|
22225
22251
|
} else {
|
|
@@ -22270,6 +22296,11 @@ async function runUninstallCommand(options, logger) {
|
|
|
22270
22296
|
fs27.unlinkSync(manifestPath);
|
|
22271
22297
|
logger.verbose(` removed manifest: ${manifestPath}`);
|
|
22272
22298
|
}
|
|
22299
|
+
pruneEmptyDirs(path24.join(scopePath, "backups"), logger);
|
|
22300
|
+
const pruneBoundary = path24.dirname(scopePath);
|
|
22301
|
+
for (const dir of removedParentDirs) {
|
|
22302
|
+
pruneEmptyAncestors(dir, pruneBoundary, logger);
|
|
22303
|
+
}
|
|
22273
22304
|
try {
|
|
22274
22305
|
const remaining = fs27.readdirSync(scopePath);
|
|
22275
22306
|
if (remaining.length === 0) {
|
|
@@ -22649,6 +22680,79 @@ var MERGE_SURFACE_SLOTS = /* @__PURE__ */ new Set([
|
|
|
22649
22680
|
"mcp_shared_file",
|
|
22650
22681
|
"mcp_file"
|
|
22651
22682
|
]);
|
|
22683
|
+
function stripTangyrFromMergeSurface(filePath, logger) {
|
|
22684
|
+
const parsed = readJsonObject2(filePath);
|
|
22685
|
+
if (!parsed) {
|
|
22686
|
+
return false;
|
|
22687
|
+
}
|
|
22688
|
+
const cleaned = { ...parsed };
|
|
22689
|
+
const hooks = removeManagedClaudeHookEntries(
|
|
22690
|
+
parsed.hooks,
|
|
22691
|
+
(entry) => entry._tangyr === true || entry._proteus === true
|
|
22692
|
+
);
|
|
22693
|
+
if (hooks === void 0) {
|
|
22694
|
+
delete cleaned.hooks;
|
|
22695
|
+
} else {
|
|
22696
|
+
cleaned.hooks = hooks;
|
|
22697
|
+
}
|
|
22698
|
+
if (isRecord(parsed.mcpServers)) {
|
|
22699
|
+
const kept = Object.fromEntries(
|
|
22700
|
+
Object.entries(parsed.mcpServers).filter(
|
|
22701
|
+
([, server]) => !isRecord(server) || !isRecord(server._tangyr) && !isRecord(server._proteus)
|
|
22702
|
+
)
|
|
22703
|
+
);
|
|
22704
|
+
if (Object.keys(kept).length === 0) {
|
|
22705
|
+
delete cleaned.mcpServers;
|
|
22706
|
+
} else {
|
|
22707
|
+
cleaned.mcpServers = kept;
|
|
22708
|
+
}
|
|
22709
|
+
}
|
|
22710
|
+
delete cleaned._tangyr;
|
|
22711
|
+
delete cleaned._proteus;
|
|
22712
|
+
if (JSON.stringify(cleaned) === JSON.stringify(parsed)) {
|
|
22713
|
+
return false;
|
|
22714
|
+
}
|
|
22715
|
+
writeJsonOrRemove(filePath, cleaned);
|
|
22716
|
+
logger.verbose(` stripped Tangyr's block from: ${filePath}`);
|
|
22717
|
+
return true;
|
|
22718
|
+
}
|
|
22719
|
+
function pruneEmptyAncestors(startDir, stopAt, logger) {
|
|
22720
|
+
const boundary = path24.resolve(stopAt);
|
|
22721
|
+
let current = path24.resolve(startDir);
|
|
22722
|
+
while (current !== boundary && current.startsWith(`${boundary}${path24.sep}`)) {
|
|
22723
|
+
try {
|
|
22724
|
+
if (fs27.readdirSync(current).length > 0) {
|
|
22725
|
+
return;
|
|
22726
|
+
}
|
|
22727
|
+
fs27.rmdirSync(current);
|
|
22728
|
+
logger.verbose(` removed empty directory: ${current}`);
|
|
22729
|
+
} catch {
|
|
22730
|
+
return;
|
|
22731
|
+
}
|
|
22732
|
+
current = path24.dirname(current);
|
|
22733
|
+
}
|
|
22734
|
+
}
|
|
22735
|
+
function pruneEmptyDirs(dir, logger) {
|
|
22736
|
+
let stat;
|
|
22737
|
+
try {
|
|
22738
|
+
stat = fs27.lstatSync(dir);
|
|
22739
|
+
} catch {
|
|
22740
|
+
return;
|
|
22741
|
+
}
|
|
22742
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
22743
|
+
return;
|
|
22744
|
+
}
|
|
22745
|
+
for (const entry of fs27.readdirSync(dir, { withFileTypes: true })) {
|
|
22746
|
+
if (entry.isDirectory() && !entry.isSymbolicLink()) {
|
|
22747
|
+
pruneEmptyDirs(path24.join(dir, entry.name), logger);
|
|
22748
|
+
}
|
|
22749
|
+
}
|
|
22750
|
+
try {
|
|
22751
|
+
fs27.rmdirSync(dir);
|
|
22752
|
+
logger.verbose(` removed empty directory: ${dir}`);
|
|
22753
|
+
} catch {
|
|
22754
|
+
}
|
|
22755
|
+
}
|
|
22652
22756
|
function stillMatchesRecord(artifactPath, recorded) {
|
|
22653
22757
|
if (isLegacyArtifactState(recorded)) {
|
|
22654
22758
|
return true;
|
|
@@ -24987,6 +25091,7 @@ function toConflictPolicy2(value) {
|
|
|
24987
25091
|
}
|
|
24988
25092
|
|
|
24989
25093
|
// src/commands/install.ts
|
|
25094
|
+
import crypto11 from "crypto";
|
|
24990
25095
|
import fs43 from "fs";
|
|
24991
25096
|
import path43 from "path";
|
|
24992
25097
|
|
|
@@ -26398,6 +26503,12 @@ function applyClaudeCodeShimUpgrade(shimPath, agentsMdPath, manifest, scopePath,
|
|
|
26398
26503
|
const firstNonEmptyLine = existing.split("\n").find((l) => l.trim().length > 0) ?? "";
|
|
26399
26504
|
const marker = extractProvenanceMarker(firstNonEmptyLine);
|
|
26400
26505
|
if (marker !== null && marker.hash === expectedBodyHash) {
|
|
26506
|
+
addArtifactToManifest(manifest, {
|
|
26507
|
+
relativePath: SHIM_MANIFEST_KEY,
|
|
26508
|
+
path: shimPath,
|
|
26509
|
+
hash: expectedBodyHash,
|
|
26510
|
+
origin: "tangyr-managed"
|
|
26511
|
+
});
|
|
26401
26512
|
logger?.verbose(
|
|
26402
26513
|
`instructions-shim: already current, skipped -> ${shimPath}`
|
|
26403
26514
|
);
|
|
@@ -30731,7 +30842,12 @@ function isBackupablePath(targetPath) {
|
|
|
30731
30842
|
}
|
|
30732
30843
|
function backupConflictingTarget(targetPath, scopePath) {
|
|
30733
30844
|
const ts2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/gu, "").replace("T", "T").replace(/\.\d+Z$/u, "Z");
|
|
30734
|
-
const
|
|
30845
|
+
const scopeRoot = path43.dirname(scopePath);
|
|
30846
|
+
let relativeToRoot = path43.relative(scopeRoot, targetPath);
|
|
30847
|
+
if (relativeToRoot.startsWith("..") || path43.isAbsolute(relativeToRoot)) {
|
|
30848
|
+
const digest = crypto11.createHash("sha256").update(path43.dirname(targetPath)).digest("hex").slice(0, 12);
|
|
30849
|
+
relativeToRoot = path43.join(`_outside-${digest}`, path43.basename(targetPath));
|
|
30850
|
+
}
|
|
30735
30851
|
const backupPath = path43.join(scopePath, "backups", ts2, relativeToRoot);
|
|
30736
30852
|
fs43.mkdirSync(path43.dirname(backupPath), { recursive: true });
|
|
30737
30853
|
const stat = fs43.lstatSync(targetPath);
|
|
@@ -30953,14 +31069,14 @@ async function runInstallCommand(options, logger) {
|
|
|
30953
31069
|
return;
|
|
30954
31070
|
}
|
|
30955
31071
|
if (conflictingFindings.length > 0) {
|
|
31072
|
+
const toolsByPath = /* @__PURE__ */ new Map();
|
|
31073
|
+
for (const finding of conflictingFindings) {
|
|
31074
|
+
const tools2 = toolsByPath.get(finding.path) ?? [];
|
|
31075
|
+
tools2.push(finding.tool);
|
|
31076
|
+
toolsByPath.set(finding.path, tools2);
|
|
31077
|
+
}
|
|
30956
31078
|
if (options.yes) {
|
|
30957
31079
|
const decidedPaths = /* @__PURE__ */ new Set();
|
|
30958
|
-
const toolsByPath = /* @__PURE__ */ new Map();
|
|
30959
|
-
for (const finding of conflictingFindings) {
|
|
30960
|
-
const tools2 = toolsByPath.get(finding.path) ?? [];
|
|
30961
|
-
tools2.push(finding.tool);
|
|
30962
|
-
toolsByPath.set(finding.path, tools2);
|
|
30963
|
-
}
|
|
30964
31080
|
const posture = config.onConflict === "ask" ? "skip" : config.onConflict;
|
|
30965
31081
|
const replaceable = Array.from(toolsByPath.keys()).filter(
|
|
30966
31082
|
(p) => !foreignSkillsSlots.has(p)
|
|
@@ -31039,10 +31155,11 @@ ACCEPTED CONFLICTS (posture: ${posture}; ${replaceable.length} target(s)):`
|
|
|
31039
31155
|
} else {
|
|
31040
31156
|
logger.info(
|
|
31041
31157
|
`
|
|
31042
|
-
Found ${
|
|
31158
|
+
Found ${toolsByPath.size} conflicting target(s). Please choose an action for each:
|
|
31043
31159
|
`
|
|
31044
31160
|
);
|
|
31045
|
-
for (const
|
|
31161
|
+
for (const [conflictPath, claimingTools] of toolsByPath) {
|
|
31162
|
+
const finding = { path: conflictPath, tool: claimingTools.join(", ") };
|
|
31046
31163
|
const choice = await dist_default8({
|
|
31047
31164
|
message: `Conflict: ${finding.path} (${finding.tool})
|
|
31048
31165
|
Choose an action:`,
|
|
@@ -32358,7 +32475,7 @@ function commandProbeRows(target, key, command, args) {
|
|
|
32358
32475
|
}
|
|
32359
32476
|
|
|
32360
32477
|
// src/commands/status.ts
|
|
32361
|
-
import
|
|
32478
|
+
import crypto12 from "crypto";
|
|
32362
32479
|
import fs45 from "fs";
|
|
32363
32480
|
import path46 from "path";
|
|
32364
32481
|
function runStatusCommand(options, logger) {
|
|
@@ -33482,7 +33599,7 @@ function containsTangyrSource(value) {
|
|
|
33482
33599
|
return typeof value._tangyr_source === "string" || typeof value._proteus_source === "string" || Object.values(value).some((entry) => containsTangyrSource(entry));
|
|
33483
33600
|
}
|
|
33484
33601
|
function hashString6(value) {
|
|
33485
|
-
return `sha256:${
|
|
33602
|
+
return `sha256:${crypto12.createHash("sha256").update(value).digest("hex")}`;
|
|
33486
33603
|
}
|
|
33487
33604
|
|
|
33488
33605
|
// src/commands/sync.ts
|