@alessandroraffa/tangyr 9.0.0 → 10.0.0
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 +529 -287
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -16362,8 +16362,8 @@ function assertSupportedNodeRuntime(nodeVersion = process.version) {
|
|
|
16362
16362
|
}
|
|
16363
16363
|
|
|
16364
16364
|
// src/commands/assess.ts
|
|
16365
|
-
import
|
|
16366
|
-
import
|
|
16365
|
+
import fs13 from "fs";
|
|
16366
|
+
import path15 from "path";
|
|
16367
16367
|
|
|
16368
16368
|
// src/core/scope.ts
|
|
16369
16369
|
import fs7 from "fs";
|
|
@@ -17263,22 +17263,107 @@ function toPosixRelativePath(root, filePath) {
|
|
|
17263
17263
|
return path11.relative(root, filePath).split(path11.sep).join(path11.posix.sep);
|
|
17264
17264
|
}
|
|
17265
17265
|
|
|
17266
|
+
// src/core/managed-sources.ts
|
|
17267
|
+
var import_yaml5 = __toESM(require_dist(), 1);
|
|
17268
|
+
import fs11 from "fs";
|
|
17269
|
+
import path12 from "path";
|
|
17270
|
+
function resolveKitComponentNames(sourceRoot, category) {
|
|
17271
|
+
const manifestPath = path12.resolve(sourceRoot, "tangyr-kit.yaml");
|
|
17272
|
+
if (!fs11.existsSync(manifestPath)) {
|
|
17273
|
+
return void 0;
|
|
17274
|
+
}
|
|
17275
|
+
try {
|
|
17276
|
+
const raw = fs11.readFileSync(manifestPath, "utf8");
|
|
17277
|
+
const doc = (0, import_yaml5.parse)(raw);
|
|
17278
|
+
if (doc && typeof doc === "object" && !Array.isArray(doc) && "components" in doc) {
|
|
17279
|
+
const components = doc.components;
|
|
17280
|
+
if (components && typeof components === "object" && !Array.isArray(components) && category in components) {
|
|
17281
|
+
const names = components[category];
|
|
17282
|
+
if (Array.isArray(names) && names.every((n7) => typeof n7 === "string")) {
|
|
17283
|
+
return names;
|
|
17284
|
+
}
|
|
17285
|
+
}
|
|
17286
|
+
}
|
|
17287
|
+
} catch {
|
|
17288
|
+
}
|
|
17289
|
+
return void 0;
|
|
17290
|
+
}
|
|
17291
|
+
function resolveKitHookNames(sourceRoot) {
|
|
17292
|
+
return resolveKitComponentNames(sourceRoot, "hooks");
|
|
17293
|
+
}
|
|
17294
|
+
function resolveKitSkillNames(sourceRoot) {
|
|
17295
|
+
return resolveKitComponentNames(sourceRoot, "skills");
|
|
17296
|
+
}
|
|
17297
|
+
function resolveKitSlotNames(sourceRoot, category) {
|
|
17298
|
+
return resolveKitComponentNames(sourceRoot, category);
|
|
17299
|
+
}
|
|
17300
|
+
function resolveKitEntrypointName(sourceRoot) {
|
|
17301
|
+
const manifestPath = path12.resolve(sourceRoot, "tangyr-kit.yaml");
|
|
17302
|
+
if (!fs11.existsSync(manifestPath)) {
|
|
17303
|
+
return void 0;
|
|
17304
|
+
}
|
|
17305
|
+
try {
|
|
17306
|
+
const doc = (0, import_yaml5.parse)(fs11.readFileSync(manifestPath, "utf8"));
|
|
17307
|
+
if (doc && typeof doc === "object" && !Array.isArray(doc)) {
|
|
17308
|
+
const value = doc.entrypoint;
|
|
17309
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
17310
|
+
return value.trim();
|
|
17311
|
+
}
|
|
17312
|
+
}
|
|
17313
|
+
} catch {
|
|
17314
|
+
}
|
|
17315
|
+
return void 0;
|
|
17316
|
+
}
|
|
17317
|
+
function resolveHooksSourceFile(sourceRoot, config) {
|
|
17318
|
+
return path12.resolve(sourceRoot, config.source.hooks, "hooks.json");
|
|
17319
|
+
}
|
|
17320
|
+
function resolveHooksSourceDir(sourceRoot, config) {
|
|
17321
|
+
return path12.resolve(sourceRoot, config.source.hooks);
|
|
17322
|
+
}
|
|
17323
|
+
function hooksSourceExists(sourceRoot, config) {
|
|
17324
|
+
const hooksJsonPath = resolveHooksSourceFile(sourceRoot, config);
|
|
17325
|
+
if (fs11.existsSync(hooksJsonPath)) {
|
|
17326
|
+
return true;
|
|
17327
|
+
}
|
|
17328
|
+
const hooksDir = resolveHooksSourceDir(sourceRoot, config);
|
|
17329
|
+
if (!fs11.existsSync(hooksDir) || !fs11.statSync(hooksDir).isDirectory()) {
|
|
17330
|
+
return false;
|
|
17331
|
+
}
|
|
17332
|
+
return fs11.readdirSync(hooksDir).some((f) => f.endsWith(".md") && !f.startsWith("."));
|
|
17333
|
+
}
|
|
17334
|
+
function hooksSourceLabel(sourceRoot, config) {
|
|
17335
|
+
const dir = normalizeManagedSourcePath(
|
|
17336
|
+
config.source.hooks.replace(/\\/gu, "/")
|
|
17337
|
+
);
|
|
17338
|
+
return fs11.existsSync(resolveHooksSourceFile(sourceRoot, config)) ? path12.posix.join(dir, "hooks.json") : `${dir}/`;
|
|
17339
|
+
}
|
|
17340
|
+
function resolveMcpSourceFile(sourceRoot, config) {
|
|
17341
|
+
return path12.resolve(sourceRoot, config.source.mcp);
|
|
17342
|
+
}
|
|
17343
|
+
function mcpSourceLabel(config) {
|
|
17344
|
+
return normalizeManagedSourcePath(config.source.mcp);
|
|
17345
|
+
}
|
|
17346
|
+
function normalizeManagedSourcePath(rawPath) {
|
|
17347
|
+
const normalized = rawPath.replace(/\\/gu, "/");
|
|
17348
|
+
return normalized.startsWith("./") ? normalized.slice(2) : normalized;
|
|
17349
|
+
}
|
|
17350
|
+
|
|
17266
17351
|
// src/core/foreign-instructions.ts
|
|
17267
|
-
import
|
|
17352
|
+
import path14 from "path";
|
|
17268
17353
|
|
|
17269
17354
|
// src/core/contested-instructions.ts
|
|
17270
|
-
import
|
|
17271
|
-
import
|
|
17355
|
+
import fs12 from "fs";
|
|
17356
|
+
import path13 from "path";
|
|
17272
17357
|
var FOLDS_RULES_INTO_INSTRUCTIONS = {
|
|
17273
17358
|
codex: "its own rules slot takes only exec-policy rules, so guidance rules are folded in",
|
|
17274
17359
|
opencode: "it has no rules slot of its own, so every rule is folded in"
|
|
17275
17360
|
};
|
|
17276
17361
|
function markerTarget(destination) {
|
|
17277
17362
|
try {
|
|
17278
|
-
if (
|
|
17363
|
+
if (fs12.lstatSync(destination).isSymbolicLink()) {
|
|
17279
17364
|
return null;
|
|
17280
17365
|
}
|
|
17281
|
-
const firstNonEmpty =
|
|
17366
|
+
const firstNonEmpty = fs12.readFileSync(destination, "utf8").split("\n").find((line) => line.trim().length > 0) ?? "";
|
|
17282
17367
|
return extractProvenanceMarker(firstNonEmpty)?.target ?? null;
|
|
17283
17368
|
} catch {
|
|
17284
17369
|
return null;
|
|
@@ -17287,7 +17372,7 @@ function markerTarget(destination) {
|
|
|
17287
17372
|
function findContestedInstructions(instructionsByTarget) {
|
|
17288
17373
|
const byPath = /* @__PURE__ */ new Map();
|
|
17289
17374
|
for (const [target, destination] of instructionsByTarget) {
|
|
17290
|
-
const resolved =
|
|
17375
|
+
const resolved = path13.resolve(destination);
|
|
17291
17376
|
byPath.set(resolved, [...byPath.get(resolved) ?? [], target]);
|
|
17292
17377
|
}
|
|
17293
17378
|
const contested = [];
|
|
@@ -17349,7 +17434,7 @@ function instructionsByActiveTarget(tools, scope, projectRoot, mappings) {
|
|
|
17349
17434
|
}
|
|
17350
17435
|
}
|
|
17351
17436
|
if (scope === "project" && projectRoot && tools.includes("copilot")) {
|
|
17352
|
-
byTarget.set("copilot",
|
|
17437
|
+
byTarget.set("copilot", path13.join(projectRoot, "AGENTS.md"));
|
|
17353
17438
|
}
|
|
17354
17439
|
return byTarget;
|
|
17355
17440
|
}
|
|
@@ -17358,7 +17443,7 @@ function instructionsByActiveTarget(tools, scope, projectRoot, mappings) {
|
|
|
17358
17443
|
function instructionsEntrypoints(tools, scope, projectRoot, mappings) {
|
|
17359
17444
|
const byPath = /* @__PURE__ */ new Map();
|
|
17360
17445
|
const add = (destination, tool) => {
|
|
17361
|
-
const resolved2 =
|
|
17446
|
+
const resolved2 = path14.resolve(destination);
|
|
17362
17447
|
const targets = byPath.get(resolved2) ?? [];
|
|
17363
17448
|
if (!targets.includes(tool)) {
|
|
17364
17449
|
targets.push(tool);
|
|
@@ -17389,7 +17474,7 @@ function instructionsEntrypoints(tools, scope, projectRoot, mappings) {
|
|
|
17389
17474
|
function findForeignInstructions(conflicting, entrypoints) {
|
|
17390
17475
|
const found2 = /* @__PURE__ */ new Map();
|
|
17391
17476
|
for (const finding of conflicting) {
|
|
17392
|
-
const resolved =
|
|
17477
|
+
const resolved = path14.resolve(finding.path);
|
|
17393
17478
|
const targets = entrypoints.get(resolved);
|
|
17394
17479
|
if (targets && !found2.has(resolved)) {
|
|
17395
17480
|
found2.set(resolved, { path: resolved, targets });
|
|
@@ -17402,7 +17487,7 @@ function describeForeignInstructions(foreign, projectRoot) {
|
|
|
17402
17487
|
if (!projectRoot) {
|
|
17403
17488
|
return target;
|
|
17404
17489
|
}
|
|
17405
|
-
const relative =
|
|
17490
|
+
const relative = path14.relative(projectRoot, target);
|
|
17406
17491
|
return relative.startsWith("..") ? target : relative;
|
|
17407
17492
|
};
|
|
17408
17493
|
const width = Math.max(...foreign.map((one) => display2(one.path).length));
|
|
@@ -17549,10 +17634,10 @@ function collectAssessFindings(scope, projectRoot, toolFilter, assessOptions) {
|
|
|
17549
17634
|
}
|
|
17550
17635
|
for (const target of probe.paths) {
|
|
17551
17636
|
const resolvedPath = resolveTargetPath(target.path);
|
|
17552
|
-
if (!
|
|
17637
|
+
if (!fs13.existsSync(resolvedPath)) {
|
|
17553
17638
|
continue;
|
|
17554
17639
|
}
|
|
17555
|
-
const stat =
|
|
17640
|
+
const stat = fs13.lstatSync(resolvedPath);
|
|
17556
17641
|
findings.push({
|
|
17557
17642
|
path: resolvedPath,
|
|
17558
17643
|
tool: probe.tool,
|
|
@@ -17580,16 +17665,17 @@ function collectAssessFindings(scope, projectRoot, toolFilter, assessOptions) {
|
|
|
17580
17665
|
if (finding.classification !== "conflicting") {
|
|
17581
17666
|
continue;
|
|
17582
17667
|
}
|
|
17583
|
-
const resolved =
|
|
17668
|
+
const resolved = path15.resolve(finding.path);
|
|
17584
17669
|
const ours = recorded.has(resolved) || finding.type === "directory" && holdsOnlyRecorded(resolved, recorded);
|
|
17585
17670
|
if (ours) {
|
|
17586
17671
|
finding.classification = "compatible";
|
|
17587
17672
|
finding.description = `${finding.description} (recorded by this installation)`;
|
|
17588
17673
|
}
|
|
17589
17674
|
}
|
|
17590
|
-
|
|
17675
|
+
expandPerEntrySlots(findings, recorded, scope, projectRoot, assessOptions);
|
|
17676
|
+
if (fs13.existsSync(path15.join(scopePath, "manifest.json"))) {
|
|
17591
17677
|
findings.push({
|
|
17592
|
-
path:
|
|
17678
|
+
path: path15.join(scopePath, "manifest.json"),
|
|
17593
17679
|
tool: "tangyr",
|
|
17594
17680
|
type: "file",
|
|
17595
17681
|
classification: "compatible",
|
|
@@ -17733,7 +17819,7 @@ function collectProjectScopeFindings(projectRoot, tools, options) {
|
|
|
17733
17819
|
for (const { resolvedPath, description, classification } of probePaths) {
|
|
17734
17820
|
let stat;
|
|
17735
17821
|
try {
|
|
17736
|
-
stat =
|
|
17822
|
+
stat = fs13.lstatSync(resolvedPath);
|
|
17737
17823
|
} catch {
|
|
17738
17824
|
continue;
|
|
17739
17825
|
}
|
|
@@ -17750,6 +17836,87 @@ function collectProjectScopeFindings(projectRoot, tools, options) {
|
|
|
17750
17836
|
}
|
|
17751
17837
|
return findings;
|
|
17752
17838
|
}
|
|
17839
|
+
function expandPerEntrySlots(findings, recorded, scope, projectRoot, options) {
|
|
17840
|
+
const slots = perEntrySlotPaths(scope, projectRoot, options);
|
|
17841
|
+
if (slots.size === 0) {
|
|
17842
|
+
return;
|
|
17843
|
+
}
|
|
17844
|
+
for (let index = findings.length - 1; index >= 0; index--) {
|
|
17845
|
+
const finding = findings[index];
|
|
17846
|
+
if (finding.classification !== "conflicting" || finding.type !== "directory" || !slots.has(path15.resolve(finding.path))) {
|
|
17847
|
+
continue;
|
|
17848
|
+
}
|
|
17849
|
+
const wanted = slots.get(path15.resolve(finding.path)) ?? /* @__PURE__ */ new Set();
|
|
17850
|
+
let entries;
|
|
17851
|
+
try {
|
|
17852
|
+
entries = fs13.readdirSync(finding.path);
|
|
17853
|
+
} catch {
|
|
17854
|
+
continue;
|
|
17855
|
+
}
|
|
17856
|
+
const foreign = entries.filter((entry) => wanted.has(entry)).map((entry) => path15.join(finding.path, entry)).filter((entry) => !recorded.has(path15.resolve(entry))).filter((entry) => !carriesProvenanceMarker(entry));
|
|
17857
|
+
findings.splice(
|
|
17858
|
+
index,
|
|
17859
|
+
1,
|
|
17860
|
+
...foreign.map((entry) => ({
|
|
17861
|
+
path: entry,
|
|
17862
|
+
tool: finding.tool,
|
|
17863
|
+
type: "file",
|
|
17864
|
+
classification: "conflicting",
|
|
17865
|
+
description: `${finding.description} \u2014 this entry is not ours`
|
|
17866
|
+
}))
|
|
17867
|
+
);
|
|
17868
|
+
}
|
|
17869
|
+
}
|
|
17870
|
+
function perEntrySlotPaths(scope, projectRoot, options) {
|
|
17871
|
+
const slots = /* @__PURE__ */ new Map();
|
|
17872
|
+
let config;
|
|
17873
|
+
let configDir;
|
|
17874
|
+
let kitPath;
|
|
17875
|
+
try {
|
|
17876
|
+
({ config, configDir } = resolveConfig(options.config));
|
|
17877
|
+
kitPath = resolveKitPath(config, configDir);
|
|
17878
|
+
if (!kitPath) {
|
|
17879
|
+
return slots;
|
|
17880
|
+
}
|
|
17881
|
+
} catch {
|
|
17882
|
+
return slots;
|
|
17883
|
+
}
|
|
17884
|
+
let profile;
|
|
17885
|
+
try {
|
|
17886
|
+
profile = resolveTargetPaths({
|
|
17887
|
+
scope,
|
|
17888
|
+
projectRoot,
|
|
17889
|
+
mappings: loadMappings(kitPath, config, configDir).platformPaths
|
|
17890
|
+
})["claude-code"];
|
|
17891
|
+
} catch {
|
|
17892
|
+
return slots;
|
|
17893
|
+
}
|
|
17894
|
+
const kit = kitPath;
|
|
17895
|
+
const named = (slot, category, sourceKey, extension) => {
|
|
17896
|
+
if (typeof slot !== "string") {
|
|
17897
|
+
return;
|
|
17898
|
+
}
|
|
17899
|
+
const source = path15.resolve(kit, String(config.source[sourceKey]));
|
|
17900
|
+
const declared = resolveKitSlotNames(kit, category);
|
|
17901
|
+
const names = declared?.map((name) => `${name}${extension}`) ?? listSourceEntries(source, extension);
|
|
17902
|
+
slots.set(path15.resolve(slot), new Set(names));
|
|
17903
|
+
};
|
|
17904
|
+
named(profile.agents, "agents", "agents", ".md");
|
|
17905
|
+
named(profile.commands, "commands", "commands", ".md");
|
|
17906
|
+
named(profile.rules, "rules", "rules", ".md");
|
|
17907
|
+
named(profile.output_styles, "output-styles", "outputStyles", ".md");
|
|
17908
|
+
named(profile.skills, "skills", "skills", "");
|
|
17909
|
+
return slots;
|
|
17910
|
+
}
|
|
17911
|
+
function listSourceEntries(source, extension) {
|
|
17912
|
+
try {
|
|
17913
|
+
return fs13.readdirSync(source, { withFileTypes: true }).filter((entry) => !entry.name.startsWith(".")).filter(
|
|
17914
|
+
(entry) => extension === "" ? entry.isDirectory() : entry.isFile() && entry.name.endsWith(extension)
|
|
17915
|
+
).map((entry) => entry.name);
|
|
17916
|
+
} catch {
|
|
17917
|
+
return [];
|
|
17918
|
+
}
|
|
17919
|
+
}
|
|
17753
17920
|
function requestedAssessTools(toolFilter) {
|
|
17754
17921
|
return toolFilter ?? [...DEFAULT_ASSESS_TARGETS];
|
|
17755
17922
|
}
|
|
@@ -17784,7 +17951,7 @@ function alwaysOnProjectFiles(tool, projectRoot) {
|
|
|
17784
17951
|
if (tool === "claude-code") {
|
|
17785
17952
|
return [
|
|
17786
17953
|
{
|
|
17787
|
-
resolvedPath:
|
|
17954
|
+
resolvedPath: path15.resolve(projectRoot, "CLAUDE.md"),
|
|
17788
17955
|
description: "Project-level Claude instructions",
|
|
17789
17956
|
classification: "conflicting"
|
|
17790
17957
|
}
|
|
@@ -17793,7 +17960,7 @@ function alwaysOnProjectFiles(tool, projectRoot) {
|
|
|
17793
17960
|
if (tool === "copilot") {
|
|
17794
17961
|
return [
|
|
17795
17962
|
{
|
|
17796
|
-
resolvedPath:
|
|
17963
|
+
resolvedPath: path15.resolve(
|
|
17797
17964
|
projectRoot,
|
|
17798
17965
|
".github/copilot-instructions.md"
|
|
17799
17966
|
),
|
|
@@ -17805,7 +17972,7 @@ function alwaysOnProjectFiles(tool, projectRoot) {
|
|
|
17805
17972
|
if (tool === "codex") {
|
|
17806
17973
|
return [
|
|
17807
17974
|
{
|
|
17808
|
-
resolvedPath:
|
|
17975
|
+
resolvedPath: path15.resolve(projectRoot, "AGENTS.md"),
|
|
17809
17976
|
description: "Codex project instructions",
|
|
17810
17977
|
classification: "conflicting"
|
|
17811
17978
|
}
|
|
@@ -17842,11 +18009,11 @@ function recordedArtifactPaths(scopePath) {
|
|
|
17842
18009
|
}
|
|
17843
18010
|
for (const artifact of manifest.artifacts) {
|
|
17844
18011
|
if (artifact.path) {
|
|
17845
|
-
paths.add(
|
|
18012
|
+
paths.add(path15.resolve(artifact.path));
|
|
17846
18013
|
}
|
|
17847
18014
|
}
|
|
17848
18015
|
for (const link of manifest.managedLinks) {
|
|
17849
|
-
paths.add(
|
|
18016
|
+
paths.add(path15.resolve(link.path));
|
|
17850
18017
|
}
|
|
17851
18018
|
} catch {
|
|
17852
18019
|
}
|
|
@@ -17855,15 +18022,15 @@ function recordedArtifactPaths(scopePath) {
|
|
|
17855
18022
|
function holdsOnlyRecorded(dir, recorded) {
|
|
17856
18023
|
let entries;
|
|
17857
18024
|
try {
|
|
17858
|
-
entries =
|
|
18025
|
+
entries = fs13.readdirSync(dir, { withFileTypes: true });
|
|
17859
18026
|
} catch {
|
|
17860
18027
|
return false;
|
|
17861
18028
|
}
|
|
17862
18029
|
if (entries.length === 0) {
|
|
17863
|
-
return [...recorded].some((p) => p.startsWith(`${dir}${
|
|
18030
|
+
return [...recorded].some((p) => p.startsWith(`${dir}${path15.sep}`));
|
|
17864
18031
|
}
|
|
17865
18032
|
for (const entry of entries) {
|
|
17866
|
-
const full =
|
|
18033
|
+
const full = path15.join(dir, entry.name);
|
|
17867
18034
|
if (entry.isDirectory() && !entry.isSymbolicLink()) {
|
|
17868
18035
|
if (!holdsOnlyRecorded(full, recorded)) {
|
|
17869
18036
|
return false;
|
|
@@ -17878,7 +18045,7 @@ function holdsOnlyRecorded(dir, recorded) {
|
|
|
17878
18045
|
}
|
|
17879
18046
|
|
|
17880
18047
|
// src/commands/auth.ts
|
|
17881
|
-
import
|
|
18048
|
+
import fs16 from "fs";
|
|
17882
18049
|
|
|
17883
18050
|
// src/core/transport.ts
|
|
17884
18051
|
var KIT_CONTRACT_VERSION = "1";
|
|
@@ -17967,11 +18134,11 @@ function createFetchKitTransport(options = {}) {
|
|
|
17967
18134
|
}
|
|
17968
18135
|
|
|
17969
18136
|
// src/core/credentials.ts
|
|
17970
|
-
import
|
|
18137
|
+
import fs14 from "fs";
|
|
17971
18138
|
import os3 from "os";
|
|
17972
|
-
import
|
|
17973
|
-
var CREDENTIALS_DIR =
|
|
17974
|
-
var CREDENTIALS_PATH =
|
|
18139
|
+
import path16 from "path";
|
|
18140
|
+
var CREDENTIALS_DIR = path16.join(os3.homedir(), ".tangyr");
|
|
18141
|
+
var CREDENTIALS_PATH = path16.join(CREDENTIALS_DIR, "credentials.json");
|
|
17975
18142
|
function isCurrentCredentialRecord(value) {
|
|
17976
18143
|
if (typeof value !== "object" || value === null) {
|
|
17977
18144
|
return false;
|
|
@@ -17980,10 +18147,10 @@ function isCurrentCredentialRecord(value) {
|
|
|
17980
18147
|
return record.schema === 2 && typeof record.clientId === "string" && record.clientId.length > 0 && typeof record.clientSecret === "string" && record.clientSecret.length > 0 && (record.validation === "validated" || record.validation === "unvalidated") && typeof record.storedAt === "string";
|
|
17981
18148
|
}
|
|
17982
18149
|
function readStoredCredentials() {
|
|
17983
|
-
if (!
|
|
18150
|
+
if (!fs14.existsSync(CREDENTIALS_PATH)) {
|
|
17984
18151
|
return null;
|
|
17985
18152
|
}
|
|
17986
|
-
const raw =
|
|
18153
|
+
const raw = fs14.readFileSync(CREDENTIALS_PATH, "utf8");
|
|
17987
18154
|
const parsed = JSON.parse(raw);
|
|
17988
18155
|
if (!isCurrentCredentialRecord(parsed)) {
|
|
17989
18156
|
throw new CredentialsLegacyError();
|
|
@@ -17993,13 +18160,13 @@ function readStoredCredentials() {
|
|
|
17993
18160
|
function ensureCredentialsDir(logger) {
|
|
17994
18161
|
let created = false;
|
|
17995
18162
|
try {
|
|
17996
|
-
created =
|
|
18163
|
+
created = fs14.mkdirSync(CREDENTIALS_DIR, { recursive: true, mode: 448 }) !== void 0;
|
|
17997
18164
|
} catch (err) {
|
|
17998
18165
|
if (err.code !== "EEXIST") {
|
|
17999
18166
|
throw err;
|
|
18000
18167
|
}
|
|
18001
18168
|
}
|
|
18002
|
-
if (
|
|
18169
|
+
if (fs14.lstatSync(CREDENTIALS_DIR).isSymbolicLink()) {
|
|
18003
18170
|
throw new Error(
|
|
18004
18171
|
`Refusing to write credentials: "${CREDENTIALS_DIR}" already exists as a symbolic link, not a directory. Remove it and run 'tangyr auth login' again.`
|
|
18005
18172
|
);
|
|
@@ -18013,7 +18180,7 @@ function ensureCredentialsDir(logger) {
|
|
|
18013
18180
|
return;
|
|
18014
18181
|
}
|
|
18015
18182
|
try {
|
|
18016
|
-
|
|
18183
|
+
fs14.chmodSync(CREDENTIALS_DIR, 448);
|
|
18017
18184
|
} catch {
|
|
18018
18185
|
logger.warn(
|
|
18019
18186
|
"Could not set owner-only (0700) permissions on the credentials directory on this platform; at-rest protection is reduced (REQ-AUT-007)."
|
|
@@ -18026,41 +18193,41 @@ function writeStoredCredentials(record, logger) {
|
|
|
18026
18193
|
`;
|
|
18027
18194
|
const tmpPath = `${CREDENTIALS_PATH}.tmp`;
|
|
18028
18195
|
try {
|
|
18029
|
-
|
|
18196
|
+
fs14.writeFileSync(tmpPath, content, { mode: 384, flag: "wx" });
|
|
18030
18197
|
} catch (err) {
|
|
18031
18198
|
if (err.code === "EEXIST") {
|
|
18032
|
-
|
|
18033
|
-
|
|
18199
|
+
fs14.unlinkSync(tmpPath);
|
|
18200
|
+
fs14.writeFileSync(tmpPath, content, { mode: 384, flag: "wx" });
|
|
18034
18201
|
} else {
|
|
18035
18202
|
throw err;
|
|
18036
18203
|
}
|
|
18037
18204
|
}
|
|
18038
18205
|
try {
|
|
18039
|
-
|
|
18206
|
+
fs14.renameSync(tmpPath, CREDENTIALS_PATH);
|
|
18040
18207
|
} catch (renameErr) {
|
|
18041
18208
|
try {
|
|
18042
18209
|
try {
|
|
18043
|
-
const destStat =
|
|
18210
|
+
const destStat = fs14.lstatSync(CREDENTIALS_PATH);
|
|
18044
18211
|
if (destStat.isSymbolicLink()) {
|
|
18045
|
-
|
|
18212
|
+
fs14.unlinkSync(CREDENTIALS_PATH);
|
|
18046
18213
|
}
|
|
18047
18214
|
} catch {
|
|
18048
18215
|
}
|
|
18049
|
-
|
|
18216
|
+
fs14.copyFileSync(tmpPath, CREDENTIALS_PATH);
|
|
18050
18217
|
try {
|
|
18051
|
-
|
|
18218
|
+
fs14.chmodSync(CREDENTIALS_PATH, 384);
|
|
18052
18219
|
} catch {
|
|
18053
18220
|
logger.warn(
|
|
18054
18221
|
"Could not set owner-only (0600) permissions on the credentials file on this platform; at-rest protection is reduced (REQ-AUT-007)."
|
|
18055
18222
|
);
|
|
18056
18223
|
}
|
|
18057
18224
|
try {
|
|
18058
|
-
|
|
18225
|
+
fs14.unlinkSync(tmpPath);
|
|
18059
18226
|
} catch {
|
|
18060
18227
|
}
|
|
18061
18228
|
} catch (copyErr) {
|
|
18062
18229
|
try {
|
|
18063
|
-
|
|
18230
|
+
fs14.unlinkSync(tmpPath);
|
|
18064
18231
|
} catch {
|
|
18065
18232
|
}
|
|
18066
18233
|
throw new Error(
|
|
@@ -18105,16 +18272,16 @@ function resolveCredentialNonInteractive() {
|
|
|
18105
18272
|
}
|
|
18106
18273
|
|
|
18107
18274
|
// src/core/freshness.ts
|
|
18108
|
-
import
|
|
18109
|
-
import
|
|
18275
|
+
import fs15 from "fs";
|
|
18276
|
+
import path17 from "path";
|
|
18110
18277
|
var AUTHORIZATION_FRESHNESS_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
18111
18278
|
var FRESHNESS_STATE_FILENAME = ".tangyr-freshness.json";
|
|
18112
18279
|
function resolveFreshnessStatePath(cacheRoot) {
|
|
18113
|
-
return
|
|
18280
|
+
return path17.join(cacheRoot, FRESHNESS_STATE_FILENAME);
|
|
18114
18281
|
}
|
|
18115
18282
|
function readFreshnessStateFile(statePath) {
|
|
18116
18283
|
try {
|
|
18117
|
-
const raw =
|
|
18284
|
+
const raw = fs15.readFileSync(statePath, "utf8");
|
|
18118
18285
|
const parsed = JSON.parse(raw);
|
|
18119
18286
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
18120
18287
|
return {};
|
|
@@ -18134,13 +18301,13 @@ function readLastAuthorizedAt(cacheRoot, originUrl) {
|
|
|
18134
18301
|
return Number.isNaN(parsed.getTime()) ? void 0 : parsed;
|
|
18135
18302
|
}
|
|
18136
18303
|
function writeLastAuthorizedAt(cacheRoot, originUrl, at2) {
|
|
18137
|
-
|
|
18304
|
+
fs15.mkdirSync(cacheRoot, { recursive: true, mode: 448 });
|
|
18138
18305
|
const statePath = resolveFreshnessStatePath(cacheRoot);
|
|
18139
18306
|
const state = readFreshnessStateFile(statePath);
|
|
18140
18307
|
state[originUrl] = at2.toISOString();
|
|
18141
18308
|
const tmpPath = `${statePath}.tmp`;
|
|
18142
|
-
|
|
18143
|
-
|
|
18309
|
+
fs15.writeFileSync(tmpPath, JSON.stringify(state), { mode: 384 });
|
|
18310
|
+
fs15.renameSync(tmpPath, statePath);
|
|
18144
18311
|
}
|
|
18145
18312
|
function isWithinFreshnessWindow(lastAuthorizedAt, now) {
|
|
18146
18313
|
if (lastAuthorizedAt === void 0) {
|
|
@@ -18361,21 +18528,21 @@ async function runAuthStatusCommand(options, logger, transport = createFetchKitT
|
|
|
18361
18528
|
}
|
|
18362
18529
|
}
|
|
18363
18530
|
function runAuthLogoutCommand(_options, logger) {
|
|
18364
|
-
if (!
|
|
18531
|
+
if (!fs16.existsSync(CREDENTIALS_PATH)) {
|
|
18365
18532
|
logger.info("No credential found. Nothing to remove.");
|
|
18366
18533
|
return;
|
|
18367
18534
|
}
|
|
18368
|
-
|
|
18535
|
+
fs16.unlinkSync(CREDENTIALS_PATH);
|
|
18369
18536
|
logger.info("Credential removed.");
|
|
18370
18537
|
}
|
|
18371
18538
|
|
|
18372
18539
|
// src/commands/cache.ts
|
|
18373
|
-
import
|
|
18374
|
-
import
|
|
18540
|
+
import fs18 from "fs";
|
|
18541
|
+
import path19 from "path";
|
|
18375
18542
|
|
|
18376
18543
|
// src/core/cache.ts
|
|
18377
|
-
import
|
|
18378
|
-
import
|
|
18544
|
+
import fs17 from "fs";
|
|
18545
|
+
import path18 from "path";
|
|
18379
18546
|
|
|
18380
18547
|
// src/core/kit-reference.ts
|
|
18381
18548
|
var BARE_URL = /^https?:\/\//u;
|
|
@@ -18434,10 +18601,10 @@ function resolveCacheRoot(env2 = process.env) {
|
|
|
18434
18601
|
);
|
|
18435
18602
|
}
|
|
18436
18603
|
function cacheEntryPath(cacheRoot, reference) {
|
|
18437
|
-
const entry =
|
|
18438
|
-
const resolvedRoot =
|
|
18439
|
-
const resolvedEntry =
|
|
18440
|
-
if (!resolvedEntry.startsWith(resolvedRoot +
|
|
18604
|
+
const entry = path18.join(cacheRoot, reference.name, reference.version);
|
|
18605
|
+
const resolvedRoot = path18.resolve(cacheRoot);
|
|
18606
|
+
const resolvedEntry = path18.resolve(entry);
|
|
18607
|
+
if (!resolvedEntry.startsWith(resolvedRoot + path18.sep)) {
|
|
18441
18608
|
throw new IntegrityError(
|
|
18442
18609
|
`Cache entry path for "${reference.name}@${reference.version}" resolves outside the cache root \u2014 refusing to write.`
|
|
18443
18610
|
);
|
|
@@ -18450,14 +18617,14 @@ function writeCompletionMarker(entryDir, reference) {
|
|
|
18450
18617
|
version: reference.version,
|
|
18451
18618
|
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
18452
18619
|
};
|
|
18453
|
-
|
|
18454
|
-
|
|
18620
|
+
fs17.writeFileSync(
|
|
18621
|
+
path18.join(entryDir, CACHE_COMPLETION_MARKER),
|
|
18455
18622
|
JSON.stringify(marker)
|
|
18456
18623
|
);
|
|
18457
18624
|
}
|
|
18458
18625
|
function writeBundleDocument(entryDir, bundle) {
|
|
18459
|
-
|
|
18460
|
-
|
|
18626
|
+
fs17.writeFileSync(
|
|
18627
|
+
path18.join(entryDir, BUNDLE_DOCUMENT_FILENAME),
|
|
18461
18628
|
JSON.stringify(bundle),
|
|
18462
18629
|
{
|
|
18463
18630
|
mode: 384
|
|
@@ -18465,10 +18632,10 @@ function writeBundleDocument(entryDir, bundle) {
|
|
|
18465
18632
|
);
|
|
18466
18633
|
}
|
|
18467
18634
|
function readBundleDocument(entryDir) {
|
|
18468
|
-
const documentPath =
|
|
18635
|
+
const documentPath = path18.join(entryDir, BUNDLE_DOCUMENT_FILENAME);
|
|
18469
18636
|
let raw;
|
|
18470
18637
|
try {
|
|
18471
|
-
raw =
|
|
18638
|
+
raw = fs17.readFileSync(documentPath, "utf8");
|
|
18472
18639
|
} catch (error) {
|
|
18473
18640
|
if (error.code === "ENOENT") {
|
|
18474
18641
|
return void 0;
|
|
@@ -18487,11 +18654,11 @@ function readBundleDocument(entryDir) {
|
|
|
18487
18654
|
}
|
|
18488
18655
|
function isCompleteCacheEntry(entryDir) {
|
|
18489
18656
|
try {
|
|
18490
|
-
if (!
|
|
18657
|
+
if (!fs17.statSync(entryDir).isDirectory()) {
|
|
18491
18658
|
return false;
|
|
18492
18659
|
}
|
|
18493
|
-
const markerPath =
|
|
18494
|
-
const raw =
|
|
18660
|
+
const markerPath = path18.join(entryDir, CACHE_COMPLETION_MARKER);
|
|
18661
|
+
const raw = fs17.readFileSync(markerPath, "utf8");
|
|
18495
18662
|
JSON.parse(raw);
|
|
18496
18663
|
return true;
|
|
18497
18664
|
} catch {
|
|
@@ -18499,53 +18666,53 @@ function isCompleteCacheEntry(entryDir) {
|
|
|
18499
18666
|
}
|
|
18500
18667
|
}
|
|
18501
18668
|
function createStagingDir(cacheRoot, reference) {
|
|
18502
|
-
const stagingRoot =
|
|
18503
|
-
|
|
18504
|
-
const prefix =
|
|
18669
|
+
const stagingRoot = path18.join(cacheRoot, ".staging");
|
|
18670
|
+
fs17.mkdirSync(stagingRoot, { recursive: true, mode: 448 });
|
|
18671
|
+
const prefix = path18.join(
|
|
18505
18672
|
stagingRoot,
|
|
18506
18673
|
`${reference.name}-${reference.version}-`
|
|
18507
18674
|
);
|
|
18508
|
-
return
|
|
18675
|
+
return fs17.mkdtempSync(prefix);
|
|
18509
18676
|
}
|
|
18510
18677
|
function publishCacheEntry(stagingDir, entryDir) {
|
|
18511
|
-
|
|
18678
|
+
fs17.mkdirSync(path18.dirname(entryDir), { recursive: true, mode: 448 });
|
|
18512
18679
|
try {
|
|
18513
|
-
|
|
18680
|
+
fs17.renameSync(stagingDir, entryDir);
|
|
18514
18681
|
return;
|
|
18515
18682
|
} catch (error) {
|
|
18516
|
-
const entryExists =
|
|
18683
|
+
const entryExists = fs17.existsSync(entryDir);
|
|
18517
18684
|
if (entryExists && isCompleteCacheEntry(entryDir)) {
|
|
18518
|
-
|
|
18685
|
+
fs17.rmSync(stagingDir, { recursive: true, force: true });
|
|
18519
18686
|
return;
|
|
18520
18687
|
}
|
|
18521
18688
|
if (entryExists) {
|
|
18522
|
-
|
|
18689
|
+
fs17.rmSync(entryDir, { recursive: true, force: true });
|
|
18523
18690
|
try {
|
|
18524
|
-
|
|
18691
|
+
fs17.renameSync(stagingDir, entryDir);
|
|
18525
18692
|
return;
|
|
18526
18693
|
} catch (retryError) {
|
|
18527
|
-
|
|
18694
|
+
fs17.rmSync(stagingDir, { recursive: true, force: true });
|
|
18528
18695
|
throw retryError;
|
|
18529
18696
|
}
|
|
18530
18697
|
}
|
|
18531
18698
|
if (error.code === "EXDEV") {
|
|
18532
18699
|
const stagedMarker = JSON.parse(
|
|
18533
|
-
|
|
18700
|
+
fs17.readFileSync(path18.join(stagingDir, CACHE_COMPLETION_MARKER), "utf8")
|
|
18534
18701
|
);
|
|
18535
|
-
|
|
18702
|
+
fs17.cpSync(stagingDir, entryDir, {
|
|
18536
18703
|
recursive: true,
|
|
18537
18704
|
preserveTimestamps: false,
|
|
18538
|
-
mode:
|
|
18539
|
-
filter: (source) =>
|
|
18705
|
+
mode: fs17.constants.COPYFILE_EXCL,
|
|
18706
|
+
filter: (source) => path18.basename(source) !== CACHE_COMPLETION_MARKER
|
|
18540
18707
|
});
|
|
18541
18708
|
writeCompletionMarker(entryDir, {
|
|
18542
18709
|
name: stagedMarker.name,
|
|
18543
18710
|
version: stagedMarker.version
|
|
18544
18711
|
});
|
|
18545
|
-
|
|
18712
|
+
fs17.rmSync(stagingDir, { recursive: true, force: true });
|
|
18546
18713
|
return;
|
|
18547
18714
|
}
|
|
18548
|
-
|
|
18715
|
+
fs17.rmSync(stagingDir, { recursive: true, force: true });
|
|
18549
18716
|
throw error;
|
|
18550
18717
|
}
|
|
18551
18718
|
}
|
|
@@ -18553,12 +18720,12 @@ function isReservedCacheRootName(name) {
|
|
|
18553
18720
|
return name.startsWith(".");
|
|
18554
18721
|
}
|
|
18555
18722
|
function listCacheEntryDirectories(cacheRoot) {
|
|
18556
|
-
if (!
|
|
18723
|
+
if (!fs17.existsSync(cacheRoot)) {
|
|
18557
18724
|
return [];
|
|
18558
18725
|
}
|
|
18559
|
-
return
|
|
18726
|
+
return fs17.readdirSync(cacheRoot, { withFileTypes: true }).filter(
|
|
18560
18727
|
(entry) => entry.isDirectory() && !isReservedCacheRootName(entry.name)
|
|
18561
|
-
).map((entry) =>
|
|
18728
|
+
).map((entry) => path18.join(cacheRoot, entry.name));
|
|
18562
18729
|
}
|
|
18563
18730
|
function resolveCacheClearTarget(cacheRoot, raw) {
|
|
18564
18731
|
if (raw.includes("@")) {
|
|
@@ -18576,10 +18743,10 @@ function resolveCacheClearTarget(cacheRoot, raw) {
|
|
|
18576
18743
|
`Cache clear target "${raw}" must not begin with "." \u2014 reserved cache-root filenames are excluded from removal by name, not only from the no-argument enumeration form.`
|
|
18577
18744
|
);
|
|
18578
18745
|
}
|
|
18579
|
-
const resolvedRoot =
|
|
18580
|
-
const target =
|
|
18581
|
-
const resolvedTarget =
|
|
18582
|
-
if (!resolvedTarget.startsWith(resolvedRoot +
|
|
18746
|
+
const resolvedRoot = path18.resolve(cacheRoot);
|
|
18747
|
+
const target = path18.join(cacheRoot, raw);
|
|
18748
|
+
const resolvedTarget = path18.resolve(target);
|
|
18749
|
+
if (!resolvedTarget.startsWith(resolvedRoot + path18.sep)) {
|
|
18583
18750
|
throw new IntegrityError(
|
|
18584
18751
|
`Cache clear target "${raw}" resolves outside the cache root \u2014 refusing to remove.`
|
|
18585
18752
|
);
|
|
@@ -18591,7 +18758,7 @@ function resolveCacheClearTarget(cacheRoot, raw) {
|
|
|
18591
18758
|
async function runCacheClearCommand(options, logger) {
|
|
18592
18759
|
const cacheRoot = resolveCacheRoot();
|
|
18593
18760
|
const targets = options.target === void 0 ? listCacheEntryDirectories(cacheRoot) : [resolveCacheClearTarget(cacheRoot, options.target)];
|
|
18594
|
-
const existing = targets.filter((target) =>
|
|
18761
|
+
const existing = targets.filter((target) => fs18.existsSync(target));
|
|
18595
18762
|
if (existing.length === 0) {
|
|
18596
18763
|
if (options.target === void 0) {
|
|
18597
18764
|
logger.info("Cache is already empty. Nothing to remove.");
|
|
@@ -18610,7 +18777,7 @@ async function runCacheClearCommand(options, logger) {
|
|
|
18610
18777
|
return;
|
|
18611
18778
|
}
|
|
18612
18779
|
if (!options.yes) {
|
|
18613
|
-
const label = options.target ?? existing.map((target) =>
|
|
18780
|
+
const label = options.target ?? existing.map((target) => path19.basename(target)).join(", ");
|
|
18614
18781
|
const proceed = await dist_default5({
|
|
18615
18782
|
message: `Remove ${existing.length} cached ${existing.length === 1 ? "entry" : "entries"} (${label})?`
|
|
18616
18783
|
});
|
|
@@ -18620,7 +18787,7 @@ async function runCacheClearCommand(options, logger) {
|
|
|
18620
18787
|
}
|
|
18621
18788
|
}
|
|
18622
18789
|
for (const target of existing) {
|
|
18623
|
-
|
|
18790
|
+
fs18.rmSync(target, { recursive: true, force: true });
|
|
18624
18791
|
logger.info(`Removed ${target}`);
|
|
18625
18792
|
}
|
|
18626
18793
|
logger.info(
|
|
@@ -18679,14 +18846,14 @@ var hs = new RegExp(pe, "g");
|
|
|
18679
18846
|
var as = /\\\\/g;
|
|
18680
18847
|
var ls = /\\{/g;
|
|
18681
18848
|
var cs = /\\}/g;
|
|
18682
|
-
var
|
|
18849
|
+
var fs19 = /\\,/g;
|
|
18683
18850
|
var us = /\\./g;
|
|
18684
18851
|
var ds = 1e5;
|
|
18685
18852
|
function Ht(n7) {
|
|
18686
18853
|
return isNaN(n7) ? n7.charCodeAt(0) : parseInt(n7, 10);
|
|
18687
18854
|
}
|
|
18688
18855
|
function ps(n7) {
|
|
18689
|
-
return n7.replace(as, fe).replace(ls, ue).replace(cs, qt).replace(
|
|
18856
|
+
return n7.replace(as, fe).replace(ls, ue).replace(cs, qt).replace(fs19, de).replace(us, pe);
|
|
18690
18857
|
}
|
|
18691
18858
|
function ms(n7) {
|
|
18692
18859
|
return n7.replace(is, "\\").replace(rs, "{").replace(ns, "}").replace(os4, ",").replace(hs, ".");
|
|
@@ -21617,8 +21784,8 @@ var Ze = Object.assign(Je, { glob: Je, globSync: ts, sync: Ui, globStream: Qe, s
|
|
|
21617
21784
|
Ze.glob = Ze;
|
|
21618
21785
|
|
|
21619
21786
|
// src/core/ownership.ts
|
|
21620
|
-
import
|
|
21621
|
-
import
|
|
21787
|
+
import fs20 from "fs";
|
|
21788
|
+
import path20 from "path";
|
|
21622
21789
|
var KNOWN_COMPONENTS = /* @__PURE__ */ new Set([
|
|
21623
21790
|
"agents",
|
|
21624
21791
|
"skills",
|
|
@@ -21633,8 +21800,8 @@ var LEGACY_SOURCE_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
|
21633
21800
|
"operational-machinery"
|
|
21634
21801
|
]);
|
|
21635
21802
|
function classifyArtifact(artifactPath, config, sourceRoot) {
|
|
21636
|
-
const resolvedArtifactPath =
|
|
21637
|
-
if (!
|
|
21803
|
+
const resolvedArtifactPath = path20.resolve(artifactPath);
|
|
21804
|
+
if (!fs20.existsSync(resolvedArtifactPath) && !isBrokenSymlink(resolvedArtifactPath)) {
|
|
21638
21805
|
return "missing";
|
|
21639
21806
|
}
|
|
21640
21807
|
if (isOurSymlink(resolvedArtifactPath, sourceRoot)) {
|
|
@@ -21654,42 +21821,42 @@ function classifyArtifact(artifactPath, config, sourceRoot) {
|
|
|
21654
21821
|
}
|
|
21655
21822
|
function isOurSymlink(linkPath, machineryRoot) {
|
|
21656
21823
|
try {
|
|
21657
|
-
const linkTarget =
|
|
21658
|
-
const absoluteTarget =
|
|
21659
|
-
const relative =
|
|
21660
|
-
return !relative.startsWith("..") && !
|
|
21824
|
+
const linkTarget = fs20.readlinkSync(linkPath);
|
|
21825
|
+
const absoluteTarget = path20.resolve(path20.dirname(linkPath), linkTarget);
|
|
21826
|
+
const relative = path20.relative(machineryRoot, absoluteTarget);
|
|
21827
|
+
return !relative.startsWith("..") && !path20.isAbsolute(relative);
|
|
21661
21828
|
} catch {
|
|
21662
21829
|
return false;
|
|
21663
21830
|
}
|
|
21664
21831
|
}
|
|
21665
21832
|
function isOurStaleSymlink(linkPath, managedPaths, config) {
|
|
21666
|
-
const resolvedLinkPath =
|
|
21833
|
+
const resolvedLinkPath = path20.resolve(linkPath);
|
|
21667
21834
|
if (!managedPaths.has(resolvedLinkPath)) {
|
|
21668
21835
|
return false;
|
|
21669
21836
|
}
|
|
21670
21837
|
try {
|
|
21671
|
-
const linkTarget =
|
|
21672
|
-
const absoluteTarget =
|
|
21673
|
-
|
|
21838
|
+
const linkTarget = fs20.readlinkSync(resolvedLinkPath);
|
|
21839
|
+
const absoluteTarget = path20.resolve(
|
|
21840
|
+
path20.dirname(resolvedLinkPath),
|
|
21674
21841
|
linkTarget
|
|
21675
21842
|
);
|
|
21676
21843
|
let isBroken = false;
|
|
21677
21844
|
try {
|
|
21678
|
-
|
|
21845
|
+
fs20.realpathSync(resolvedLinkPath);
|
|
21679
21846
|
} catch {
|
|
21680
21847
|
isBroken = true;
|
|
21681
21848
|
}
|
|
21682
21849
|
const knownFiles = new Set(
|
|
21683
21850
|
Object.values(config.source).map(
|
|
21684
|
-
(sourcePath) =>
|
|
21851
|
+
(sourcePath) => path20.basename(sourcePath)
|
|
21685
21852
|
)
|
|
21686
21853
|
);
|
|
21687
|
-
const lastSegment =
|
|
21688
|
-
const parentSegment =
|
|
21854
|
+
const lastSegment = path20.basename(linkTarget);
|
|
21855
|
+
const parentSegment = path20.basename(path20.dirname(linkTarget));
|
|
21689
21856
|
if (isBroken) {
|
|
21690
21857
|
return KNOWN_COMPONENTS.has(lastSegment) || KNOWN_COMPONENTS.has(parentSegment) || KNOWN_INSTRUCTION_FILES.has(lastSegment) || knownFiles.has(lastSegment);
|
|
21691
21858
|
}
|
|
21692
|
-
const targetSegments = absoluteTarget.split(
|
|
21859
|
+
const targetSegments = absoluteTarget.split(path20.sep);
|
|
21693
21860
|
const traversesLegacyRoot = targetSegments.some(
|
|
21694
21861
|
(segment) => LEGACY_SOURCE_DIRECTORIES.has(segment)
|
|
21695
21862
|
);
|
|
@@ -21703,12 +21870,12 @@ function isOurStaleSymlink(linkPath, managedPaths, config) {
|
|
|
21703
21870
|
}
|
|
21704
21871
|
function isBrokenSymlink(filePath) {
|
|
21705
21872
|
try {
|
|
21706
|
-
|
|
21873
|
+
fs20.lstatSync(filePath);
|
|
21707
21874
|
} catch {
|
|
21708
21875
|
return false;
|
|
21709
21876
|
}
|
|
21710
21877
|
try {
|
|
21711
|
-
|
|
21878
|
+
fs20.realpathSync(filePath);
|
|
21712
21879
|
return false;
|
|
21713
21880
|
} catch {
|
|
21714
21881
|
return true;
|
|
@@ -21716,26 +21883,26 @@ function isBrokenSymlink(filePath) {
|
|
|
21716
21883
|
}
|
|
21717
21884
|
function isManagedCompiledFile(filePath) {
|
|
21718
21885
|
try {
|
|
21719
|
-
const stat =
|
|
21886
|
+
const stat = fs20.lstatSync(filePath);
|
|
21720
21887
|
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
21721
21888
|
return false;
|
|
21722
21889
|
}
|
|
21723
|
-
return extractProvenanceMarker(
|
|
21890
|
+
return extractProvenanceMarker(fs20.readFileSync(filePath, "utf8")) !== null;
|
|
21724
21891
|
} catch {
|
|
21725
21892
|
return false;
|
|
21726
21893
|
}
|
|
21727
21894
|
}
|
|
21728
21895
|
|
|
21729
21896
|
// src/core/merge.ts
|
|
21730
|
-
import
|
|
21731
|
-
import
|
|
21897
|
+
import fs21 from "fs";
|
|
21898
|
+
import path21 from "path";
|
|
21732
21899
|
function readSharedFile(filePath, parser) {
|
|
21733
|
-
if (!
|
|
21900
|
+
if (!fs21.existsSync(filePath)) {
|
|
21734
21901
|
return { parsed: parser(""), unparseable: false };
|
|
21735
21902
|
}
|
|
21736
21903
|
try {
|
|
21737
21904
|
return {
|
|
21738
|
-
parsed: parser(
|
|
21905
|
+
parsed: parser(fs21.readFileSync(filePath, "utf8")),
|
|
21739
21906
|
unparseable: false
|
|
21740
21907
|
};
|
|
21741
21908
|
} catch {
|
|
@@ -21744,13 +21911,13 @@ function readSharedFile(filePath, parser) {
|
|
|
21744
21911
|
}
|
|
21745
21912
|
function writeSharedFile(filePath, parsed, serializer, logger) {
|
|
21746
21913
|
const serialized = serializer(parsed);
|
|
21747
|
-
if (
|
|
21914
|
+
if (fs21.existsSync(filePath) && fs21.readFileSync(filePath, "utf8") === serialized) {
|
|
21748
21915
|
return false;
|
|
21749
21916
|
}
|
|
21750
21917
|
let realTarget = null;
|
|
21751
21918
|
try {
|
|
21752
|
-
if (
|
|
21753
|
-
realTarget =
|
|
21919
|
+
if (fs21.lstatSync(filePath).isSymbolicLink()) {
|
|
21920
|
+
realTarget = fs21.realpathSync(filePath);
|
|
21754
21921
|
}
|
|
21755
21922
|
} catch {
|
|
21756
21923
|
realTarget = null;
|
|
@@ -21760,12 +21927,12 @@ function writeSharedFile(filePath, parsed, serializer, logger) {
|
|
|
21760
21927
|
`tangyr: ${filePath} is a symlink \u2014 the file being modified is ${realTarget}`
|
|
21761
21928
|
);
|
|
21762
21929
|
}
|
|
21763
|
-
|
|
21764
|
-
|
|
21930
|
+
fs21.mkdirSync(path21.dirname(filePath), { recursive: true });
|
|
21931
|
+
fs21.writeFileSync(filePath, serialized);
|
|
21765
21932
|
return true;
|
|
21766
21933
|
}
|
|
21767
21934
|
function removeManagedEntries(filePath, parser, serializer, removeManaged, logger, options) {
|
|
21768
|
-
if (!
|
|
21935
|
+
if (!fs21.existsSync(filePath)) {
|
|
21769
21936
|
return;
|
|
21770
21937
|
}
|
|
21771
21938
|
const readResult = readSharedFile(filePath, parser);
|
|
@@ -21777,98 +21944,16 @@ function removeManagedEntries(filePath, parser, serializer, removeManaged, logge
|
|
|
21777
21944
|
}
|
|
21778
21945
|
const cleaned = removeManaged(readResult.parsed);
|
|
21779
21946
|
if (options?.removeFileWhen?.(readResult.parsed, cleaned)) {
|
|
21780
|
-
|
|
21947
|
+
fs21.rmSync(filePath, { force: true });
|
|
21781
21948
|
return;
|
|
21782
21949
|
}
|
|
21783
|
-
|
|
21950
|
+
fs21.writeFileSync(filePath, serializer(cleaned));
|
|
21784
21951
|
}
|
|
21785
21952
|
|
|
21786
21953
|
// src/commands/uninstall.ts
|
|
21787
21954
|
import fs29 from "fs";
|
|
21788
21955
|
import path29 from "path";
|
|
21789
21956
|
|
|
21790
|
-
// src/core/managed-sources.ts
|
|
21791
|
-
var import_yaml5 = __toESM(require_dist(), 1);
|
|
21792
|
-
import fs21 from "fs";
|
|
21793
|
-
import path21 from "path";
|
|
21794
|
-
function resolveKitComponentNames(sourceRoot, category) {
|
|
21795
|
-
const manifestPath = path21.resolve(sourceRoot, "tangyr-kit.yaml");
|
|
21796
|
-
if (!fs21.existsSync(manifestPath)) {
|
|
21797
|
-
return void 0;
|
|
21798
|
-
}
|
|
21799
|
-
try {
|
|
21800
|
-
const raw = fs21.readFileSync(manifestPath, "utf8");
|
|
21801
|
-
const doc = (0, import_yaml5.parse)(raw);
|
|
21802
|
-
if (doc && typeof doc === "object" && !Array.isArray(doc) && "components" in doc) {
|
|
21803
|
-
const components = doc.components;
|
|
21804
|
-
if (components && typeof components === "object" && !Array.isArray(components) && category in components) {
|
|
21805
|
-
const names = components[category];
|
|
21806
|
-
if (Array.isArray(names) && names.every((n7) => typeof n7 === "string")) {
|
|
21807
|
-
return names;
|
|
21808
|
-
}
|
|
21809
|
-
}
|
|
21810
|
-
}
|
|
21811
|
-
} catch {
|
|
21812
|
-
}
|
|
21813
|
-
return void 0;
|
|
21814
|
-
}
|
|
21815
|
-
function resolveKitHookNames(sourceRoot) {
|
|
21816
|
-
return resolveKitComponentNames(sourceRoot, "hooks");
|
|
21817
|
-
}
|
|
21818
|
-
function resolveKitSkillNames(sourceRoot) {
|
|
21819
|
-
return resolveKitComponentNames(sourceRoot, "skills");
|
|
21820
|
-
}
|
|
21821
|
-
function resolveKitEntrypointName(sourceRoot) {
|
|
21822
|
-
const manifestPath = path21.resolve(sourceRoot, "tangyr-kit.yaml");
|
|
21823
|
-
if (!fs21.existsSync(manifestPath)) {
|
|
21824
|
-
return void 0;
|
|
21825
|
-
}
|
|
21826
|
-
try {
|
|
21827
|
-
const doc = (0, import_yaml5.parse)(fs21.readFileSync(manifestPath, "utf8"));
|
|
21828
|
-
if (doc && typeof doc === "object" && !Array.isArray(doc)) {
|
|
21829
|
-
const value = doc.entrypoint;
|
|
21830
|
-
if (typeof value === "string" && value.trim().length > 0) {
|
|
21831
|
-
return value.trim();
|
|
21832
|
-
}
|
|
21833
|
-
}
|
|
21834
|
-
} catch {
|
|
21835
|
-
}
|
|
21836
|
-
return void 0;
|
|
21837
|
-
}
|
|
21838
|
-
function resolveHooksSourceFile(sourceRoot, config) {
|
|
21839
|
-
return path21.resolve(sourceRoot, config.source.hooks, "hooks.json");
|
|
21840
|
-
}
|
|
21841
|
-
function resolveHooksSourceDir(sourceRoot, config) {
|
|
21842
|
-
return path21.resolve(sourceRoot, config.source.hooks);
|
|
21843
|
-
}
|
|
21844
|
-
function hooksSourceExists(sourceRoot, config) {
|
|
21845
|
-
const hooksJsonPath = resolveHooksSourceFile(sourceRoot, config);
|
|
21846
|
-
if (fs21.existsSync(hooksJsonPath)) {
|
|
21847
|
-
return true;
|
|
21848
|
-
}
|
|
21849
|
-
const hooksDir = resolveHooksSourceDir(sourceRoot, config);
|
|
21850
|
-
if (!fs21.existsSync(hooksDir) || !fs21.statSync(hooksDir).isDirectory()) {
|
|
21851
|
-
return false;
|
|
21852
|
-
}
|
|
21853
|
-
return fs21.readdirSync(hooksDir).some((f) => f.endsWith(".md") && !f.startsWith("."));
|
|
21854
|
-
}
|
|
21855
|
-
function hooksSourceLabel(sourceRoot, config) {
|
|
21856
|
-
const dir = normalizeManagedSourcePath(
|
|
21857
|
-
config.source.hooks.replace(/\\/gu, "/")
|
|
21858
|
-
);
|
|
21859
|
-
return fs21.existsSync(resolveHooksSourceFile(sourceRoot, config)) ? path21.posix.join(dir, "hooks.json") : `${dir}/`;
|
|
21860
|
-
}
|
|
21861
|
-
function resolveMcpSourceFile(sourceRoot, config) {
|
|
21862
|
-
return path21.resolve(sourceRoot, config.source.mcp);
|
|
21863
|
-
}
|
|
21864
|
-
function mcpSourceLabel(config) {
|
|
21865
|
-
return normalizeManagedSourcePath(config.source.mcp);
|
|
21866
|
-
}
|
|
21867
|
-
function normalizeManagedSourcePath(rawPath) {
|
|
21868
|
-
const normalized = rawPath.replace(/\\/gu, "/");
|
|
21869
|
-
return normalized.startsWith("./") ? normalized.slice(2) : normalized;
|
|
21870
|
-
}
|
|
21871
|
-
|
|
21872
21957
|
// src/compiler/hook-components.ts
|
|
21873
21958
|
import fs23 from "fs";
|
|
21874
21959
|
import path23 from "path";
|
|
@@ -24916,12 +25001,26 @@ function restoreBackup(backup, logger) {
|
|
|
24916
25001
|
});
|
|
24917
25002
|
fs29.rmSync(backup.backupLocation, { recursive: true, force: true });
|
|
24918
25003
|
} else {
|
|
25004
|
+
if (isEmptyDirectory(backup.originalPath)) {
|
|
25005
|
+
fs29.rmdirSync(backup.originalPath);
|
|
25006
|
+
}
|
|
24919
25007
|
fs29.renameSync(backup.backupLocation, backup.originalPath);
|
|
24920
25008
|
}
|
|
24921
25009
|
logger.verbose(
|
|
24922
25010
|
` restored: ${backup.backupLocation} \u2192 ${backup.originalPath}`
|
|
24923
25011
|
);
|
|
24924
25012
|
}
|
|
25013
|
+
function isEmptyDirectory(candidate) {
|
|
25014
|
+
try {
|
|
25015
|
+
const stat = fs29.lstatSync(candidate);
|
|
25016
|
+
if (!stat.isDirectory()) {
|
|
25017
|
+
return false;
|
|
25018
|
+
}
|
|
25019
|
+
return fs29.readdirSync(candidate).length === 0;
|
|
25020
|
+
} catch {
|
|
25021
|
+
return false;
|
|
25022
|
+
}
|
|
25023
|
+
}
|
|
24925
25024
|
function isSymlink(p) {
|
|
24926
25025
|
try {
|
|
24927
25026
|
return fs29.lstatSync(p).isSymbolicLink();
|
|
@@ -27173,9 +27272,10 @@ function buildAgentsMdShim(_shimPath, _agentsMdPath, target) {
|
|
|
27173
27272
|
${SHIM_BODY}`;
|
|
27174
27273
|
}
|
|
27175
27274
|
|
|
27176
|
-
// src/core/
|
|
27275
|
+
// src/core/linked-slot.ts
|
|
27177
27276
|
import fs37 from "fs";
|
|
27178
27277
|
import path37 from "path";
|
|
27278
|
+
var SKILL_ENTRY = { component: "skills", kind: "dir" };
|
|
27179
27279
|
function isForeignSkillsSlotSymlink(destination, config, sourceRoot, source) {
|
|
27180
27280
|
if (!isSymlinkPath(destination)) {
|
|
27181
27281
|
return false;
|
|
@@ -27188,16 +27288,17 @@ function isForeignSkillsSlotSymlink(destination, config, sourceRoot, source) {
|
|
|
27188
27288
|
}
|
|
27189
27289
|
function syncSkillsSlot(sync) {
|
|
27190
27290
|
const { source, destination, logger } = sync;
|
|
27291
|
+
const entry = sync.entry ?? SKILL_ENTRY;
|
|
27191
27292
|
if (!fs37.existsSync(source)) {
|
|
27192
27293
|
return [
|
|
27193
27294
|
{
|
|
27194
|
-
component:
|
|
27295
|
+
component: entry.component,
|
|
27195
27296
|
status: "skipped",
|
|
27196
27297
|
path: `${source}: source not configured`
|
|
27197
27298
|
}
|
|
27198
27299
|
];
|
|
27199
27300
|
}
|
|
27200
|
-
const declaredNames = resolveKitSkillNames(sync.sourceRoot);
|
|
27301
|
+
const declaredNames = sync.declared ?? (entry.component === "skills" ? resolveKitSkillNames(sync.sourceRoot) : void 0);
|
|
27201
27302
|
const foreignSlotSymlink = isForeignSkillsSlotSymlink(
|
|
27202
27303
|
destination,
|
|
27203
27304
|
sync.config,
|
|
@@ -27208,56 +27309,103 @@ function syncSkillsSlot(sync) {
|
|
|
27208
27309
|
if (sync.dryRun) {
|
|
27209
27310
|
if (foreignSlotSymlink) {
|
|
27210
27311
|
logger.info(
|
|
27211
|
-
`[dry-run]
|
|
27312
|
+
`[dry-run] ${entry.component}: ${destination} is a symlink Tangyr did not create \u2014 unmanaged conflict, slot left alone`
|
|
27212
27313
|
);
|
|
27213
|
-
return [
|
|
27314
|
+
return [
|
|
27315
|
+
{ component: entry.component, status: "conflict", path: destination }
|
|
27316
|
+
];
|
|
27214
27317
|
}
|
|
27215
27318
|
const outcomes2 = [];
|
|
27216
27319
|
if (isLegacyWholesaleSymlink) {
|
|
27217
|
-
for (const name of foreignSkillNames(source, declaredNames)) {
|
|
27320
|
+
for (const name of foreignSkillNames(source, declaredNames, entry)) {
|
|
27321
|
+
const file = entryFileName(name, entry);
|
|
27218
27322
|
logger.info(
|
|
27219
|
-
`[dry-run]
|
|
27323
|
+
`[dry-run] ${entry.component}: migrate undeclared ${path37.join(source, file)} -> ${path37.join(destination, file)}`
|
|
27220
27324
|
);
|
|
27221
27325
|
}
|
|
27222
27326
|
logger.info(
|
|
27223
|
-
`[dry-run]
|
|
27327
|
+
`[dry-run] ${entry.component}: replace wholesale symlink with real directory ${destination}`
|
|
27224
27328
|
);
|
|
27225
27329
|
}
|
|
27226
|
-
for (const name of declaredNames ??
|
|
27227
|
-
const
|
|
27330
|
+
for (const name of declaredNames ?? listEntryNames(source, entry)) {
|
|
27331
|
+
const file = entryFileName(name, entry);
|
|
27332
|
+
const entryDestination = path37.join(destination, file);
|
|
27228
27333
|
logger.info(
|
|
27229
|
-
`[dry-run]
|
|
27334
|
+
`[dry-run] ${entry.component}: symlink ${path37.join(source, file)} -> ${entryDestination}`
|
|
27230
27335
|
);
|
|
27231
27336
|
outcomes2.push({
|
|
27232
|
-
component:
|
|
27337
|
+
component: entry.component,
|
|
27233
27338
|
status: "dry-run",
|
|
27234
|
-
path:
|
|
27339
|
+
path: entryDestination
|
|
27235
27340
|
});
|
|
27236
27341
|
}
|
|
27237
27342
|
return outcomes2;
|
|
27238
27343
|
}
|
|
27239
27344
|
if (foreignSlotSymlink) {
|
|
27240
27345
|
if (!sync.onUnmanagedConflict(destination) || isSymlinkPath(destination)) {
|
|
27241
|
-
return [
|
|
27346
|
+
return [
|
|
27347
|
+
{ component: entry.component, status: "conflict", path: destination }
|
|
27348
|
+
];
|
|
27242
27349
|
}
|
|
27243
27350
|
}
|
|
27244
27351
|
if (isLegacyWholesaleSymlink) {
|
|
27245
|
-
migrateWholesaleSkillsSymlink(
|
|
27352
|
+
migrateWholesaleSkillsSymlink(
|
|
27353
|
+
source,
|
|
27354
|
+
destination,
|
|
27355
|
+
declaredNames,
|
|
27356
|
+
entry,
|
|
27357
|
+
logger
|
|
27358
|
+
);
|
|
27246
27359
|
}
|
|
27247
27360
|
ensureDir(destination);
|
|
27248
27361
|
const outcomes = [];
|
|
27249
|
-
for (const name of declaredNames ??
|
|
27250
|
-
outcomes.push(syncSingleSkill(sync, name));
|
|
27362
|
+
for (const name of declaredNames ?? listEntryNames(source, entry)) {
|
|
27363
|
+
outcomes.push(syncSingleSkill(sync, name, entry));
|
|
27251
27364
|
}
|
|
27365
|
+
pruneUndeclaredLinks(source, destination, declaredNames, entry, logger);
|
|
27252
27366
|
return outcomes;
|
|
27253
27367
|
}
|
|
27254
|
-
function
|
|
27368
|
+
function pruneUndeclaredLinks(source, destination, declaredNames, entry, logger) {
|
|
27369
|
+
if (!declaredNames) {
|
|
27370
|
+
return;
|
|
27371
|
+
}
|
|
27372
|
+
const declared = new Set(
|
|
27373
|
+
declaredNames.map((name) => entryFileName(name, entry))
|
|
27374
|
+
);
|
|
27375
|
+
let present;
|
|
27376
|
+
try {
|
|
27377
|
+
present = fs37.readdirSync(destination, { withFileTypes: true });
|
|
27378
|
+
} catch {
|
|
27379
|
+
return;
|
|
27380
|
+
}
|
|
27381
|
+
for (const found2 of present) {
|
|
27382
|
+
if (!found2.isSymbolicLink() || declared.has(found2.name)) {
|
|
27383
|
+
continue;
|
|
27384
|
+
}
|
|
27385
|
+
const link = path37.join(destination, found2.name);
|
|
27386
|
+
let target;
|
|
27387
|
+
try {
|
|
27388
|
+
target = path37.resolve(destination, fs37.readlinkSync(link));
|
|
27389
|
+
} catch {
|
|
27390
|
+
continue;
|
|
27391
|
+
}
|
|
27392
|
+
if (path37.dirname(target) !== path37.resolve(source)) {
|
|
27393
|
+
continue;
|
|
27394
|
+
}
|
|
27395
|
+
fs37.unlinkSync(link);
|
|
27396
|
+
logger.verbose(
|
|
27397
|
+
` ${entry.component}: removed ${link} \u2014 the kit no longer declares it`
|
|
27398
|
+
);
|
|
27399
|
+
}
|
|
27400
|
+
}
|
|
27401
|
+
function syncSingleSkill(sync, name, entry) {
|
|
27255
27402
|
const { config, sourceRoot, source, destination } = sync;
|
|
27256
|
-
const
|
|
27257
|
-
const
|
|
27403
|
+
const file = entryFileName(name, entry);
|
|
27404
|
+
const skillSource = path37.join(source, file);
|
|
27405
|
+
const skillDestination = path37.join(destination, file);
|
|
27258
27406
|
if (!fs37.existsSync(skillSource)) {
|
|
27259
27407
|
return {
|
|
27260
|
-
component:
|
|
27408
|
+
component: entry.component,
|
|
27261
27409
|
status: "skipped",
|
|
27262
27410
|
path: `${skillSource}: source not configured`
|
|
27263
27411
|
};
|
|
@@ -27265,7 +27413,7 @@ function syncSingleSkill(sync, name) {
|
|
|
27265
27413
|
const artifactClass = classifyArtifact(skillDestination, config, sourceRoot);
|
|
27266
27414
|
if (artifactClass === "managed-symlink" && isSymlinkTo2(skillDestination, skillSource)) {
|
|
27267
27415
|
return {
|
|
27268
|
-
component:
|
|
27416
|
+
component: entry.component,
|
|
27269
27417
|
status: "skipped-current",
|
|
27270
27418
|
path: skillDestination
|
|
27271
27419
|
};
|
|
@@ -27273,44 +27421,63 @@ function syncSingleSkill(sync, name) {
|
|
|
27273
27421
|
if (artifactClass === "managed-stale" && isOurStaleSymlink(skillDestination, /* @__PURE__ */ new Set([skillDestination]), config)) {
|
|
27274
27422
|
fs37.unlinkSync(skillDestination);
|
|
27275
27423
|
} else if (artifactClass === "unmanaged-conflict" && !sync.onUnmanagedConflict(skillDestination)) {
|
|
27276
|
-
return {
|
|
27424
|
+
return {
|
|
27425
|
+
component: entry.component,
|
|
27426
|
+
status: "conflict",
|
|
27427
|
+
path: skillDestination
|
|
27428
|
+
};
|
|
27277
27429
|
} else if (artifactClass === "managed-symlink") {
|
|
27278
27430
|
fs37.unlinkSync(skillDestination);
|
|
27279
27431
|
}
|
|
27280
|
-
createRelativeSymlink(skillSource, skillDestination,
|
|
27281
|
-
return {
|
|
27432
|
+
createRelativeSymlink(skillSource, skillDestination, entry.kind);
|
|
27433
|
+
return {
|
|
27434
|
+
component: entry.component,
|
|
27435
|
+
status: "success",
|
|
27436
|
+
path: skillDestination
|
|
27437
|
+
};
|
|
27282
27438
|
}
|
|
27283
|
-
function migrateWholesaleSkillsSymlink(source, destination, declaredNames, logger) {
|
|
27284
|
-
const foreignNames = foreignSkillNames(source, declaredNames);
|
|
27439
|
+
function migrateWholesaleSkillsSymlink(source, destination, declaredNames, entry, logger) {
|
|
27440
|
+
const foreignNames = foreignSkillNames(source, declaredNames, entry);
|
|
27285
27441
|
fs37.unlinkSync(destination);
|
|
27286
27442
|
ensureDir(destination);
|
|
27287
27443
|
for (const name of foreignNames) {
|
|
27288
|
-
const
|
|
27289
|
-
const
|
|
27444
|
+
const file = entryFileName(name, entry);
|
|
27445
|
+
const from = path37.join(source, file);
|
|
27446
|
+
const to = path37.join(destination, file);
|
|
27290
27447
|
if (fs37.existsSync(to)) {
|
|
27291
27448
|
logger.warn(
|
|
27292
|
-
|
|
27449
|
+
`${entry.component} migration: ${to} already exists \u2014 skipping ${from} to avoid overwrite. Nothing in the kit was changed.`
|
|
27293
27450
|
);
|
|
27294
27451
|
continue;
|
|
27295
27452
|
}
|
|
27296
27453
|
fs37.cpSync(from, to, { recursive: true, verbatimSymlinks: true });
|
|
27297
27454
|
logger.warn(
|
|
27298
|
-
|
|
27455
|
+
`${entry.component} migration: '${name}' is present in the kit's ${entry.component}/ but is not declared in its manifest. Copied ${from} -> ${to} so the harness can read it. The original is left in the kit deliberately: this command does not modify a kit. Remove ${from} yourself if it does not belong there, or declare it in tangyr-kit.yaml if it does.`
|
|
27299
27456
|
);
|
|
27300
27457
|
}
|
|
27301
27458
|
}
|
|
27302
|
-
function foreignSkillNames(source, declaredNames) {
|
|
27459
|
+
function foreignSkillNames(source, declaredNames, entry) {
|
|
27303
27460
|
if (!declaredNames) {
|
|
27304
27461
|
return [];
|
|
27305
27462
|
}
|
|
27306
27463
|
const declaredSet = new Set(declaredNames);
|
|
27307
|
-
return
|
|
27464
|
+
return listEntryNames(source, entry).filter((name) => !declaredSet.has(name));
|
|
27308
27465
|
}
|
|
27309
|
-
function
|
|
27466
|
+
function listEntryNames(dir, entry) {
|
|
27310
27467
|
if (!fs37.existsSync(dir)) {
|
|
27311
27468
|
return [];
|
|
27312
27469
|
}
|
|
27313
|
-
|
|
27470
|
+
const found2 = fs37.readdirSync(dir, { withFileTypes: true });
|
|
27471
|
+
if (entry.kind === "dir") {
|
|
27472
|
+
return found2.filter((one) => one.isDirectory() && !one.name.startsWith(".")).map((one) => one.name);
|
|
27473
|
+
}
|
|
27474
|
+
const extension = entry.extension ?? "";
|
|
27475
|
+
return found2.filter(
|
|
27476
|
+
(one) => one.isFile() && !one.name.startsWith(".") && one.name.endsWith(extension)
|
|
27477
|
+
).map((one) => one.name.slice(0, one.name.length - extension.length));
|
|
27478
|
+
}
|
|
27479
|
+
function entryFileName(name, entry) {
|
|
27480
|
+
return entry.kind === "dir" ? name : `${name}${entry.extension ?? ""}`;
|
|
27314
27481
|
}
|
|
27315
27482
|
function isSymlinkPath(filePath) {
|
|
27316
27483
|
try {
|
|
@@ -27500,6 +27667,20 @@ function syncClaudeCode(config, sourceRoot, options, logger, mappings, manifest,
|
|
|
27500
27667
|
if (shouldSkipComponent(options, directComponent.component)) {
|
|
27501
27668
|
continue;
|
|
27502
27669
|
}
|
|
27670
|
+
if (directComponent.type === "dir") {
|
|
27671
|
+
outcomes.push(
|
|
27672
|
+
...syncClaudeCodeSlot(
|
|
27673
|
+
config,
|
|
27674
|
+
sourceRoot,
|
|
27675
|
+
options,
|
|
27676
|
+
logger,
|
|
27677
|
+
directComponent,
|
|
27678
|
+
manifest,
|
|
27679
|
+
scopePath
|
|
27680
|
+
)
|
|
27681
|
+
);
|
|
27682
|
+
continue;
|
|
27683
|
+
}
|
|
27503
27684
|
outcomes.push(
|
|
27504
27685
|
syncDirectComponent(
|
|
27505
27686
|
config,
|
|
@@ -27692,6 +27873,52 @@ function applyClaudeCodeShimUpgrade(shimPath, agentsMdPath, manifest, scopePath,
|
|
|
27692
27873
|
recordShimState(manifest, shimPath);
|
|
27693
27874
|
logger?.verbose(`instructions-shim: backed up and replaced -> ${shimPath}`);
|
|
27694
27875
|
}
|
|
27876
|
+
var SLOT_ENTRIES = {
|
|
27877
|
+
agents: {
|
|
27878
|
+
category: "agents",
|
|
27879
|
+
entry: { component: "agents", kind: "file", extension: ".md" }
|
|
27880
|
+
},
|
|
27881
|
+
commands: {
|
|
27882
|
+
category: "commands",
|
|
27883
|
+
entry: { component: "commands", kind: "file", extension: ".md" }
|
|
27884
|
+
},
|
|
27885
|
+
rules: {
|
|
27886
|
+
category: "rules",
|
|
27887
|
+
entry: { component: "rules", kind: "file", extension: ".md" }
|
|
27888
|
+
},
|
|
27889
|
+
"output-styles": {
|
|
27890
|
+
category: null,
|
|
27891
|
+
entry: { component: "output-styles", kind: "file", extension: ".md" }
|
|
27892
|
+
}
|
|
27893
|
+
};
|
|
27894
|
+
function syncClaudeCodeSlot(config, sourceRoot, options, logger, directComponent, manifest, scopePath) {
|
|
27895
|
+
const shape = SLOT_ENTRIES[directComponent.component];
|
|
27896
|
+
const source = path40.resolve(
|
|
27897
|
+
sourceRoot,
|
|
27898
|
+
config.source[directComponent.sourceKey]
|
|
27899
|
+
);
|
|
27900
|
+
if (!shape) {
|
|
27901
|
+
return [skippedMissingSource(directComponent.component, source)];
|
|
27902
|
+
}
|
|
27903
|
+
return syncSkillsSlot({
|
|
27904
|
+
config,
|
|
27905
|
+
sourceRoot,
|
|
27906
|
+
source,
|
|
27907
|
+
destination: directComponent.destination,
|
|
27908
|
+
dryRun: options.dryRun,
|
|
27909
|
+
logger,
|
|
27910
|
+
entry: shape.entry,
|
|
27911
|
+
declared: shape.category === null ? void 0 : resolveKitSlotNames(sourceRoot, shape.category),
|
|
27912
|
+
onUnmanagedConflict: (conflictPath) => handleConflict(
|
|
27913
|
+
conflictPath,
|
|
27914
|
+
config,
|
|
27915
|
+
options,
|
|
27916
|
+
logger,
|
|
27917
|
+
manifest,
|
|
27918
|
+
scopePath
|
|
27919
|
+
)
|
|
27920
|
+
});
|
|
27921
|
+
}
|
|
27695
27922
|
function syncDirectComponent(config, sourceRoot, options, logger, directComponent, manifest, scopePath) {
|
|
27696
27923
|
const source = directComponent.sourceKey === "instructions" ? instructionsSourcePath(sourceRoot, config) : path40.resolve(sourceRoot, config.source[directComponent.sourceKey]);
|
|
27697
27924
|
const sourceLabel = directComponent.sourceKey === "instructions" ? instructionsSourceLabel(sourceRoot, config) : config.source[directComponent.sourceKey];
|
|
@@ -32458,8 +32685,28 @@ async function runInstallCommand(options, logger) {
|
|
|
32458
32685
|
config: options.config,
|
|
32459
32686
|
scope
|
|
32460
32687
|
});
|
|
32688
|
+
const claudeProfileForConflicts = (() => {
|
|
32689
|
+
try {
|
|
32690
|
+
return resolveTargetPaths({
|
|
32691
|
+
scope,
|
|
32692
|
+
projectRoot,
|
|
32693
|
+
mappings: loadMappings(kitInfo.path, config, configDir).platformPaths
|
|
32694
|
+
})["claude-code"];
|
|
32695
|
+
} catch {
|
|
32696
|
+
return void 0;
|
|
32697
|
+
}
|
|
32698
|
+
})();
|
|
32461
32699
|
const skillsSource = path50.resolve(kitInfo.path, config.source.skills);
|
|
32462
|
-
const
|
|
32700
|
+
const perEntrySlots = new Set(
|
|
32701
|
+
[
|
|
32702
|
+
claudeProfileForConflicts?.agents,
|
|
32703
|
+
claudeProfileForConflicts?.commands,
|
|
32704
|
+
claudeProfileForConflicts?.rules,
|
|
32705
|
+
claudeProfileForConflicts?.output_styles,
|
|
32706
|
+
claudeProfileForConflicts?.skills
|
|
32707
|
+
].filter((slot) => typeof slot === "string")
|
|
32708
|
+
);
|
|
32709
|
+
const isPerSkillSkillsSlot = (f) => f.tool === "copilot" && path50.basename(f.path) === "skills" || f.tool === "claude-code" && perEntrySlots.has(f.path);
|
|
32463
32710
|
const foreignSkillsSlots = new Set(
|
|
32464
32711
|
assessResult.findings.filter(
|
|
32465
32712
|
(f) => isPerSkillSkillsSlot(f) && isForeignSkillsSlotSymlink(
|
|
@@ -33038,7 +33285,13 @@ function installClaudeCodeAdapterSlots(args) {
|
|
|
33038
33285
|
{ component: "hooks", slot: "hooks_shared_file" },
|
|
33039
33286
|
{ component: "settings", slot: "settings_shared_file" },
|
|
33040
33287
|
{ component: "mcp", slot: "mcp_shared_file" },
|
|
33041
|
-
{ component: "output-styles", slot: "output_styles" }
|
|
33288
|
+
{ component: "output-styles", slot: "output_styles" },
|
|
33289
|
+
// Filled one entry at a time, so they are the adapter's work and not a
|
|
33290
|
+
// placement's. The slot root is still what `skippedTargetPaths` is asked
|
|
33291
|
+
// about: an operator who declined the whole directory declined all of it.
|
|
33292
|
+
{ component: "agents", slot: "agents" },
|
|
33293
|
+
{ component: "commands", slot: "commands" },
|
|
33294
|
+
{ component: "rules", slot: "rules" }
|
|
33042
33295
|
];
|
|
33043
33296
|
const scopePath = resolveScopePath(
|
|
33044
33297
|
scope,
|
|
@@ -33119,6 +33372,15 @@ function claudeCodeOutcomeToManifestKey(profile, outcome, scope, projectRoot, ma
|
|
|
33119
33372
|
return `claude-code/${slot}`;
|
|
33120
33373
|
}
|
|
33121
33374
|
}
|
|
33375
|
+
for (const [slot, slotPath] of Object.entries(profile)) {
|
|
33376
|
+
if (typeof slotPath !== "string") {
|
|
33377
|
+
continue;
|
|
33378
|
+
}
|
|
33379
|
+
const prefix = `${slotPath}${path50.sep}`;
|
|
33380
|
+
if (outcome.path.startsWith(prefix)) {
|
|
33381
|
+
return `claude-code/${slot}/${outcome.path.slice(prefix.length)}`;
|
|
33382
|
+
}
|
|
33383
|
+
}
|
|
33122
33384
|
return null;
|
|
33123
33385
|
}
|
|
33124
33386
|
function resolveClaudeCodeSkillsDestination(scope, projectRoot, mappings) {
|
|
@@ -33468,6 +33730,19 @@ function syncOutcomeToManifestKey(tool, outcome, mappings, scope = "global", pro
|
|
|
33468
33730
|
if (shared) {
|
|
33469
33731
|
return shared;
|
|
33470
33732
|
}
|
|
33733
|
+
if (tool === "claude-code") {
|
|
33734
|
+
return claudeCodeOutcomeToManifestKey(
|
|
33735
|
+
resolveTargetPaths({
|
|
33736
|
+
scope,
|
|
33737
|
+
projectRoot,
|
|
33738
|
+
mappings: mappings.platformPaths
|
|
33739
|
+
})["claude-code"],
|
|
33740
|
+
outcome,
|
|
33741
|
+
scope,
|
|
33742
|
+
projectRoot,
|
|
33743
|
+
mappings
|
|
33744
|
+
);
|
|
33745
|
+
}
|
|
33471
33746
|
if (tool !== "copilot" && tool !== "codex" && tool !== "opencode" && tool !== "cursor" && tool !== "cline") {
|
|
33472
33747
|
if (isDeferredTarget(tool)) {
|
|
33473
33748
|
throw new Error(
|
|
@@ -33715,23 +33990,6 @@ function getClaudeCodePlacements(kitInfo, config, scope = "global", projectRoot,
|
|
|
33715
33990
|
isDir: false
|
|
33716
33991
|
});
|
|
33717
33992
|
}
|
|
33718
|
-
const componentDirMap = {
|
|
33719
|
-
agents: resolvedPaths.agents,
|
|
33720
|
-
commands: resolvedPaths.commands,
|
|
33721
|
-
rules: resolvedPaths.rules
|
|
33722
|
-
};
|
|
33723
|
-
for (const [component, targetPath] of Object.entries(componentDirMap)) {
|
|
33724
|
-
const componentDir = path50.join(kitInfo.path, component);
|
|
33725
|
-
if (fs47.existsSync(componentDir) && fs47.statSync(componentDir).isDirectory()) {
|
|
33726
|
-
placements.push({
|
|
33727
|
-
source: componentDir,
|
|
33728
|
-
destination: targetPath,
|
|
33729
|
-
manifestKey: `claude-code/${component}`,
|
|
33730
|
-
type: "symlink",
|
|
33731
|
-
isDir: true
|
|
33732
|
-
});
|
|
33733
|
-
}
|
|
33734
|
-
}
|
|
33735
33993
|
return placements;
|
|
33736
33994
|
}
|
|
33737
33995
|
function getClaudeCodePlacementsFromProfile(kitInfo, profile, config) {
|
|
@@ -33746,23 +34004,6 @@ function getClaudeCodePlacementsFromProfile(kitInfo, profile, config) {
|
|
|
33746
34004
|
isDir: false
|
|
33747
34005
|
});
|
|
33748
34006
|
}
|
|
33749
|
-
const componentDirMap = {
|
|
33750
|
-
agents: profile.agents,
|
|
33751
|
-
commands: profile.commands,
|
|
33752
|
-
rules: profile.rules
|
|
33753
|
-
};
|
|
33754
|
-
for (const [component, targetPath] of Object.entries(componentDirMap)) {
|
|
33755
|
-
const componentDir = path50.join(kitInfo.path, component);
|
|
33756
|
-
if (fs47.existsSync(componentDir) && fs47.statSync(componentDir).isDirectory()) {
|
|
33757
|
-
placements.push({
|
|
33758
|
-
source: componentDir,
|
|
33759
|
-
destination: targetPath,
|
|
33760
|
-
manifestKey: `claude-code/${component}`,
|
|
33761
|
-
type: "symlink",
|
|
33762
|
-
isDir: true
|
|
33763
|
-
});
|
|
33764
|
-
}
|
|
33765
|
-
}
|
|
33766
34007
|
return placements;
|
|
33767
34008
|
}
|
|
33768
34009
|
function collectAllFiles(kitInfo, config) {
|
|
@@ -36043,6 +36284,7 @@ function updateManifest(kitInfo, kitSync, written) {
|
|
|
36043
36284
|
writeManifest(kitSync.scopePath, kitSync.manifest);
|
|
36044
36285
|
}
|
|
36045
36286
|
var outcomeRecordableTargets = /* @__PURE__ */ new Set([
|
|
36287
|
+
"claude-code",
|
|
36046
36288
|
"copilot",
|
|
36047
36289
|
"codex",
|
|
36048
36290
|
"opencode",
|