@tekdi/coding-analytics 1.0.2 → 1.0.4

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.
Files changed (62) hide show
  1. package/dist/analysis/analysis-prompt.d.ts +97 -0
  2. package/dist/analysis/analysis-prompt.d.ts.map +1 -0
  3. package/dist/analysis/analysis-prompt.js +312 -0
  4. package/dist/analysis/analysis-prompt.js.map +1 -0
  5. package/dist/analysis/feedback-aggregator.d.ts +15 -0
  6. package/dist/analysis/feedback-aggregator.d.ts.map +1 -0
  7. package/dist/analysis/feedback-aggregator.js +142 -0
  8. package/dist/analysis/feedback-aggregator.js.map +1 -0
  9. package/dist/analysis/llm-provider.d.ts +9 -0
  10. package/dist/analysis/llm-provider.d.ts.map +1 -0
  11. package/dist/analysis/llm-provider.js +23 -0
  12. package/dist/analysis/llm-provider.js.map +1 -0
  13. package/dist/analysis/providers/claude-provider.d.ts +11 -0
  14. package/dist/analysis/providers/claude-provider.d.ts.map +1 -0
  15. package/dist/analysis/providers/claude-provider.js +74 -0
  16. package/dist/analysis/providers/claude-provider.js.map +1 -0
  17. package/dist/analysis/providers/gemini-provider.d.ts +11 -0
  18. package/dist/analysis/providers/gemini-provider.d.ts.map +1 -0
  19. package/dist/analysis/providers/gemini-provider.js +58 -0
  20. package/dist/analysis/providers/gemini-provider.js.map +1 -0
  21. package/dist/analysis/providers/openai-provider.d.ts +11 -0
  22. package/dist/analysis/providers/openai-provider.d.ts.map +1 -0
  23. package/dist/analysis/providers/openai-provider.js +66 -0
  24. package/dist/analysis/providers/openai-provider.js.map +1 -0
  25. package/dist/analysis/providers/parse-helper.d.ts +7 -0
  26. package/dist/analysis/providers/parse-helper.d.ts.map +1 -0
  27. package/dist/analysis/providers/parse-helper.js +27 -0
  28. package/dist/analysis/providers/parse-helper.js.map +1 -0
  29. package/dist/analysis/session-analyzer.d.ts +8 -0
  30. package/dist/analysis/session-analyzer.d.ts.map +1 -0
  31. package/dist/analysis/session-analyzer.js +115 -0
  32. package/dist/analysis/session-analyzer.js.map +1 -0
  33. package/dist/analysis/session-builder.d.ts +19 -0
  34. package/dist/analysis/session-builder.d.ts.map +1 -0
  35. package/dist/analysis/session-builder.js +174 -0
  36. package/dist/analysis/session-builder.js.map +1 -0
  37. package/dist/analysis/types.d.ts +94 -0
  38. package/dist/analysis/types.d.ts.map +1 -0
  39. package/dist/analysis/types.js +3 -0
  40. package/dist/analysis/types.js.map +1 -0
  41. package/dist/artifact-extractor.d.ts +55 -0
  42. package/dist/artifact-extractor.d.ts.map +1 -0
  43. package/dist/artifact-extractor.js +146 -0
  44. package/dist/artifact-extractor.js.map +1 -0
  45. package/dist/claude-hooks-receiver.d.ts +20 -0
  46. package/dist/claude-hooks-receiver.d.ts.map +1 -1
  47. package/dist/claude-hooks-receiver.js +402 -12
  48. package/dist/claude-hooks-receiver.js.map +1 -1
  49. package/dist/cli.js +242 -0
  50. package/dist/cli.js.map +1 -1
  51. package/dist/config.d.ts +14 -0
  52. package/dist/config.d.ts.map +1 -1
  53. package/dist/config.js +18 -0
  54. package/dist/config.js.map +1 -1
  55. package/dist/heartbeat.d.ts +12 -0
  56. package/dist/heartbeat.d.ts.map +1 -0
  57. package/dist/heartbeat.js +33 -0
  58. package/dist/heartbeat.js.map +1 -0
  59. package/dist/logger.d.ts.map +1 -1
  60. package/dist/logger.js +16 -8
  61. package/dist/logger.js.map +1 -1
  62. package/package.json +8 -2
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SessionBuilder = void 0;
4
+ class SessionBuilder {
5
+ constructor(config) {
6
+ this.config = config;
7
+ }
8
+ async build(sessionId) {
9
+ const events = await this.fetchEvents(sessionId);
10
+ if (events.length === 0) {
11
+ throw new Error(`No events found for session: ${sessionId}`);
12
+ }
13
+ return this.assemble(sessionId, events);
14
+ }
15
+ async listSessionIds(distinctId, afterIso) {
16
+ const events = await this.fetchEventsByUser(distinctId, afterIso);
17
+ const ids = new Set();
18
+ for (const e of events) {
19
+ if (e.properties.session_id)
20
+ ids.add(e.properties.session_id);
21
+ }
22
+ return Array.from(ids);
23
+ }
24
+ // ── PostHog querying ────────────────────────────────────────────────────────
25
+ getQueryBase() {
26
+ const host = this.config.analysis.posthogQueryHost;
27
+ const project = this.config.analysis.posthogProjectId;
28
+ return `${host}/api/projects/${project}/events`;
29
+ }
30
+ authHeader() {
31
+ return {
32
+ Authorization: `Bearer ${this.config.analysis.posthogQueryApiKey}`,
33
+ 'Content-Type': 'application/json',
34
+ };
35
+ }
36
+ async fetchEvents(sessionId) {
37
+ const filter = encodeURIComponent(JSON.stringify([{ key: 'session_id', operator: 'exact', value: sessionId, type: 'event' }]));
38
+ const url = `${this.getQueryBase()}/?properties=${filter}&orderBy=%5B%22timestamp%22%5D&limit=200`;
39
+ return this.paginate(url);
40
+ }
41
+ async fetchEventsByUser(distinctId, afterIso) {
42
+ const url = `${this.getQueryBase()}/?distinct_id=${encodeURIComponent(distinctId)}&after=${encodeURIComponent(afterIso)}&limit=500`;
43
+ return this.paginate(url);
44
+ }
45
+ async paginate(url) {
46
+ const results = [];
47
+ let next = url;
48
+ while (next) {
49
+ const res = await fetch(next, { headers: this.authHeader() });
50
+ if (!res.ok) {
51
+ const body = await res.text();
52
+ throw new Error(`PostHog API error ${res.status}: ${body}`);
53
+ }
54
+ const data = await res.json();
55
+ results.push(...(data.results ?? []));
56
+ next = data.next ?? null;
57
+ }
58
+ return results;
59
+ }
60
+ // ── Session assembly ────────────────────────────────────────────────────────
61
+ assemble(sessionId, events) {
62
+ // Sort ascending so turns are in order
63
+ events.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
64
+ const first = events[0];
65
+ const last = events[events.length - 1];
66
+ const provider = this.detectProvider(events);
67
+ const metadata = this.extractMetadata(events);
68
+ const turns = this.buildTurns(events);
69
+ const stats = this.computeStats(events, turns);
70
+ return {
71
+ sessionId,
72
+ provider,
73
+ metadata,
74
+ turns,
75
+ stats,
76
+ startTime: first.timestamp,
77
+ endTime: last.timestamp,
78
+ };
79
+ }
80
+ detectProvider(events) {
81
+ for (const e of events) {
82
+ const p = e.properties.provider;
83
+ if (p === 'cursor' || p === 'claude')
84
+ return p;
85
+ if (e.event.startsWith('cursor_'))
86
+ return 'cursor';
87
+ if (e.event.startsWith('claude_'))
88
+ return 'claude';
89
+ }
90
+ return 'unknown';
91
+ }
92
+ extractMetadata(events) {
93
+ // Prefer the session_started event for stable metadata; fall back to first prompt
94
+ const candidates = events.filter((e) => e.event.endsWith('_session_started') || e.event.endsWith('_prompt_submitted'));
95
+ const src = candidates[0] ?? events[0];
96
+ const p = src.properties;
97
+ return {
98
+ repository: p.repository,
99
+ branch: p.branch,
100
+ model: p.model,
101
+ userEmail: p.user_email,
102
+ hasClaudeMd: p.has_claude_md,
103
+ hasCursorRules: p.has_cursor_rules,
104
+ hasAiRules: p.has_ai_rules,
105
+ isDirty: p.is_dirty,
106
+ modifiedFiles: p.modified_files,
107
+ stagedFiles: p.staged_files,
108
+ os: p.os,
109
+ nodeVersion: p.node_version,
110
+ };
111
+ }
112
+ buildTurns(events) {
113
+ const turns = [];
114
+ let promptIndex = 0;
115
+ for (const e of events) {
116
+ const p = e.properties;
117
+ if (e.event.endsWith('_prompt_submitted')) {
118
+ promptIndex++;
119
+ turns.push({
120
+ type: 'prompt',
121
+ index: promptIndex,
122
+ text: p.prompt ?? '[redacted]',
123
+ length: p.prompt_length ?? 0,
124
+ });
125
+ }
126
+ else if (e.event.endsWith('_tool_used') || e.event.endsWith('_tool_pre_use')) {
127
+ // Skip pre_use duplicates — only record the post-use result
128
+ if (e.event.endsWith('_tool_pre_use'))
129
+ continue;
130
+ turns.push({
131
+ type: 'tool_call',
132
+ name: p.tool_name ?? 'unknown',
133
+ exitCode: p.exit_code ?? null,
134
+ success: (p.exit_code ?? 0) === 0,
135
+ });
136
+ }
137
+ else if (e.event.endsWith('_agent_responded')) {
138
+ turns.push({
139
+ type: 'response',
140
+ length: p.response_length ?? 0,
141
+ });
142
+ }
143
+ else if (e.event.endsWith('_subagent_started')) {
144
+ turns.push({ type: 'subagent_start' });
145
+ }
146
+ else if (e.event.endsWith('_subagent_stopped')) {
147
+ turns.push({ type: 'subagent_stop' });
148
+ }
149
+ }
150
+ return turns;
151
+ }
152
+ computeStats(events, turns) {
153
+ const prompts = turns.filter((t) => t.type === 'prompt');
154
+ const toolCalls = turns.filter((t) => t.type === 'tool_call');
155
+ // Repeated: same tool name as the immediately preceding tool call
156
+ let repeated = 0;
157
+ for (let i = 1; i < toolCalls.length; i++) {
158
+ if (toolCalls[i].name === toolCalls[i - 1].name)
159
+ repeated++;
160
+ }
161
+ const startMs = new Date(events[0].timestamp).getTime();
162
+ const endMs = new Date(events[events.length - 1].timestamp).getTime();
163
+ return {
164
+ totalPrompts: prompts.length,
165
+ totalToolCalls: toolCalls.length,
166
+ toolFailures: toolCalls.filter((t) => !t.success).length,
167
+ repeatedToolCalls: repeated,
168
+ subagentCount: turns.filter((t) => t.type === 'subagent_start').length,
169
+ estimatedDurationMs: endMs - startMs,
170
+ };
171
+ }
172
+ }
173
+ exports.SessionBuilder = SessionBuilder;
174
+ //# sourceMappingURL=session-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-builder.js","sourceRoot":"","sources":["../../analysis/session-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ export type SessionTurnType = 'prompt' | 'tool_call' | 'response' | 'subagent_start' | 'subagent_stop';
2
+ export interface PromptTurn {
3
+ type: 'prompt';
4
+ index: number;
5
+ text: string;
6
+ length: number;
7
+ }
8
+ export interface ToolCallTurn {
9
+ type: 'tool_call';
10
+ name: string;
11
+ exitCode: number | null;
12
+ success: boolean;
13
+ }
14
+ export interface ResponseTurn {
15
+ type: 'response';
16
+ length: number;
17
+ }
18
+ export interface SubagentTurn {
19
+ type: 'subagent_start' | 'subagent_stop';
20
+ }
21
+ export type SessionTurn = PromptTurn | ToolCallTurn | ResponseTurn | SubagentTurn;
22
+ export interface SessionMetadata {
23
+ repository?: string;
24
+ branch?: string;
25
+ model?: string;
26
+ userEmail?: string;
27
+ hasClaudeMd?: boolean;
28
+ hasCursorRules?: boolean;
29
+ hasAiRules?: boolean;
30
+ isDirty?: boolean;
31
+ modifiedFiles?: number;
32
+ stagedFiles?: number;
33
+ os?: string;
34
+ nodeVersion?: string;
35
+ }
36
+ export interface SessionStats {
37
+ totalPrompts: number;
38
+ totalToolCalls: number;
39
+ toolFailures: number;
40
+ repeatedToolCalls: number;
41
+ subagentCount: number;
42
+ estimatedDurationMs: number;
43
+ }
44
+ export interface SessionContext {
45
+ sessionId: string;
46
+ provider: 'cursor' | 'claude' | 'unknown';
47
+ metadata: SessionMetadata;
48
+ turns: SessionTurn[];
49
+ stats: SessionStats;
50
+ startTime: string;
51
+ endTime: string;
52
+ }
53
+ export interface PatternToImprove {
54
+ name: string;
55
+ prompt_references: string[];
56
+ explanation: string;
57
+ rewrite: string;
58
+ }
59
+ export interface SessionScores {
60
+ prompt_clarity: number;
61
+ prompt_clarity_reason: string;
62
+ context_provision: number;
63
+ context_provision_reason: string;
64
+ session_efficiency: number;
65
+ session_efficiency_reason: string;
66
+ setup_and_tooling: number;
67
+ setup_and_tooling_reason: string;
68
+ }
69
+ export interface QuickWin {
70
+ action: string;
71
+ spec_sections_needed: string[];
72
+ }
73
+ export interface SessionFeedback {
74
+ overview: string;
75
+ context_setup: string;
76
+ patterns_to_improve: PatternToImprove[];
77
+ scores: SessionScores;
78
+ quick_win: QuickWin;
79
+ }
80
+ export interface UserReport {
81
+ userId: string;
82
+ period: string;
83
+ sessionsAnalyzed: number;
84
+ averageSessionScore: number;
85
+ recurring_weaknesses: string[];
86
+ top_improvements: string[];
87
+ progress_notes: string[];
88
+ session_summaries: Array<{
89
+ sessionId: string;
90
+ score: number;
91
+ summary: string;
92
+ }>;
93
+ }
94
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../analysis/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../analysis/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Pure helpers that identify which reusable "artifact" (skill / subagent /
3
+ * slash-command) a Claude Code event represents.
4
+ *
5
+ * Design constraints:
6
+ * - Zero dependencies, no IO, never throws — safe to call on the hook fast path.
7
+ * - Operates on RAW hook data (tool_name / tool_input / prompt) so it works
8
+ * even when `config.capture.prompts` is off (an artifact NAME is not a secret).
9
+ * - Reads only names, never argument payloads, so secrets in args never leak.
10
+ *
11
+ * Maps to the telemetry envelope in new-plan/tekdi_ai_sdlc_engineering_plan.md:
12
+ * artifact_type ∈ { skill, subagent, command }.
13
+ */
14
+ export type ArtifactType = 'skill' | 'subagent' | 'command';
15
+ export interface Artifact {
16
+ name: string;
17
+ type: ArtifactType;
18
+ /** Plugin namespace if the name is "plugin:artifact", else undefined. */
19
+ plugin?: string;
20
+ }
21
+ /**
22
+ * Map a tool invocation to a tracked artifact, or null if it isn't one.
23
+ * Skill -> { name: tool_input.skill, type: 'skill' }
24
+ * Agent | Task -> { name: tool_input.subagent_type, type: 'subagent' }
25
+ * anything else -> null
26
+ * Plugin skills (e.g. "pr-review-toolkit:review-pr") are captured verbatim.
27
+ */
28
+ export declare function extractArtifact(toolName: unknown, toolInput: unknown): Artifact | null;
29
+ /**
30
+ * Built-in Claude Code slash commands that are NOT reusable skills. These are
31
+ * pure-UI / session-control commands; counting them would pollute the adoption
32
+ * funnel. A denylist (not an allowlist) is used so that unknown user/plugin
33
+ * skills are still captured.
34
+ */
35
+ export declare const BUILTIN_COMMAND_DENYLIST: Set<string>;
36
+ /**
37
+ * The plugin namespace of an artifact name, or null if it isn't namespaced.
38
+ * "superpowers:brainstorming" -> "superpowers"
39
+ * "pr-review-toolkit:code-reviewer" -> "pr-review-toolkit"
40
+ * "explain-project" -> null (local/user artifact)
41
+ * Pure, never throws.
42
+ */
43
+ export declare function pluginOf(name: unknown): string | null;
44
+ /**
45
+ * Extract a slash-command name from prompt text. Handles BOTH forms Claude Code
46
+ * can pass to the UserPromptSubmit hook:
47
+ * - raw, as typed: "/explain-project some args" -> "explain-project"
48
+ * - expanded transcript: "<command-name>/explain-project</command-name> …"
49
+ * -> "explain-project"
50
+ * Returns the command NAME only — arguments are deliberately discarded so
51
+ * command args never enter telemetry. Denylisted built-ins and non-commands
52
+ * return null. Pure, never throws.
53
+ */
54
+ export declare function extractSlashCommand(promptText: unknown): string | null;
55
+ //# sourceMappingURL=artifact-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-extractor.d.ts","sourceRoot":"","sources":["../artifact-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;AAE5D,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,CAAC;IACnB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAmCD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAgBtF;AAED;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,aAKnC,CAAC;AAEH;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAMrD;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CA6BtE"}
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ /**
3
+ * Pure helpers that identify which reusable "artifact" (skill / subagent /
4
+ * slash-command) a Claude Code event represents.
5
+ *
6
+ * Design constraints:
7
+ * - Zero dependencies, no IO, never throws — safe to call on the hook fast path.
8
+ * - Operates on RAW hook data (tool_name / tool_input / prompt) so it works
9
+ * even when `config.capture.prompts` is off (an artifact NAME is not a secret).
10
+ * - Reads only names, never argument payloads, so secrets in args never leak.
11
+ *
12
+ * Maps to the telemetry envelope in new-plan/tekdi_ai_sdlc_engineering_plan.md:
13
+ * artifact_type ∈ { skill, subagent, command }.
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.BUILTIN_COMMAND_DENYLIST = void 0;
17
+ exports.extractArtifact = extractArtifact;
18
+ exports.pluginOf = pluginOf;
19
+ exports.extractSlashCommand = extractSlashCommand;
20
+ /**
21
+ * Coerce a hook `tool_input` into a plain object. Claude Code normally passes a
22
+ * parsed object, but be defensive: it may arrive as a JSON string, null, or a
23
+ * non-object. Never throws.
24
+ */
25
+ function asObject(toolInput) {
26
+ if (toolInput == null)
27
+ return null;
28
+ if (typeof toolInput === 'object')
29
+ return toolInput;
30
+ if (typeof toolInput === 'string') {
31
+ const s = toolInput.trim();
32
+ if (!s.startsWith('{'))
33
+ return null;
34
+ try {
35
+ const parsed = JSON.parse(s);
36
+ return parsed && typeof parsed === 'object' ? parsed : null;
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
42
+ return null;
43
+ }
44
+ function cleanName(value) {
45
+ if (typeof value !== 'string')
46
+ return null;
47
+ const trimmed = value.trim();
48
+ return trimmed.length > 0 ? trimmed : null;
49
+ }
50
+ /** Attach the plugin namespace (if any) derived from the artifact name. */
51
+ function withPlugin(artifact) {
52
+ const plugin = pluginOf(artifact.name);
53
+ return plugin ? { ...artifact, plugin } : artifact;
54
+ }
55
+ /**
56
+ * Map a tool invocation to a tracked artifact, or null if it isn't one.
57
+ * Skill -> { name: tool_input.skill, type: 'skill' }
58
+ * Agent | Task -> { name: tool_input.subagent_type, type: 'subagent' }
59
+ * anything else -> null
60
+ * Plugin skills (e.g. "pr-review-toolkit:review-pr") are captured verbatim.
61
+ */
62
+ function extractArtifact(toolName, toolInput) {
63
+ const name = typeof toolName === 'string' ? toolName.trim() : '';
64
+ if (!name)
65
+ return null;
66
+ if (name === 'Skill') {
67
+ const skill = cleanName(asObject(toolInput)?.skill);
68
+ return skill ? withPlugin({ name: skill, type: 'skill' }) : null;
69
+ }
70
+ // Claude Code has used both "Agent" and "Task" as the subagent tool name.
71
+ if (name === 'Agent' || name === 'Task') {
72
+ const sub = cleanName(asObject(toolInput)?.subagent_type);
73
+ return sub ? withPlugin({ name: sub, type: 'subagent' }) : null;
74
+ }
75
+ return null;
76
+ }
77
+ /**
78
+ * Built-in Claude Code slash commands that are NOT reusable skills. These are
79
+ * pure-UI / session-control commands; counting them would pollute the adoption
80
+ * funnel. A denylist (not an allowlist) is used so that unknown user/plugin
81
+ * skills are still captured.
82
+ */
83
+ exports.BUILTIN_COMMAND_DENYLIST = new Set([
84
+ 'clear', 'help', 'config', 'compact', 'cost', 'doctor', 'exit', 'quit',
85
+ 'login', 'logout', 'init', 'memory', 'model', 'status', 'resume', 'vim',
86
+ 'terminal-setup', 'add-dir', 'permissions', 'hooks', 'mcp', 'agents',
87
+ 'pr-comments', 'export', 'bug', 'release-notes', 'plugin', 'plugins',
88
+ ]);
89
+ /**
90
+ * The plugin namespace of an artifact name, or null if it isn't namespaced.
91
+ * "superpowers:brainstorming" -> "superpowers"
92
+ * "pr-review-toolkit:code-reviewer" -> "pr-review-toolkit"
93
+ * "explain-project" -> null (local/user artifact)
94
+ * Pure, never throws.
95
+ */
96
+ function pluginOf(name) {
97
+ if (typeof name !== 'string')
98
+ return null;
99
+ const i = name.indexOf(':');
100
+ if (i <= 0)
101
+ return null; // no colon, or leading colon (":x")
102
+ const plugin = name.slice(0, i).trim();
103
+ return plugin.length > 0 ? plugin : null;
104
+ }
105
+ /**
106
+ * Extract a slash-command name from prompt text. Handles BOTH forms Claude Code
107
+ * can pass to the UserPromptSubmit hook:
108
+ * - raw, as typed: "/explain-project some args" -> "explain-project"
109
+ * - expanded transcript: "<command-name>/explain-project</command-name> …"
110
+ * -> "explain-project"
111
+ * Returns the command NAME only — arguments are deliberately discarded so
112
+ * command args never enter telemetry. Denylisted built-ins and non-commands
113
+ * return null. Pure, never throws.
114
+ */
115
+ function extractSlashCommand(promptText) {
116
+ if (typeof promptText !== 'string')
117
+ return null;
118
+ let candidate = null;
119
+ // Expanded form: <command-name>/foo</command-name> (slash optional inside tag).
120
+ // Tag is always lowercase in Claude Code output — no /i flag, to avoid
121
+ // false-positives on prose that mentions "<COMMAND-NAME>" in caps.
122
+ const tag = promptText.match(/<command-name>\s*\/?\s*([^<\s]+)/);
123
+ if (tag) {
124
+ candidate = tag[1];
125
+ }
126
+ else {
127
+ // Raw form: must start with '/' (after leading whitespace).
128
+ const t = promptText.trimStart();
129
+ if (!t.startsWith('/'))
130
+ return null;
131
+ const m = t.match(/^\/([A-Za-z0-9][A-Za-z0-9_:-]*)/);
132
+ if (!m)
133
+ return null; // "/" alone, "//", "/ foo", etc.
134
+ candidate = m[1];
135
+ }
136
+ // Normalize + validate the captured token (strip any stray leading slash).
137
+ candidate = candidate.replace(/^\/+/, '');
138
+ if (!/^[A-Za-z0-9][A-Za-z0-9_:-]*$/.test(candidate))
139
+ return null;
140
+ // Denylist check is namespace-insensitive ("plugin:foo" -> check "foo").
141
+ const bare = candidate.includes(':') ? candidate.split(':').pop() : candidate;
142
+ if (exports.BUILTIN_COMMAND_DENYLIST.has(bare.toLowerCase()))
143
+ return null;
144
+ return candidate;
145
+ }
146
+ //# sourceMappingURL=artifact-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-extractor.js","sourceRoot":"","sources":["../artifact-extractor.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ export declare class ClaudeHooksReceiver {
2
2
  private enricher;
3
3
  private batcher;
4
4
  private config;
5
+ private pendingTranscriptEvents;
5
6
  constructor();
6
7
  private getEnricher;
7
8
  private getBatcher;
@@ -10,6 +11,25 @@ export declare class ClaudeHooksReceiver {
10
11
  handleEvent(hookType: string, eventData: any): Promise<void>;
11
12
  shutdown(): Promise<void>;
12
13
  private mapEvent;
14
+ private sessionsDir;
15
+ /** Path for a session's accumulator file, or null if session_id is unusable. */
16
+ private sessionFile;
17
+ /** Append one artifact name for a session. Best-effort; never throws. */
18
+ private recordArtifact;
19
+ /** Read, dedupe, and delete a session accumulator. Never throws; returns []. */
20
+ private readAndClearArtifacts;
21
+ /** Delete accumulator files from sessions that never reached Stop (>24h old). */
22
+ private reapStaleSessions;
23
+ private zeroTotals;
24
+ private cursorFile;
25
+ private readCursor;
26
+ private writeCursor;
27
+ /**
28
+ * Reads new transcript lines since the last cursor offset, emits
29
+ * claude_agent_responded/claude_agent_thought events, and folds token/message
30
+ * counts into the running totals. Best-effort; never throws on the hot path.
31
+ */
32
+ private ingestTranscript;
13
33
  private applyPrivacyFilters;
14
34
  private redactSecrets;
15
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"claude-hooks-receiver.d.ts","sourceRoot":"","sources":["../claude-hooks-receiver.ts"],"names":[],"mappings":"AAOA,qBAAa,mBAAmB;IAE9B,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,MAAM,CAAS;;IAMvB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,UAAU;IAKlB,0EAA0E;IACpE,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAU3D,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAoB5D,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B,OAAO,CAAC,QAAQ;IAgHhB,OAAO,CAAC,mBAAmB;IAU3B,OAAO,CAAC,aAAa;CAStB"}
1
+ {"version":3,"file":"claude-hooks-receiver.d.ts","sourceRoot":"","sources":["../claude-hooks-receiver.ts"],"names":[],"mappings":"AA+BA,qBAAa,mBAAmB;IAE9B,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,MAAM,CAAS;IAIvB,OAAO,CAAC,uBAAuB,CAAmB;;IAMlD,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,UAAU;IAKlB,0EAA0E;IACpE,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAe3D,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IA6B5D,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B,OAAO,CAAC,QAAQ;IA6LhB,OAAO,CAAC,WAAW;IAInB,gFAAgF;IAChF,OAAO,CAAC,WAAW;IAOnB,yEAAyE;IACzE,OAAO,CAAC,cAAc;IAatB,gFAAgF;IAChF,OAAO,CAAC,qBAAqB;IAsB7B,iFAAiF;IACjF,OAAO,CAAC,iBAAiB;IA2BzB,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,UAAU;IAgBlB,OAAO,CAAC,WAAW;IAenB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAoHxB,OAAO,CAAC,mBAAmB;IAgB3B,OAAO,CAAC,aAAa;CAStB"}