mobbdev 1.2.60 → 1.2.65
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/args/commands/upload_ai_blame.mjs +17 -16
- package/dist/index.mjs +203 -38
- package/package.json +1 -1
|
@@ -5518,21 +5518,6 @@ Make sure the input is not:
|
|
|
5518
5518
|
- \`Runtime.getRuntime().exec(new String[] {"perl", "-e", "print '" + input + "'"});\``,
|
|
5519
5519
|
guidance: () => ""
|
|
5520
5520
|
},
|
|
5521
|
-
isPlainCommandArgument: {
|
|
5522
|
-
content: () => "Is the input an argument of a plain command?",
|
|
5523
|
-
description: () => `Examples for "yes" answer:
|
|
5524
|
-
|
|
5525
|
-
- \`Runtime.getRuntime().exec("git clone " + input);\`
|
|
5526
|
-
- \`Runtime.getRuntime().exec("curl " + input);\`
|
|
5527
|
-
- \`Runtime.getRuntime().exec("cat " + input);\`
|
|
5528
|
-
|
|
5529
|
-
Examples for "no" answer:
|
|
5530
|
-
|
|
5531
|
-
- \`Runtime.getRuntime().exec("cmd /c " + input);\`
|
|
5532
|
-
- \`Runtime.getRuntime().exec("sh -c " + input);\`
|
|
5533
|
-
- \`Runtime.getRuntime().exec("perl -e " + input);\``,
|
|
5534
|
-
guidance: () => ""
|
|
5535
|
-
},
|
|
5536
5521
|
installApacheCommonsText: {
|
|
5537
5522
|
content: () => "Is the Apache Commons library (org.apache.commons) included in your project, if not, can you add it?",
|
|
5538
5523
|
description: () => "Apache Commons Text is a library focused on algorithms working on strings.",
|
|
@@ -7209,7 +7194,17 @@ import Debug8 from "debug";
|
|
|
7209
7194
|
|
|
7210
7195
|
// src/utils/sanitize-sensitive-data.ts
|
|
7211
7196
|
import { OpenRedaction } from "@openredaction/openredaction";
|
|
7197
|
+
var ADO_PAT_PATTERN = {
|
|
7198
|
+
type: "AZURE_DEVOPS_PAT",
|
|
7199
|
+
regex: /\b[a-zA-Z0-9]{20,}JQQJ99[a-zA-Z0-9]{10,52}\b/g,
|
|
7200
|
+
priority: 95,
|
|
7201
|
+
placeholder: "[ADO_PAT_{n}]",
|
|
7202
|
+
description: "Azure DevOps Personal Access Token",
|
|
7203
|
+
severity: "high",
|
|
7204
|
+
validator: (match) => match.length >= 52 && match.length <= 100
|
|
7205
|
+
};
|
|
7212
7206
|
var openRedaction = new OpenRedaction({
|
|
7207
|
+
customPatterns: [ADO_PAT_PATTERN],
|
|
7213
7208
|
patterns: [
|
|
7214
7209
|
// Core Personal Data
|
|
7215
7210
|
// Removed EMAIL - causes false positives in code/test snippets (e.g. --author="Eve Author <eve@example.com>")
|
|
@@ -7280,7 +7275,9 @@ var openRedaction = new OpenRedaction({
|
|
|
7280
7275
|
"STRIPE_API_KEY",
|
|
7281
7276
|
"GOOGLE_API_KEY",
|
|
7282
7277
|
"FIREBASE_API_KEY",
|
|
7283
|
-
|
|
7278
|
+
// Removed HEROKU_API_KEY - its regex matches ALL UUIDs ([a-f0-9]{8}-[a-f0-9]{4}-...)
|
|
7279
|
+
// and the validator triggers on "auth" anywhere in context (e.g. "oauth2" in user IDs).
|
|
7280
|
+
// This causes false positives on every UUID when OAuth-related strings are nearby.
|
|
7284
7281
|
"MAILGUN_API_KEY",
|
|
7285
7282
|
"SENDGRID_API_KEY",
|
|
7286
7283
|
"TWILIO_API_KEY",
|
|
@@ -7305,7 +7302,11 @@ async function sanitizeDataWithCounts(obj) {
|
|
|
7305
7302
|
const counts = {
|
|
7306
7303
|
detections: { total: 0, high: 0, medium: 0, low: 0 }
|
|
7307
7304
|
};
|
|
7305
|
+
const MAX_SCAN_LENGTH = 1e5;
|
|
7308
7306
|
const sanitizeString = async (str) => {
|
|
7307
|
+
if (str.length > MAX_SCAN_LENGTH) {
|
|
7308
|
+
return str;
|
|
7309
|
+
}
|
|
7309
7310
|
let result = str;
|
|
7310
7311
|
const piiDetections = openRedaction.scan(str);
|
|
7311
7312
|
if (piiDetections && piiDetections.total > 0) {
|
package/dist/index.mjs
CHANGED
|
@@ -5269,21 +5269,6 @@ Make sure the input is not:
|
|
|
5269
5269
|
- \`Runtime.getRuntime().exec(new String[] {"perl", "-e", "print '" + input + "'"});\``,
|
|
5270
5270
|
guidance: () => ""
|
|
5271
5271
|
},
|
|
5272
|
-
isPlainCommandArgument: {
|
|
5273
|
-
content: () => "Is the input an argument of a plain command?",
|
|
5274
|
-
description: () => `Examples for "yes" answer:
|
|
5275
|
-
|
|
5276
|
-
- \`Runtime.getRuntime().exec("git clone " + input);\`
|
|
5277
|
-
- \`Runtime.getRuntime().exec("curl " + input);\`
|
|
5278
|
-
- \`Runtime.getRuntime().exec("cat " + input);\`
|
|
5279
|
-
|
|
5280
|
-
Examples for "no" answer:
|
|
5281
|
-
|
|
5282
|
-
- \`Runtime.getRuntime().exec("cmd /c " + input);\`
|
|
5283
|
-
- \`Runtime.getRuntime().exec("sh -c " + input);\`
|
|
5284
|
-
- \`Runtime.getRuntime().exec("perl -e " + input);\``,
|
|
5285
|
-
guidance: () => ""
|
|
5286
|
-
},
|
|
5287
5272
|
installApacheCommonsText: {
|
|
5288
5273
|
content: () => "Is the Apache Commons library (org.apache.commons) included in your project, if not, can you add it?",
|
|
5289
5274
|
description: () => "Apache Commons Text is a library focused on algorithms working on strings.",
|
|
@@ -13186,7 +13171,17 @@ function getStableComputerName() {
|
|
|
13186
13171
|
|
|
13187
13172
|
// src/utils/sanitize-sensitive-data.ts
|
|
13188
13173
|
import { OpenRedaction } from "@openredaction/openredaction";
|
|
13174
|
+
var ADO_PAT_PATTERN = {
|
|
13175
|
+
type: "AZURE_DEVOPS_PAT",
|
|
13176
|
+
regex: /\b[a-zA-Z0-9]{20,}JQQJ99[a-zA-Z0-9]{10,52}\b/g,
|
|
13177
|
+
priority: 95,
|
|
13178
|
+
placeholder: "[ADO_PAT_{n}]",
|
|
13179
|
+
description: "Azure DevOps Personal Access Token",
|
|
13180
|
+
severity: "high",
|
|
13181
|
+
validator: (match) => match.length >= 52 && match.length <= 100
|
|
13182
|
+
};
|
|
13189
13183
|
var openRedaction = new OpenRedaction({
|
|
13184
|
+
customPatterns: [ADO_PAT_PATTERN],
|
|
13190
13185
|
patterns: [
|
|
13191
13186
|
// Core Personal Data
|
|
13192
13187
|
// Removed EMAIL - causes false positives in code/test snippets (e.g. --author="Eve Author <eve@example.com>")
|
|
@@ -13257,7 +13252,9 @@ var openRedaction = new OpenRedaction({
|
|
|
13257
13252
|
"STRIPE_API_KEY",
|
|
13258
13253
|
"GOOGLE_API_KEY",
|
|
13259
13254
|
"FIREBASE_API_KEY",
|
|
13260
|
-
|
|
13255
|
+
// Removed HEROKU_API_KEY - its regex matches ALL UUIDs ([a-f0-9]{8}-[a-f0-9]{4}-...)
|
|
13256
|
+
// and the validator triggers on "auth" anywhere in context (e.g. "oauth2" in user IDs).
|
|
13257
|
+
// This causes false positives on every UUID when OAuth-related strings are nearby.
|
|
13261
13258
|
"MAILGUN_API_KEY",
|
|
13262
13259
|
"SENDGRID_API_KEY",
|
|
13263
13260
|
"TWILIO_API_KEY",
|
|
@@ -13282,7 +13279,11 @@ async function sanitizeDataWithCounts(obj) {
|
|
|
13282
13279
|
const counts = {
|
|
13283
13280
|
detections: { total: 0, high: 0, medium: 0, low: 0 }
|
|
13284
13281
|
};
|
|
13282
|
+
const MAX_SCAN_LENGTH = 1e5;
|
|
13285
13283
|
const sanitizeString = async (str) => {
|
|
13284
|
+
if (str.length > MAX_SCAN_LENGTH) {
|
|
13285
|
+
return str;
|
|
13286
|
+
}
|
|
13286
13287
|
let result = str;
|
|
13287
13288
|
const piiDetections = openRedaction.scan(str);
|
|
13288
13289
|
if (piiDetections && piiDetections.total > 0) {
|
|
@@ -16394,9 +16395,11 @@ async function analyzeHandler(args) {
|
|
|
16394
16395
|
}
|
|
16395
16396
|
|
|
16396
16397
|
// src/features/claude_code/data_collector.ts
|
|
16398
|
+
import { execFile } from "child_process";
|
|
16397
16399
|
import { createHash as createHash2 } from "crypto";
|
|
16398
16400
|
import { access, open as open4, readdir, readFile, unlink } from "fs/promises";
|
|
16399
16401
|
import path14 from "path";
|
|
16402
|
+
import { promisify } from "util";
|
|
16400
16403
|
import { z as z33 } from "zod";
|
|
16401
16404
|
init_client_generates();
|
|
16402
16405
|
|
|
@@ -16552,7 +16555,10 @@ function createDdBatch(config2) {
|
|
|
16552
16555
|
}
|
|
16553
16556
|
});
|
|
16554
16557
|
}
|
|
16555
|
-
|
|
16558
|
+
function updateDdTags(ddtags) {
|
|
16559
|
+
config2.ddtags = ddtags;
|
|
16560
|
+
}
|
|
16561
|
+
return { enqueue, flush, flushAsync, dispose, createPinoStream, updateDdTags };
|
|
16556
16562
|
}
|
|
16557
16563
|
|
|
16558
16564
|
// src/utils/shared-logger/hostname.ts
|
|
@@ -16665,6 +16671,11 @@ function createLogger(config2) {
|
|
|
16665
16671
|
ddBatch.dispose();
|
|
16666
16672
|
}
|
|
16667
16673
|
}
|
|
16674
|
+
function updateDdTags(newDdTags) {
|
|
16675
|
+
if (ddBatch) {
|
|
16676
|
+
ddBatch.updateDdTags(newDdTags);
|
|
16677
|
+
}
|
|
16678
|
+
}
|
|
16668
16679
|
return {
|
|
16669
16680
|
info,
|
|
16670
16681
|
warn,
|
|
@@ -16675,14 +16686,23 @@ function createLogger(config2) {
|
|
|
16675
16686
|
flushLogs: flushLogs2,
|
|
16676
16687
|
flushDdAsync,
|
|
16677
16688
|
disposeDd,
|
|
16678
|
-
setScopePath: csStream.setScopePath
|
|
16689
|
+
setScopePath: csStream.setScopePath,
|
|
16690
|
+
updateDdTags
|
|
16679
16691
|
};
|
|
16680
16692
|
}
|
|
16681
16693
|
|
|
16682
16694
|
// src/features/claude_code/hook_logger.ts
|
|
16683
16695
|
var DD_RUM_TOKEN = true ? "pubf59c0182545bfb4c299175119f1abf9b" : "";
|
|
16684
|
-
var CLI_VERSION = true ? "1.2.
|
|
16696
|
+
var CLI_VERSION = true ? "1.2.65" : "unknown";
|
|
16685
16697
|
var NAMESPACE = "mobbdev-claude-code-hook-logs";
|
|
16698
|
+
var claudeCodeVersion;
|
|
16699
|
+
function buildDdTags() {
|
|
16700
|
+
const tags = [`version:${CLI_VERSION}`];
|
|
16701
|
+
if (claudeCodeVersion) {
|
|
16702
|
+
tags.push(`cc_version:${claudeCodeVersion}`);
|
|
16703
|
+
}
|
|
16704
|
+
return tags.join(",");
|
|
16705
|
+
}
|
|
16686
16706
|
function createHookLogger(scopePath) {
|
|
16687
16707
|
return createLogger({
|
|
16688
16708
|
namespace: NAMESPACE,
|
|
@@ -16691,7 +16711,7 @@ function createHookLogger(scopePath) {
|
|
|
16691
16711
|
apiKey: DD_RUM_TOKEN,
|
|
16692
16712
|
ddsource: "mobbdev-cli",
|
|
16693
16713
|
service: "mobbdev-cli-hook",
|
|
16694
|
-
ddtags:
|
|
16714
|
+
ddtags: buildDdTags(),
|
|
16695
16715
|
hostnameMode: "hashed",
|
|
16696
16716
|
unrefTimer: true
|
|
16697
16717
|
}
|
|
@@ -16700,6 +16720,13 @@ function createHookLogger(scopePath) {
|
|
|
16700
16720
|
var logger = createHookLogger();
|
|
16701
16721
|
var activeScopedLoggers = [];
|
|
16702
16722
|
var hookLog = logger;
|
|
16723
|
+
function setClaudeCodeVersion(version) {
|
|
16724
|
+
claudeCodeVersion = version;
|
|
16725
|
+
logger.updateDdTags(buildDdTags());
|
|
16726
|
+
}
|
|
16727
|
+
function getClaudeCodeVersion() {
|
|
16728
|
+
return claudeCodeVersion;
|
|
16729
|
+
}
|
|
16703
16730
|
function flushLogs() {
|
|
16704
16731
|
logger.flushLogs();
|
|
16705
16732
|
for (const scoped of activeScopedLoggers) {
|
|
@@ -16725,8 +16752,7 @@ import os5 from "os";
|
|
|
16725
16752
|
import path13 from "path";
|
|
16726
16753
|
import chalk11 from "chalk";
|
|
16727
16754
|
var CLAUDE_SETTINGS_PATH = path13.join(os5.homedir(), ".claude", "settings.json");
|
|
16728
|
-
var RECOMMENDED_MATCHER = "
|
|
16729
|
-
var STALE_MATCHERS = /* @__PURE__ */ new Set(["", "*", "Edit|Write"]);
|
|
16755
|
+
var RECOMMENDED_MATCHER = "Write|Edit";
|
|
16730
16756
|
async function claudeSettingsExists() {
|
|
16731
16757
|
try {
|
|
16732
16758
|
await fsPromises4.access(CLAUDE_SETTINGS_PATH);
|
|
@@ -16758,12 +16784,19 @@ async function autoUpgradeMatcherIfStale() {
|
|
|
16758
16784
|
let upgraded = false;
|
|
16759
16785
|
for (const hook of hooks) {
|
|
16760
16786
|
const isMobbHook = hook.hooks.some(
|
|
16761
|
-
(h) => h.command?.includes("claude-code-process-hook")
|
|
16787
|
+
(h) => h.command?.includes("claude-code-process-hook")
|
|
16762
16788
|
);
|
|
16763
|
-
if (isMobbHook
|
|
16789
|
+
if (!isMobbHook) continue;
|
|
16790
|
+
if (hook.matcher !== RECOMMENDED_MATCHER) {
|
|
16764
16791
|
hook.matcher = RECOMMENDED_MATCHER;
|
|
16765
16792
|
upgraded = true;
|
|
16766
16793
|
}
|
|
16794
|
+
for (const h of hook.hooks) {
|
|
16795
|
+
if (!h.async) {
|
|
16796
|
+
h.async = true;
|
|
16797
|
+
upgraded = true;
|
|
16798
|
+
}
|
|
16799
|
+
}
|
|
16767
16800
|
}
|
|
16768
16801
|
if (upgraded) {
|
|
16769
16802
|
await writeClaudeSettings(settings);
|
|
@@ -16817,7 +16850,8 @@ async function installMobbHooks(options = {}) {
|
|
|
16817
16850
|
hooks: [
|
|
16818
16851
|
{
|
|
16819
16852
|
type: "command",
|
|
16820
|
-
command
|
|
16853
|
+
command,
|
|
16854
|
+
async: true
|
|
16821
16855
|
}
|
|
16822
16856
|
]
|
|
16823
16857
|
};
|
|
@@ -16842,6 +16876,8 @@ async function installMobbHooks(options = {}) {
|
|
|
16842
16876
|
}
|
|
16843
16877
|
|
|
16844
16878
|
// src/features/claude_code/data_collector.ts
|
|
16879
|
+
var CC_VERSION_CACHE_KEY = "claudeCode.detectedCCVersion";
|
|
16880
|
+
var CC_VERSION_CLI_KEY = "claudeCode.detectedCCVersionCli";
|
|
16845
16881
|
var GLOBAL_COOLDOWN_MS = 5e3;
|
|
16846
16882
|
var HOOK_COOLDOWN_MS = 15e3;
|
|
16847
16883
|
var ACTIVE_LOCK_TTL_MS = 6e4;
|
|
@@ -16852,14 +16888,35 @@ var MAX_ENTRIES_PER_INVOCATION = 50;
|
|
|
16852
16888
|
var COOLDOWN_KEY = "lastHookRunAt";
|
|
16853
16889
|
var ACTIVE_KEY = "hookActiveAt";
|
|
16854
16890
|
var HookDataSchema = z33.object({
|
|
16855
|
-
session_id: z33.string(),
|
|
16856
|
-
transcript_path: z33.string(),
|
|
16857
|
-
cwd: z33.string(),
|
|
16891
|
+
session_id: z33.string().nullish(),
|
|
16892
|
+
transcript_path: z33.string().nullish(),
|
|
16893
|
+
cwd: z33.string().nullish(),
|
|
16858
16894
|
hook_event_name: z33.string(),
|
|
16859
16895
|
tool_name: z33.string(),
|
|
16860
16896
|
tool_input: z33.unknown(),
|
|
16861
16897
|
tool_response: z33.unknown()
|
|
16862
16898
|
});
|
|
16899
|
+
var execFileAsync = promisify(execFile);
|
|
16900
|
+
async function detectClaudeCodeVersion() {
|
|
16901
|
+
const cachedCliVersion = configStore.get(CC_VERSION_CLI_KEY);
|
|
16902
|
+
if (cachedCliVersion === packageJson.version) {
|
|
16903
|
+
return configStore.get(CC_VERSION_CACHE_KEY);
|
|
16904
|
+
}
|
|
16905
|
+
try {
|
|
16906
|
+
const { stdout: stdout2 } = await execFileAsync("claude", ["--version"], {
|
|
16907
|
+
timeout: 3e3,
|
|
16908
|
+
encoding: "utf-8"
|
|
16909
|
+
});
|
|
16910
|
+
const version = stdout2.trim().split(/\s/)[0] || stdout2.trim();
|
|
16911
|
+
configStore.set(CC_VERSION_CACHE_KEY, version);
|
|
16912
|
+
configStore.set(CC_VERSION_CLI_KEY, packageJson.version);
|
|
16913
|
+
return version;
|
|
16914
|
+
} catch {
|
|
16915
|
+
configStore.set(CC_VERSION_CACHE_KEY, void 0);
|
|
16916
|
+
configStore.set(CC_VERSION_CLI_KEY, packageJson.version);
|
|
16917
|
+
return void 0;
|
|
16918
|
+
}
|
|
16919
|
+
}
|
|
16863
16920
|
var STDIN_TIMEOUT_MS = 1e4;
|
|
16864
16921
|
async function readStdinData() {
|
|
16865
16922
|
hookLog.debug("Reading stdin data");
|
|
@@ -16911,6 +16968,24 @@ async function readStdinData() {
|
|
|
16911
16968
|
function validateHookData(data) {
|
|
16912
16969
|
return HookDataSchema.parse(data);
|
|
16913
16970
|
}
|
|
16971
|
+
async function extractSessionIdFromTranscript(transcriptPath) {
|
|
16972
|
+
try {
|
|
16973
|
+
const fh = await open4(transcriptPath, "r");
|
|
16974
|
+
try {
|
|
16975
|
+
const buf = Buffer.alloc(4096);
|
|
16976
|
+
const { bytesRead } = await fh.read(buf, 0, 4096, 0);
|
|
16977
|
+
const chunk = buf.toString("utf-8", 0, bytesRead);
|
|
16978
|
+
const firstLine = chunk.split("\n").find((l) => l.trim().length > 0);
|
|
16979
|
+
if (!firstLine) return null;
|
|
16980
|
+
const entry = JSON.parse(firstLine);
|
|
16981
|
+
return entry.sessionId ?? null;
|
|
16982
|
+
} finally {
|
|
16983
|
+
await fh.close();
|
|
16984
|
+
}
|
|
16985
|
+
} catch {
|
|
16986
|
+
return null;
|
|
16987
|
+
}
|
|
16988
|
+
}
|
|
16914
16989
|
function generateSyntheticId(sessionId, timestamp, type2, lineIndex) {
|
|
16915
16990
|
const input = `${sessionId ?? ""}:${timestamp ?? ""}:${type2 ?? ""}:${lineIndex}`;
|
|
16916
16991
|
const hash = createHash2("sha256").update(input).digest("hex").slice(0, 16);
|
|
@@ -17201,9 +17276,94 @@ async function processAndUploadTranscriptEntries() {
|
|
|
17201
17276
|
hookLog.info("Auto-upgraded hook matcher to reduce CPU usage");
|
|
17202
17277
|
}
|
|
17203
17278
|
}
|
|
17279
|
+
try {
|
|
17280
|
+
const ccVersion = await detectClaudeCodeVersion();
|
|
17281
|
+
setClaudeCodeVersion(ccVersion);
|
|
17282
|
+
} catch {
|
|
17283
|
+
}
|
|
17204
17284
|
const rawData = await readStdinData();
|
|
17205
|
-
const
|
|
17206
|
-
const
|
|
17285
|
+
const rawObj = rawData;
|
|
17286
|
+
const hookData = (() => {
|
|
17287
|
+
try {
|
|
17288
|
+
return validateHookData(rawData);
|
|
17289
|
+
} catch (err) {
|
|
17290
|
+
hookLog.error(
|
|
17291
|
+
{
|
|
17292
|
+
data: {
|
|
17293
|
+
hook_event_name: rawObj?.["hook_event_name"],
|
|
17294
|
+
tool_name: rawObj?.["tool_name"],
|
|
17295
|
+
session_id: rawObj?.["session_id"],
|
|
17296
|
+
cwd: rawObj?.["cwd"],
|
|
17297
|
+
keys: rawObj ? Object.keys(rawObj) : []
|
|
17298
|
+
}
|
|
17299
|
+
},
|
|
17300
|
+
`Hook validation failed: ${err.message?.slice(0, 200)}`
|
|
17301
|
+
);
|
|
17302
|
+
throw err;
|
|
17303
|
+
}
|
|
17304
|
+
})();
|
|
17305
|
+
if (!hookData.transcript_path) {
|
|
17306
|
+
hookLog.warn(
|
|
17307
|
+
{
|
|
17308
|
+
data: {
|
|
17309
|
+
hook_event_name: hookData.hook_event_name,
|
|
17310
|
+
tool_name: hookData.tool_name,
|
|
17311
|
+
session_id: hookData.session_id,
|
|
17312
|
+
cwd: hookData.cwd
|
|
17313
|
+
}
|
|
17314
|
+
},
|
|
17315
|
+
"Missing transcript_path \u2014 cannot process hook"
|
|
17316
|
+
);
|
|
17317
|
+
return { entriesUploaded: 0, entriesSkipped: 0, errors: 0 };
|
|
17318
|
+
}
|
|
17319
|
+
let sessionId = hookData.session_id;
|
|
17320
|
+
if (!sessionId) {
|
|
17321
|
+
sessionId = await extractSessionIdFromTranscript(hookData.transcript_path);
|
|
17322
|
+
if (sessionId) {
|
|
17323
|
+
hookLog.warn(
|
|
17324
|
+
{
|
|
17325
|
+
data: {
|
|
17326
|
+
hook_event_name: hookData.hook_event_name,
|
|
17327
|
+
tool_name: hookData.tool_name,
|
|
17328
|
+
cwd: hookData.cwd,
|
|
17329
|
+
extractedSessionId: sessionId
|
|
17330
|
+
}
|
|
17331
|
+
},
|
|
17332
|
+
"Missing session_id in hook data \u2014 extracted from transcript"
|
|
17333
|
+
);
|
|
17334
|
+
} else {
|
|
17335
|
+
hookLog.warn(
|
|
17336
|
+
{
|
|
17337
|
+
data: {
|
|
17338
|
+
hook_event_name: hookData.hook_event_name,
|
|
17339
|
+
tool_name: hookData.tool_name,
|
|
17340
|
+
transcript_path: hookData.transcript_path
|
|
17341
|
+
}
|
|
17342
|
+
},
|
|
17343
|
+
"Missing session_id and could not extract from transcript \u2014 cannot process hook"
|
|
17344
|
+
);
|
|
17345
|
+
return { entriesUploaded: 0, entriesSkipped: 0, errors: 0 };
|
|
17346
|
+
}
|
|
17347
|
+
}
|
|
17348
|
+
if (!hookData.cwd) {
|
|
17349
|
+
hookLog.warn(
|
|
17350
|
+
{
|
|
17351
|
+
data: {
|
|
17352
|
+
hook_event_name: hookData.hook_event_name,
|
|
17353
|
+
tool_name: hookData.tool_name,
|
|
17354
|
+
session_id: sessionId
|
|
17355
|
+
}
|
|
17356
|
+
},
|
|
17357
|
+
"Missing cwd in hook data \u2014 scoped logging and repo URL detection disabled"
|
|
17358
|
+
);
|
|
17359
|
+
}
|
|
17360
|
+
const resolvedHookData = {
|
|
17361
|
+
...hookData,
|
|
17362
|
+
session_id: sessionId,
|
|
17363
|
+
transcript_path: hookData.transcript_path,
|
|
17364
|
+
cwd: hookData.cwd ?? void 0
|
|
17365
|
+
};
|
|
17366
|
+
const sessionStore = createSessionConfigStore(resolvedHookData.session_id);
|
|
17207
17367
|
await cleanupStaleSessions(sessionStore);
|
|
17208
17368
|
const now = Date.now();
|
|
17209
17369
|
const lastRunAt = sessionStore.get(COOLDOWN_KEY);
|
|
@@ -17218,7 +17378,7 @@ async function processAndUploadTranscriptEntries() {
|
|
|
17218
17378
|
{
|
|
17219
17379
|
data: {
|
|
17220
17380
|
activeDurationMs: activeDuration,
|
|
17221
|
-
sessionId:
|
|
17381
|
+
sessionId: resolvedHookData.session_id
|
|
17222
17382
|
}
|
|
17223
17383
|
},
|
|
17224
17384
|
"Hook still active \u2014 possible slow upload or hung process"
|
|
@@ -17228,20 +17388,21 @@ async function processAndUploadTranscriptEntries() {
|
|
|
17228
17388
|
}
|
|
17229
17389
|
sessionStore.set(ACTIVE_KEY, now);
|
|
17230
17390
|
sessionStore.set(COOLDOWN_KEY, now);
|
|
17231
|
-
const log2 = createScopedHookLog(
|
|
17391
|
+
const log2 = createScopedHookLog(resolvedHookData.cwd ?? process.cwd());
|
|
17232
17392
|
log2.info(
|
|
17233
17393
|
{
|
|
17234
17394
|
data: {
|
|
17235
|
-
sessionId:
|
|
17236
|
-
toolName:
|
|
17237
|
-
hookEvent:
|
|
17238
|
-
cwd:
|
|
17395
|
+
sessionId: resolvedHookData.session_id,
|
|
17396
|
+
toolName: resolvedHookData.tool_name,
|
|
17397
|
+
hookEvent: resolvedHookData.hook_event_name,
|
|
17398
|
+
cwd: resolvedHookData.cwd,
|
|
17399
|
+
claudeCodeVersion: getClaudeCodeVersion()
|
|
17239
17400
|
}
|
|
17240
17401
|
},
|
|
17241
17402
|
"Hook data validated"
|
|
17242
17403
|
);
|
|
17243
17404
|
try {
|
|
17244
|
-
return await processTranscript(
|
|
17405
|
+
return await processTranscript(resolvedHookData, sessionStore, log2);
|
|
17245
17406
|
} finally {
|
|
17246
17407
|
sessionStore.delete(ACTIVE_KEY);
|
|
17247
17408
|
log2.flushLogs();
|
|
@@ -17330,6 +17491,9 @@ async function processTranscript(hookData, sessionStore, log2) {
|
|
|
17330
17491
|
rawEntry["message"] = { model: lastSeenModel };
|
|
17331
17492
|
}
|
|
17332
17493
|
}
|
|
17494
|
+
if (!rawEntry["sessionId"]) {
|
|
17495
|
+
rawEntry["sessionId"] = hookData.session_id;
|
|
17496
|
+
}
|
|
17333
17497
|
return {
|
|
17334
17498
|
platform: "CLAUDE_CODE" /* ClaudeCode */,
|
|
17335
17499
|
recordId: _recordId,
|
|
@@ -17371,7 +17535,8 @@ async function processTranscript(hookData, sessionStore, log2) {
|
|
|
17371
17535
|
sessionStore.set(cursorKey, cursor);
|
|
17372
17536
|
log2.heartbeat("Upload ok", {
|
|
17373
17537
|
entriesUploaded: entries.length,
|
|
17374
|
-
entriesSkipped: filteredOut
|
|
17538
|
+
entriesSkipped: filteredOut,
|
|
17539
|
+
claudeCodeVersion: getClaudeCodeVersion()
|
|
17375
17540
|
});
|
|
17376
17541
|
return {
|
|
17377
17542
|
entriesUploaded: entries.length,
|