mobbdev 1.4.18 → 1.4.19
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.mjs +80 -9
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -19448,7 +19448,7 @@ function createLogger(config2) {
|
|
|
19448
19448
|
|
|
19449
19449
|
// src/features/claude_code/hook_logger.ts
|
|
19450
19450
|
var DD_RUM_TOKEN = true ? "pubf59c0182545bfb4c299175119f1abf9b" : "";
|
|
19451
|
-
var CLI_VERSION = true ? "1.4.
|
|
19451
|
+
var CLI_VERSION = true ? "1.4.19" : "unknown";
|
|
19452
19452
|
var NAMESPACE = "mobbdev-claude-code-hook-logs";
|
|
19453
19453
|
var claudeCodeVersion;
|
|
19454
19454
|
function buildDdTags() {
|
|
@@ -19940,7 +19940,12 @@ async function processTranscript(input, sessionStore, log2, maxEntries = DAEMON_
|
|
|
19940
19940
|
rawData: rawEntry,
|
|
19941
19941
|
repositoryUrl: sampledRepoState.repositoryUrl ?? void 0,
|
|
19942
19942
|
branch: sampledRepoState.branch,
|
|
19943
|
-
commitSha: sampledRepoState.commitSha
|
|
19943
|
+
commitSha: sampledRepoState.commitSha,
|
|
19944
|
+
// T-510: sub-agent attribution stamped per record. Defaults preserve
|
|
19945
|
+
// main-session semantics so the upload schema's `isSubagent` defaults
|
|
19946
|
+
// to false on the wire for older clients / main-transcript files.
|
|
19947
|
+
isSubagent: input.isSubagent ?? false,
|
|
19948
|
+
agentType: input.agentType ?? null
|
|
19944
19949
|
};
|
|
19945
19950
|
});
|
|
19946
19951
|
let totalRawDataBytes = 0;
|
|
@@ -19980,9 +19985,16 @@ async function processTranscript(input, sessionStore, log2, maxEntries = DAEMON_
|
|
|
19980
19985
|
lastModel: lastSeenModel ?? void 0
|
|
19981
19986
|
};
|
|
19982
19987
|
sessionStore.set(cursorKey, cursor);
|
|
19988
|
+
const isSubagentBatch = input.isSubagent === true;
|
|
19983
19989
|
log2.heartbeat("Upload ok", {
|
|
19984
19990
|
entriesUploaded: entries.length,
|
|
19985
19991
|
entriesSkipped: filteredOut,
|
|
19992
|
+
subagentEntriesUploaded: isSubagentBatch ? entries.length : 0,
|
|
19993
|
+
// Renamed for clarity: this counts rows uploaded with no agent_type
|
|
19994
|
+
// because the sibling .meta.json was missing/unreadable at scan
|
|
19995
|
+
// time. Should be ~0 in steady state; a non-zero rate is a signal
|
|
19996
|
+
// that Claude Code's meta convention may have changed.
|
|
19997
|
+
subagentEntriesUploadedMissingMeta: isSubagentBatch && input.agentType == null ? entries.length : 0,
|
|
19986
19998
|
claudeCodeVersion: getClaudeCodeVersion()
|
|
19987
19999
|
});
|
|
19988
20000
|
return {
|
|
@@ -20224,7 +20236,7 @@ async function installMobbHooks(options = {}) {
|
|
|
20224
20236
|
}
|
|
20225
20237
|
|
|
20226
20238
|
// src/features/claude_code/transcript_scanner.ts
|
|
20227
|
-
import { open as open5, readdir as readdir4, stat as stat4 } from "fs/promises";
|
|
20239
|
+
import { lstat as lstat2, open as open5, readdir as readdir4, stat as stat4 } from "fs/promises";
|
|
20228
20240
|
import os7 from "os";
|
|
20229
20241
|
import path23 from "path";
|
|
20230
20242
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -20238,11 +20250,59 @@ function getClaudeProjectsDirs() {
|
|
|
20238
20250
|
dirs.push(path23.join(os7.homedir(), ".claude", "projects"));
|
|
20239
20251
|
return dirs;
|
|
20240
20252
|
}
|
|
20241
|
-
|
|
20253
|
+
var META_MAX_BYTES = 4096;
|
|
20254
|
+
var AGENT_TYPE_RE = /^[A-Za-z0-9_.\- ]+$/;
|
|
20255
|
+
var agentTypeCache = /* @__PURE__ */ new Map();
|
|
20256
|
+
var knownAbsentSubagentDirs = /* @__PURE__ */ new Set();
|
|
20257
|
+
async function readAgentType(jsonlPath, jsonlMtimeMs) {
|
|
20258
|
+
const cached = agentTypeCache.get(jsonlPath);
|
|
20259
|
+
if (cached && cached.mtimeMs === jsonlMtimeMs) {
|
|
20260
|
+
return cached.value;
|
|
20261
|
+
}
|
|
20262
|
+
const metaPath = jsonlPath.replace(/\.jsonl$/, ".meta.json");
|
|
20263
|
+
let fh;
|
|
20264
|
+
let value = null;
|
|
20265
|
+
try {
|
|
20266
|
+
const lst = await lstat2(metaPath);
|
|
20267
|
+
if (!lst.isFile() || lst.size > META_MAX_BYTES) {
|
|
20268
|
+
agentTypeCache.set(jsonlPath, { mtimeMs: jsonlMtimeMs, value: null });
|
|
20269
|
+
return null;
|
|
20270
|
+
}
|
|
20271
|
+
fh = await open5(metaPath, "r");
|
|
20272
|
+
const buf = Buffer.alloc(Math.min(lst.size, META_MAX_BYTES));
|
|
20273
|
+
const { bytesRead } = await fh.read(buf, 0, buf.length, 0);
|
|
20274
|
+
const raw = buf.toString("utf8", 0, bytesRead);
|
|
20275
|
+
const parsed = JSON.parse(raw);
|
|
20276
|
+
if (parsed && typeof parsed === "object") {
|
|
20277
|
+
const candidate = parsed.agentType;
|
|
20278
|
+
if (typeof candidate === "string" && candidate.length > 0 && candidate.length <= 128 && AGENT_TYPE_RE.test(candidate.trim())) {
|
|
20279
|
+
value = candidate.trim();
|
|
20280
|
+
}
|
|
20281
|
+
}
|
|
20282
|
+
} catch {
|
|
20283
|
+
} finally {
|
|
20284
|
+
if (fh) {
|
|
20285
|
+
await fh.close().catch(() => void 0);
|
|
20286
|
+
}
|
|
20287
|
+
}
|
|
20288
|
+
agentTypeCache.set(jsonlPath, { mtimeMs: jsonlMtimeMs, value });
|
|
20289
|
+
return value;
|
|
20290
|
+
}
|
|
20291
|
+
async function collectJsonlFiles(files, dir, projectDir, seen, now, results, override) {
|
|
20242
20292
|
for (const file of files) {
|
|
20243
20293
|
if (!file.endsWith(".jsonl")) continue;
|
|
20244
|
-
|
|
20245
|
-
|
|
20294
|
+
let sessionId;
|
|
20295
|
+
let isSubagent;
|
|
20296
|
+
if (override) {
|
|
20297
|
+
if (!/^agent-[A-Za-z0-9_-]+\.jsonl$/.test(file)) continue;
|
|
20298
|
+
sessionId = override.parentUuid;
|
|
20299
|
+
isSubagent = true;
|
|
20300
|
+
} else {
|
|
20301
|
+
const basename2 = file.replace(".jsonl", "");
|
|
20302
|
+
if (!UUID_RE.test(basename2)) continue;
|
|
20303
|
+
sessionId = basename2;
|
|
20304
|
+
isSubagent = false;
|
|
20305
|
+
}
|
|
20246
20306
|
const filePath = path23.join(dir, file);
|
|
20247
20307
|
if (seen.has(filePath)) continue;
|
|
20248
20308
|
seen.add(filePath);
|
|
@@ -20253,12 +20313,15 @@ async function collectJsonlFiles(files, dir, projectDir, seen, now, results) {
|
|
|
20253
20313
|
continue;
|
|
20254
20314
|
}
|
|
20255
20315
|
if (now - fileStat.mtimeMs > TRANSCRIPT_MAX_AGE_MS) continue;
|
|
20316
|
+
const agentType = isSubagent ? await readAgentType(filePath, fileStat.mtimeMs) : null;
|
|
20256
20317
|
results.push({
|
|
20257
20318
|
filePath,
|
|
20258
20319
|
sessionId,
|
|
20259
20320
|
projectDir,
|
|
20260
20321
|
mtimeMs: fileStat.mtimeMs,
|
|
20261
|
-
size: fileStat.size
|
|
20322
|
+
size: fileStat.size,
|
|
20323
|
+
isSubagent,
|
|
20324
|
+
agentType
|
|
20262
20325
|
});
|
|
20263
20326
|
}
|
|
20264
20327
|
}
|
|
@@ -20292,6 +20355,7 @@ async function scanForTranscripts(projectsDirs = getClaudeProjectsDirs()) {
|
|
|
20292
20355
|
for (const entry of files) {
|
|
20293
20356
|
if (!UUID_RE.test(entry)) continue;
|
|
20294
20357
|
const subagentsDir = path23.join(projPath, entry, "subagents");
|
|
20358
|
+
if (knownAbsentSubagentDirs.has(subagentsDir)) continue;
|
|
20295
20359
|
try {
|
|
20296
20360
|
const s = await stat4(subagentsDir);
|
|
20297
20361
|
if (!s.isDirectory()) continue;
|
|
@@ -20302,9 +20366,11 @@ async function scanForTranscripts(projectsDirs = getClaudeProjectsDirs()) {
|
|
|
20302
20366
|
projPath,
|
|
20303
20367
|
seen,
|
|
20304
20368
|
now,
|
|
20305
|
-
results
|
|
20369
|
+
results,
|
|
20370
|
+
{ parentUuid: entry }
|
|
20306
20371
|
);
|
|
20307
20372
|
} catch {
|
|
20373
|
+
knownAbsentSubagentDirs.add(subagentsDir);
|
|
20308
20374
|
}
|
|
20309
20375
|
}
|
|
20310
20376
|
}
|
|
@@ -20535,7 +20601,12 @@ async function drainTranscript(transcript, sessionStore, gqlClient, sessionCwdCa
|
|
|
20535
20601
|
{
|
|
20536
20602
|
session_id: transcript.sessionId,
|
|
20537
20603
|
transcript_path: transcript.filePath,
|
|
20538
|
-
cwd
|
|
20604
|
+
cwd,
|
|
20605
|
+
// T-510: forward sub-agent attribution from transcript_scanner.ts.
|
|
20606
|
+
// For main-session files these are false / null and behave
|
|
20607
|
+
// identically to the pre-T-510 wire.
|
|
20608
|
+
isSubagent: transcript.isSubagent,
|
|
20609
|
+
agentType: transcript.agentType
|
|
20539
20610
|
},
|
|
20540
20611
|
sessionStore,
|
|
20541
20612
|
log2,
|