@ramarivera/coding-agent-langfuse 0.1.52 → 0.1.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/dist/backfill.d.ts +2 -1
- package/dist/backfill.js +33 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -63,13 +63,14 @@ There are two config layers:
|
|
|
63
63
|
- Optional project-local overlays: every `.langfuse-ca.json` found while
|
|
64
64
|
walking from the session cwd up to the scanned home directory
|
|
65
65
|
|
|
66
|
-
Global config uses prefix rules:
|
|
66
|
+
Global config uses path-prefix or Git-remote rules:
|
|
67
67
|
|
|
68
68
|
```json
|
|
69
69
|
{
|
|
70
70
|
"rules": [
|
|
71
71
|
{
|
|
72
72
|
"pathPrefix": "/Users/example/dev/acme",
|
|
73
|
+
"gitRemoteIncludes": ["github.com/acme"],
|
|
73
74
|
"tags": ["acme", "client:acme"],
|
|
74
75
|
"metadata": {
|
|
75
76
|
"project_group": "acme",
|
|
@@ -82,6 +83,11 @@ Global config uses prefix rules:
|
|
|
82
83
|
}
|
|
83
84
|
```
|
|
84
85
|
|
|
86
|
+
Use `pathPrefix` for stable checkout roots. Use `gitRemoteIncludes` for
|
|
87
|
+
temporary agent worktrees, where the cwd may live under a random directory such
|
|
88
|
+
as `.codex/worktrees/<id>/repo` but the Git remote still identifies the real
|
|
89
|
+
project.
|
|
90
|
+
|
|
85
91
|
Project-local config is intentionally smaller and overrides/extends the matched
|
|
86
92
|
global rule. Parent overlays are applied before child overlays, so a config at
|
|
87
93
|
`~/work/client-a/.langfuse-ca.json` can tag a whole workstream while nested
|
package/dist/backfill.d.ts
CHANGED
package/dist/backfill.js
CHANGED
|
@@ -196,13 +196,20 @@ function projectMetadata(cwd) {
|
|
|
196
196
|
projectFolder: projectName,
|
|
197
197
|
};
|
|
198
198
|
}
|
|
199
|
-
function matchPathTags(cwd, config, homeDir) {
|
|
200
|
-
if (!cwd)
|
|
199
|
+
function matchPathTags(cwd, config, homeDir, git) {
|
|
200
|
+
if (!cwd && !git?.remoteUrls?.length)
|
|
201
201
|
return { tags: [], metadata: {} };
|
|
202
|
-
const normalizedCwd = normalizeRulePath(cwd);
|
|
202
|
+
const normalizedCwd = cwd ? normalizeRulePath(cwd) : undefined;
|
|
203
|
+
const normalizedRemotes = (git?.remoteUrls ?? []).map((remote) => remote.toLowerCase());
|
|
203
204
|
const matched = config.rules.filter((rule) => {
|
|
204
|
-
const
|
|
205
|
-
|
|
205
|
+
const pathMatch = rule.pathPrefix && normalizedCwd
|
|
206
|
+
? (() => {
|
|
207
|
+
const prefix = normalizeRulePath(rule.pathPrefix);
|
|
208
|
+
return normalizedCwd === prefix || normalizedCwd.startsWith(`${prefix}/`);
|
|
209
|
+
})()
|
|
210
|
+
: false;
|
|
211
|
+
const gitRemoteMatch = (rule.gitRemoteIncludes ?? []).some((needle) => normalizedRemotes.some((remote) => remote.includes(needle.toLowerCase())));
|
|
212
|
+
return pathMatch || gitRemoteMatch;
|
|
206
213
|
});
|
|
207
214
|
const globalMatch = matched.reduce((acc, rule) => ({
|
|
208
215
|
tags: [...new Set([...acc.tags, ...rule.tags])],
|
|
@@ -238,14 +245,15 @@ function matchPathTags(cwd, config, homeDir) {
|
|
|
238
245
|
}
|
|
239
246
|
function mergeProjectMetadata(cwd, config, homeDir) {
|
|
240
247
|
const project = projectMetadata(cwd);
|
|
241
|
-
const
|
|
248
|
+
const git = loadGitMetadata(cwd);
|
|
249
|
+
const pathTags = matchPathTags(cwd, config, homeDir, git);
|
|
242
250
|
return {
|
|
243
251
|
...project,
|
|
244
252
|
projectName: pathTags.projectName ?? project.projectName,
|
|
245
253
|
projectFolder: pathTags.projectFolder ?? project.projectFolder,
|
|
246
254
|
tags: pathTags.tags,
|
|
247
255
|
metadata: pathTags.metadata,
|
|
248
|
-
git
|
|
256
|
+
git,
|
|
249
257
|
};
|
|
250
258
|
}
|
|
251
259
|
function loadGitMetadata(cwd) {
|
|
@@ -263,10 +271,16 @@ function loadGitMetadata(cwd) {
|
|
|
263
271
|
const branch = gitOutput(gitCwd, ["branch", "--show-current"]) ??
|
|
264
272
|
gitOutput(gitCwd, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
265
273
|
const commit = gitOutput(gitCwd, ["rev-parse", "--verify", "HEAD"]);
|
|
274
|
+
const remoteUrls = gitOutput(gitCwd, ["remote", "-v"])
|
|
275
|
+
?.split("\n")
|
|
276
|
+
.map((line) => line.trim().split(/\s+/)[1])
|
|
277
|
+
.filter((remote) => Boolean(remote))
|
|
278
|
+
.filter((remote, index, remotes) => remotes.indexOf(remote) === index);
|
|
266
279
|
const metadata = {
|
|
267
280
|
worktreePath,
|
|
268
281
|
branch: branch === "HEAD" ? undefined : branch,
|
|
269
282
|
commit,
|
|
283
|
+
remoteUrls,
|
|
270
284
|
};
|
|
271
285
|
gitMetadataCache.set(gitCwd, metadata);
|
|
272
286
|
return metadata;
|
|
@@ -511,8 +525,10 @@ function loadPathTagsConfig(path) {
|
|
|
511
525
|
const rules = rawRules.map((rawRule, index) => {
|
|
512
526
|
const rule = asRecord(rawRule);
|
|
513
527
|
const pathPrefix = asString(rule.pathPrefix) ?? asString(rule.path_prefix);
|
|
514
|
-
|
|
515
|
-
|
|
528
|
+
const gitRemoteIncludes = stringArray(rule.gitRemoteIncludes ?? rule.git_remote_includes ?? rule.gitRemoteInclude ??
|
|
529
|
+
rule.git_remote_include);
|
|
530
|
+
if (!pathPrefix && gitRemoteIncludes.length === 0) {
|
|
531
|
+
throw new Error(`Invalid path tags config ${path}: rules[${index}] requires pathPrefix or gitRemoteIncludes`);
|
|
516
532
|
}
|
|
517
533
|
const tags = Array.isArray(rule.tags)
|
|
518
534
|
? rule.tags.filter((tag) => typeof tag === "string" && tag.trim().length > 0)
|
|
@@ -520,6 +536,7 @@ function loadPathTagsConfig(path) {
|
|
|
520
536
|
const metadata = asRecord(rule.metadata);
|
|
521
537
|
return {
|
|
522
538
|
pathPrefix,
|
|
539
|
+
gitRemoteIncludes,
|
|
523
540
|
tags,
|
|
524
541
|
metadata,
|
|
525
542
|
projectName: asString(rule.projectName) ?? asString(rule.project_name),
|
|
@@ -764,6 +781,13 @@ function getPath(value, keys) {
|
|
|
764
781
|
function asString(value) {
|
|
765
782
|
return typeof value === "string" ? value : undefined;
|
|
766
783
|
}
|
|
784
|
+
function stringArray(value) {
|
|
785
|
+
if (typeof value === "string" && value.trim().length > 0)
|
|
786
|
+
return [value];
|
|
787
|
+
if (!Array.isArray(value))
|
|
788
|
+
return [];
|
|
789
|
+
return value.filter((item) => typeof item === "string" && item.trim().length > 0);
|
|
790
|
+
}
|
|
767
791
|
function asNumber(value) {
|
|
768
792
|
return typeof value === "number" && Number.isFinite(value)
|
|
769
793
|
? value
|