sidekick-shared 0.19.3 → 0.20.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/README.md CHANGED
@@ -33,7 +33,7 @@ npm install sidekick-shared
33
33
  | **Quota** | Claude Max subscription quota fetching (5-hour and 7-day windows) and Codex rate-limit extraction from event streams |
34
34
  | **Provider Status** | API health checking via status.claude.com and status.openai.com (indicator, components, incidents) |
35
35
  | **Schemas** | Zod schemas for runtime validation of data crossing process/IPC boundaries — JSONL session events (`sessionEventSchema`, `messageUsageSchema`, `sessionMessageSchema`), assistant turns, quota, account status, and quota history — plus `extractSessionEvents()` to unwrap `progress`-wrapped events. Also published fs-free via the [`sidekick-shared/schemas`](#supported-import-paths) subpath |
36
- | **Extractors** | Pure functions for single-event processing: `extractTokenUsage()`, `extractToolCall()` (top-level `tool_use`), `extractToolCalls()` (assistant content blocks) |
36
+ | **Extractors** | Pure functions for single-event processing: `extractTokenUsage()`, `extractToolCall()` (top-level `tool_use`), `extractToolCalls()` (assistant content blocks), plus Node-only session asset extraction (`gatherAssetsForCwd()`, `readClaudeAssets()`, `readCodexAssets()`) for URLs, file paths, commands, and plans |
37
37
  | **Model Info & Pricing** | Model family parsing (Anthropic / OpenAI / Google, including legacy `claude-3-opus-…` and `claude-3-5-sonnet-…` IDs), context-window lookup (including Fable 5 / Opus 4.8 / Opus 4.7 / Sonnet 4.7 1M and GPT-5.x variants), pricing tables with optional LiteLLM hydration, null-aware cost (`calculateCost()`), provenance-preserving cost (`calculateCostWithProvenance()`, `mergeCostSources()`), and display helpers (`shortModelName()`, `getModelDisplayInfo()`, `compareModelIds()`, `sortModelIds()`, `formatCost()`) |
38
38
  | **Quota Polling** | `QuotaPoller` class with exponential backoff, active/idle intervals, and cached fallback |
39
39
  | **Multi-Provider Quota** | `MultiProviderQuotaService` orchestrates Claude polling + peak-hours + account labels + Codex quota updates behind one typed `{ claude?, codex? }` event stream. `CodexQuotaWatcher` watches the active Codex rollout for live rate limits with snapshot fallback |
@@ -184,6 +184,33 @@ const tools = extractToolCalls(event); // ToolCall[] — assistant
184
184
  const toolFromEvent = extractToolCall(event); // ToolCall | null — top-level `tool_use` events
185
185
  ```
186
186
 
187
+ ### Extract actionable assets from recent sessions
188
+
189
+ Use the Node-only root API to collect URLs, filesystem-validated paths, commands the agent suggested for the user to run, and plan-mode plans from recent Claude Code and Codex sessions for exactly one working directory.
190
+
191
+ This API powers `sidekick extract` and was contributed by [@B33pBeeps](https://github.com/B33pBeeps) (Juan Fourie), adapted from his MIT-licensed [`trawl`](https://github.com/B33pBeeps/trawl) project.
192
+
193
+ ```typescript
194
+ import { gatherAssetsForCwd } from 'sidekick-shared';
195
+
196
+ const assets = gatherAssetsForCwd({
197
+ cwd: '/path/to/project',
198
+ agents: ['claude', 'codex'],
199
+ caps: { url: 20, path: 20, command: 20, plan: 10 },
200
+ });
201
+
202
+ console.log(assets.urls);
203
+ console.log(assets.paths);
204
+ console.log(assets.commands);
205
+ console.log(assets.plans);
206
+
207
+ // Each item keeps stable text/display fields plus optional provenance:
208
+ // { agent: 'claude' | 'codex', sessionPath, source }
209
+ console.log(assets.urls[0]?.agent);
210
+ ```
211
+
212
+ The extractor is safe for CLI and VS Code extension-host code, but not for browser or webview bundles because it reads session files and validates paths with Node filesystem APIs.
213
+
187
214
  ### Project session context evidence
188
215
 
189
216
  Build a provider-neutral snapshot of what an assistant has "seen" in a session — layered evidence sources, context pressure, and observed capabilities. Read it through any session provider, or build it directly from a canonical `SessionEvent[]`.
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Aggregate actionable assets for exactly one working directory.
3
+ *
4
+ * Portions adapted from `trawl` by Juan Fourie (B33pBeeps), MIT licensed:
5
+ * https://github.com/B33pBeeps/trawl
6
+ *
7
+ * @module extractors/gatherAssets
8
+ */
9
+ import { type AssetAgent, type ExtractedAssets, type ExtractedAssetType } from './sessionAssets';
10
+ export type { AssetAgent } from './sessionAssets';
11
+ export interface GatherAssetsOptions {
12
+ cwd?: string;
13
+ agents?: AssetAgent[];
14
+ sessionsPerAgent?: number;
15
+ caps?: Partial<Record<ExtractedAssetType, number>>;
16
+ }
17
+ export interface GatherAssetsResult extends ExtractedAssets {
18
+ inChat: boolean;
19
+ }
20
+ export declare function gatherAssetsForCwd(options?: GatherAssetsOptions): GatherAssetsResult;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ /**
3
+ * Aggregate actionable assets for exactly one working directory.
4
+ *
5
+ * Portions adapted from `trawl` by Juan Fourie (B33pBeeps), MIT licensed:
6
+ * https://github.com/B33pBeeps/trawl
7
+ *
8
+ * @module extractors/gatherAssets
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.gatherAssetsForCwd = gatherAssetsForCwd;
12
+ const node_path_1 = require("node:path");
13
+ const claudeAssets_1 = require("./sources/claudeAssets");
14
+ const codexAssets_1 = require("./sources/codexAssets");
15
+ const sessionAssets_1 = require("./sessionAssets");
16
+ const ALL_AGENTS = ['claude', 'codex'];
17
+ function gatherAssetsForCwd(options = {}) {
18
+ const cwd = (0, node_path_1.resolve)(options.cwd || process.cwd());
19
+ const sessionLimit = options.sessionsPerAgent ?? 3;
20
+ const agents = options.agents ?? ALL_AGENTS;
21
+ const caps = { ...sessionAssets_1.DEFAULT_CAPS, ...(options.caps || {}) };
22
+ const sources = [];
23
+ if (agents.includes('claude'))
24
+ sources.push((0, claudeAssets_1.readClaudeAssets)(cwd, sessionLimit));
25
+ if (agents.includes('codex'))
26
+ sources.push((0, codexAssets_1.readCodexAssets)(cwd, sessionLimit));
27
+ const merge = (key, cap) => (0, sessionAssets_1.capped)((0, sessionAssets_1.dedupeAssets)(sources.flatMap((source) => source[key]).sort(sessionAssets_1.byTimestampDesc)), cap);
28
+ return {
29
+ urls: merge('urls', caps.url),
30
+ paths: merge('paths', caps.path),
31
+ commands: merge('commands', caps.command),
32
+ plans: (0, sessionAssets_1.capped)((0, sessionAssets_1.dedupePlansByTitle)(sources.flatMap((source) => source.plans).sort(sessionAssets_1.byTimestampDesc)), caps.plan),
33
+ inChat: sources.some((source) => source.hadSession),
34
+ };
35
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Extract actionable assets from agent session transcript text.
3
+ *
4
+ * Portions adapted from `trawl` by Juan Fourie (B33pBeeps), MIT licensed:
5
+ * https://github.com/B33pBeeps/trawl
6
+ *
7
+ * @module extractors/sessionAssets
8
+ */
9
+ export type ExtractedAssetType = 'url' | 'path' | 'command' | 'plan';
10
+ export type AssetAgent = 'claude' | 'codex';
11
+ export interface ExtractedAssetProvenance {
12
+ agent?: AssetAgent;
13
+ sessionPath?: string;
14
+ source?: string;
15
+ }
16
+ export interface ExtractedAsset extends ExtractedAssetProvenance {
17
+ type: ExtractedAssetType;
18
+ text: string;
19
+ display: string;
20
+ timestamp?: string;
21
+ }
22
+ export interface ExtractedAssets {
23
+ urls: ExtractedAsset[];
24
+ paths: ExtractedAsset[];
25
+ commands: ExtractedAsset[];
26
+ plans: ExtractedAsset[];
27
+ }
28
+ export interface SourceAssets extends ExtractedAssets {
29
+ hadSession: boolean;
30
+ }
31
+ export declare const DEFAULT_CAPS: Record<ExtractedAssetType, number>;
32
+ export declare function extractUrls(text: unknown): string[];
33
+ export declare function extractFilePaths(text: unknown, cwd?: string): Array<{
34
+ file: string;
35
+ line?: number;
36
+ }>;
37
+ export declare function extractCommands(text: unknown): string[];
38
+ export declare function urlAsset(url: string, timestamp?: string, provenance?: ExtractedAssetProvenance): ExtractedAsset;
39
+ export declare function commandAsset(command: string, timestamp?: string, provenance?: ExtractedAssetProvenance): ExtractedAsset;
40
+ export declare function pathAsset(path: {
41
+ file: string;
42
+ line?: number;
43
+ }, timestamp?: string, provenance?: ExtractedAssetProvenance): ExtractedAsset;
44
+ export declare function planAsset(markdown: string, timestamp?: string, provenance?: ExtractedAssetProvenance): ExtractedAsset;
45
+ export declare function flat(value: string): string;
46
+ export declare function planTitle(markdown: string): string;
47
+ export declare function isExistingFile(filePath: string): boolean;
48
+ export declare function readPlanFile(filePath: string | undefined): string | undefined;
49
+ export declare function byTimestampDesc(a: ExtractedAsset, b: ExtractedAsset): number;
50
+ export declare function dedupeAssets(assets: ExtractedAsset[]): ExtractedAsset[];
51
+ export declare function dedupePlansByTitle(plans: ExtractedAsset[]): ExtractedAsset[];
52
+ export declare function capped(assets: ExtractedAsset[], cap: number): ExtractedAsset[];
@@ -0,0 +1,219 @@
1
+ "use strict";
2
+ /**
3
+ * Extract actionable assets from agent session transcript text.
4
+ *
5
+ * Portions adapted from `trawl` by Juan Fourie (B33pBeeps), MIT licensed:
6
+ * https://github.com/B33pBeeps/trawl
7
+ *
8
+ * @module extractors/sessionAssets
9
+ */
10
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ var desc = Object.getOwnPropertyDescriptor(m, k);
13
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
+ desc = { enumerable: true, get: function() { return m[k]; } };
15
+ }
16
+ Object.defineProperty(o, k2, desc);
17
+ }) : (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ o[k2] = m[k];
20
+ }));
21
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
23
+ }) : function(o, v) {
24
+ o["default"] = v;
25
+ });
26
+ var __importStar = (this && this.__importStar) || (function () {
27
+ var ownKeys = function(o) {
28
+ ownKeys = Object.getOwnPropertyNames || function (o) {
29
+ var ar = [];
30
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
31
+ return ar;
32
+ };
33
+ return ownKeys(o);
34
+ };
35
+ return function (mod) {
36
+ if (mod && mod.__esModule) return mod;
37
+ var result = {};
38
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
39
+ __setModuleDefault(result, mod);
40
+ return result;
41
+ };
42
+ })();
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.DEFAULT_CAPS = void 0;
45
+ exports.extractUrls = extractUrls;
46
+ exports.extractFilePaths = extractFilePaths;
47
+ exports.extractCommands = extractCommands;
48
+ exports.urlAsset = urlAsset;
49
+ exports.commandAsset = commandAsset;
50
+ exports.pathAsset = pathAsset;
51
+ exports.planAsset = planAsset;
52
+ exports.flat = flat;
53
+ exports.planTitle = planTitle;
54
+ exports.isExistingFile = isExistingFile;
55
+ exports.readPlanFile = readPlanFile;
56
+ exports.byTimestampDesc = byTimestampDesc;
57
+ exports.dedupeAssets = dedupeAssets;
58
+ exports.dedupePlansByTitle = dedupePlansByTitle;
59
+ exports.capped = capped;
60
+ const fs = __importStar(require("node:fs"));
61
+ const os = __importStar(require("node:os"));
62
+ const node_path_1 = require("node:path");
63
+ const URL_RE = /(?:https?|file):\/\/[^\s"'<>)\]`\\]+/g;
64
+ const PATH_RE = /(?:~|\.{0,2}\/)?[A-Za-z0-9_@.-]*(?:\/[A-Za-z0-9_@.-]+)+(?::\d+){0,2}|[A-Za-z0-9_@-]+\.[A-Za-z0-9]{1,8}(?::\d+){0,2}/g;
65
+ const SHELL_TAGS = new Set(['sh', 'bash', 'shell', 'zsh', 'console', 'shellscript', 'shell-session']);
66
+ exports.DEFAULT_CAPS = {
67
+ command: 60,
68
+ path: 60,
69
+ url: 40,
70
+ plan: 25,
71
+ };
72
+ function extractUrls(text) {
73
+ if (!text)
74
+ return [];
75
+ const urls = [];
76
+ for (const match of String(text).matchAll(URL_RE)) {
77
+ urls.push(match[0].replace(/[.,;:!?'"`]+$/, ''));
78
+ }
79
+ return urls;
80
+ }
81
+ function extractFilePaths(text, cwd) {
82
+ if (!text)
83
+ return [];
84
+ const home = os.homedir();
85
+ const base = cwd ? (0, node_path_1.resolve)(cwd) : process.cwd();
86
+ const paths = [];
87
+ for (const match of String(text).matchAll(PATH_RE)) {
88
+ let token = match[0].replace(/[.,;:)>"]+$/, '');
89
+ let line;
90
+ const lineMatch = /^(.+?):(\d+)(?::\d+)?$/.exec(token);
91
+ if (lineMatch) {
92
+ token = lineMatch[1];
93
+ line = Number(lineMatch[2]);
94
+ }
95
+ let file = token.startsWith('~') ? token.replace(/^~/, home) : token;
96
+ if (!(0, node_path_1.isAbsolute)(file))
97
+ file = (0, node_path_1.resolve)(base, file);
98
+ if (isExistingFile(file)) {
99
+ paths.push(line !== undefined ? { file, line } : { file });
100
+ }
101
+ }
102
+ return paths;
103
+ }
104
+ function extractCommands(text) {
105
+ if (!text)
106
+ return [];
107
+ const commands = [];
108
+ const source = String(text);
109
+ const fence = /```([\w.-]*)[ \t]*\r?\n([\s\S]*?)```/g;
110
+ const fencedSpans = [];
111
+ let match;
112
+ while ((match = fence.exec(source))) {
113
+ fencedSpans.push([match.index, fence.lastIndex]);
114
+ const shellTagged = SHELL_TAGS.has(match[1].toLowerCase());
115
+ let continuation = '';
116
+ for (const rawLine of match[2].split('\n')) {
117
+ const promptLine = /^\s*\$\s+(.+)$/.exec(rawLine);
118
+ if (promptLine) {
119
+ commands.push(promptLine[1].trim());
120
+ continue;
121
+ }
122
+ if (!shellTagged)
123
+ continue;
124
+ let line = rawLine.trim();
125
+ if (!line || line.startsWith('#'))
126
+ continue;
127
+ if (continuation) {
128
+ line = `${continuation} ${line}`;
129
+ continuation = '';
130
+ }
131
+ if (line.endsWith('\\')) {
132
+ continuation = line.slice(0, -1).trim();
133
+ continue;
134
+ }
135
+ commands.push(line);
136
+ }
137
+ }
138
+ for (const lineMatch of source.matchAll(/^[ \t]*\$[ \t]+(.+)$/gm)) {
139
+ const index = lineMatch.index ?? 0;
140
+ if (fencedSpans.some(([start, end]) => index >= start && index < end))
141
+ continue;
142
+ commands.push(lineMatch[1].trim());
143
+ }
144
+ return commands;
145
+ }
146
+ function urlAsset(url, timestamp, provenance = {}) {
147
+ return { type: 'url', text: url, display: url, timestamp, ...provenance };
148
+ }
149
+ function commandAsset(command, timestamp, provenance = {}) {
150
+ return { type: 'command', text: command, display: flat(command), timestamp, ...provenance };
151
+ }
152
+ function pathAsset(path, timestamp, provenance = {}) {
153
+ const text = path.line !== undefined ? `${path.file}:${path.line}` : path.file;
154
+ return { type: 'path', text, display: text, timestamp, ...provenance };
155
+ }
156
+ function planAsset(markdown, timestamp, provenance = {}) {
157
+ return { type: 'plan', text: markdown, display: planTitle(markdown), timestamp, ...provenance };
158
+ }
159
+ function flat(value) {
160
+ return value.replace(/\s*\n\s*/g, ' ').trim();
161
+ }
162
+ function planTitle(markdown) {
163
+ for (const rawLine of markdown.split('\n')) {
164
+ const line = rawLine.trim();
165
+ if (line)
166
+ return line.replace(/^#{1,6}\s*/, '');
167
+ }
168
+ return 'Plan';
169
+ }
170
+ function isExistingFile(filePath) {
171
+ try {
172
+ return fs.statSync(filePath).isFile();
173
+ }
174
+ catch {
175
+ return false;
176
+ }
177
+ }
178
+ function readPlanFile(filePath) {
179
+ if (!filePath)
180
+ return undefined;
181
+ try {
182
+ return fs.readFileSync(filePath, 'utf8');
183
+ }
184
+ catch {
185
+ return undefined;
186
+ }
187
+ }
188
+ function byTimestampDesc(a, b) {
189
+ return (b.timestamp || '').localeCompare(a.timestamp || '');
190
+ }
191
+ function dedupeAssets(assets) {
192
+ const seen = new Set();
193
+ const deduped = [];
194
+ for (const asset of assets) {
195
+ if (!asset.text)
196
+ continue;
197
+ const key = `${asset.type}\0${asset.text}`;
198
+ if (seen.has(key))
199
+ continue;
200
+ seen.add(key);
201
+ deduped.push(asset);
202
+ }
203
+ return deduped;
204
+ }
205
+ function dedupePlansByTitle(plans) {
206
+ const seen = new Set();
207
+ const deduped = [];
208
+ for (const plan of plans) {
209
+ const key = (plan.display || plan.text).trim().toLowerCase();
210
+ if (!key || seen.has(key))
211
+ continue;
212
+ seen.add(key);
213
+ deduped.push(plan);
214
+ }
215
+ return deduped;
216
+ }
217
+ function capped(assets, cap) {
218
+ return cap > 0 ? assets.slice(0, cap) : assets;
219
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Claude Code transcript reader for actionable asset extraction.
3
+ *
4
+ * Portions adapted from `trawl` by Juan Fourie (B33pBeeps), MIT licensed:
5
+ * https://github.com/B33pBeeps/trawl
6
+ *
7
+ * @module extractors/sources/claudeAssets
8
+ */
9
+ import { type SourceAssets } from '../sessionAssets';
10
+ export declare function claudeSessions(cwd: string, limit?: number): string[];
11
+ export declare function readClaudeAssets(cwd: string, limit?: number): SourceAssets;
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ /**
3
+ * Claude Code transcript reader for actionable asset extraction.
4
+ *
5
+ * Portions adapted from `trawl` by Juan Fourie (B33pBeeps), MIT licensed:
6
+ * https://github.com/B33pBeeps/trawl
7
+ *
8
+ * @module extractors/sources/claudeAssets
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.claudeSessions = claudeSessions;
12
+ exports.readClaudeAssets = readClaudeAssets;
13
+ const node_path_1 = require("node:path");
14
+ const node_fs_1 = require("node:fs");
15
+ const sessionPathResolver_1 = require("../../parsers/sessionPathResolver");
16
+ const sessionAssets_1 = require("../sessionAssets");
17
+ const PATH_TOOLS = new Set(['Read', 'Write', 'Edit', 'NotebookEdit']);
18
+ function dirExists(path) {
19
+ try {
20
+ return (0, node_fs_1.statSync)(path).isDirectory();
21
+ }
22
+ catch {
23
+ return false;
24
+ }
25
+ }
26
+ function filesByMtimeDesc(dir, filter) {
27
+ let names;
28
+ try {
29
+ names = (0, node_fs_1.readdirSync)(dir);
30
+ }
31
+ catch {
32
+ return [];
33
+ }
34
+ return names
35
+ .filter(filter)
36
+ .map((name) => (0, node_path_1.join)(dir, name))
37
+ .map((filePath) => {
38
+ try {
39
+ return { path: filePath, mtime: (0, node_fs_1.statSync)(filePath).mtimeMs };
40
+ }
41
+ catch {
42
+ return null;
43
+ }
44
+ })
45
+ .filter((entry) => entry !== null)
46
+ .sort((a, b) => b.mtime - a.mtime)
47
+ .map((entry) => entry.path);
48
+ }
49
+ function readJsonl(filePath) {
50
+ let raw;
51
+ try {
52
+ raw = (0, node_fs_1.readFileSync)(filePath, 'utf8');
53
+ }
54
+ catch {
55
+ return [];
56
+ }
57
+ const lines = [];
58
+ for (const line of raw.split('\n')) {
59
+ const trimmed = line.trim();
60
+ if (!trimmed)
61
+ continue;
62
+ try {
63
+ lines.push(JSON.parse(trimmed));
64
+ }
65
+ catch {
66
+ // Ignore partial or malformed JSONL lines.
67
+ }
68
+ }
69
+ return lines;
70
+ }
71
+ function claudeSessions(cwd, limit = 3) {
72
+ const dir = (0, sessionPathResolver_1.getSessionDirectory)(cwd);
73
+ if (!dirExists(dir))
74
+ return [];
75
+ return filesByMtimeDesc(dir, (name) => name.endsWith('.jsonl')).slice(0, limit);
76
+ }
77
+ function asString(value) {
78
+ return typeof value === 'string' ? value : undefined;
79
+ }
80
+ function provenance(sessionPath, source) {
81
+ return { agent: 'claude', sessionPath, source };
82
+ }
83
+ function addTextAssets(acc, text, cwd, timestamp, meta) {
84
+ for (const url of (0, sessionAssets_1.extractUrls)(text))
85
+ acc.urls.push((0, sessionAssets_1.urlAsset)(url, timestamp, meta));
86
+ for (const filePath of (0, sessionAssets_1.extractFilePaths)(text, cwd))
87
+ acc.paths.push((0, sessionAssets_1.pathAsset)(filePath, timestamp, meta));
88
+ for (const command of (0, sessionAssets_1.extractCommands)(text))
89
+ acc.commands.push((0, sessionAssets_1.commandAsset)(command, timestamp, meta));
90
+ }
91
+ function addToolPathAssets(acc, value, cwd, timestamp, meta) {
92
+ for (const filePath of (0, sessionAssets_1.extractFilePaths)(value, cwd)) {
93
+ acc.paths.push((0, sessionAssets_1.pathAsset)(filePath, timestamp, meta));
94
+ }
95
+ }
96
+ function accumClaude(filePath, cwd, acc) {
97
+ for (const line of readJsonl(filePath)) {
98
+ const timestamp = asString(line.timestamp);
99
+ if (line.type === 'attachment') {
100
+ const attachment = line.attachment;
101
+ const planFilePath = asString(attachment?.planFilePath);
102
+ if (planFilePath && (0, sessionAssets_1.isExistingFile)(planFilePath)) {
103
+ const text = (0, sessionAssets_1.readPlanFile)(planFilePath);
104
+ if (text?.trim())
105
+ acc.plans.push((0, sessionAssets_1.planAsset)(text, timestamp, provenance(filePath, 'attachment:plan')));
106
+ }
107
+ continue;
108
+ }
109
+ const message = line.message;
110
+ const content = message?.content;
111
+ if (typeof content === 'string') {
112
+ addTextAssets(acc, content, cwd, timestamp, provenance(filePath, 'message'));
113
+ continue;
114
+ }
115
+ if (!Array.isArray(content))
116
+ continue;
117
+ for (const block of content) {
118
+ const typedBlock = block;
119
+ if (typedBlock.type === 'text') {
120
+ addTextAssets(acc, typedBlock.text, cwd, timestamp, provenance(filePath, 'message'));
121
+ continue;
122
+ }
123
+ if (typedBlock.type !== 'tool_use')
124
+ continue;
125
+ const name = asString(typedBlock.name);
126
+ const input = typedBlock.input || {};
127
+ const toolSource = name ? `tool:${name}` : 'tool';
128
+ const toolMeta = provenance(filePath, toolSource);
129
+ if (name === 'Bash') {
130
+ for (const url of (0, sessionAssets_1.extractUrls)(input.command))
131
+ acc.urls.push((0, sessionAssets_1.urlAsset)(url, timestamp, toolMeta));
132
+ addToolPathAssets(acc, input.command, cwd, timestamp, toolMeta);
133
+ }
134
+ else if (name && PATH_TOOLS.has(name)) {
135
+ addToolPathAssets(acc, input.file_path, cwd, timestamp, toolMeta);
136
+ }
137
+ else if (name === 'WebFetch' || name === 'WebSearch') {
138
+ for (const url of (0, sessionAssets_1.extractUrls)(JSON.stringify(input)))
139
+ acc.urls.push((0, sessionAssets_1.urlAsset)(url, timestamp, toolMeta));
140
+ }
141
+ else if (name === 'ExitPlanMode') {
142
+ const inline = asString(input.plan);
143
+ const markdown = inline?.trim() ? inline : (0, sessionAssets_1.readPlanFile)(asString(input.planFilePath));
144
+ if (markdown?.trim())
145
+ acc.plans.push((0, sessionAssets_1.planAsset)(markdown, timestamp, toolMeta));
146
+ }
147
+ }
148
+ }
149
+ }
150
+ function readClaudeAssets(cwd, limit = 3) {
151
+ const sessions = claudeSessions(cwd, limit);
152
+ const acc = { urls: [], paths: [], commands: [], plans: [], hadSession: sessions.length > 0 };
153
+ for (const session of sessions)
154
+ accumClaude(session, cwd, acc);
155
+ return acc;
156
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Codex CLI rollout reader for actionable asset extraction.
3
+ *
4
+ * Portions adapted from `trawl` by Juan Fourie (B33pBeeps), MIT licensed:
5
+ * https://github.com/B33pBeeps/trawl
6
+ *
7
+ * @module extractors/sources/codexAssets
8
+ */
9
+ import { type SourceAssets } from '../sessionAssets';
10
+ export declare function codexSessions(cwd: string, limit?: number): string[];
11
+ export declare function readCodexAssets(cwd: string, limit?: number): SourceAssets;
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+ /**
3
+ * Codex CLI rollout reader for actionable asset extraction.
4
+ *
5
+ * Portions adapted from `trawl` by Juan Fourie (B33pBeeps), MIT licensed:
6
+ * https://github.com/B33pBeeps/trawl
7
+ *
8
+ * @module extractors/sources/codexAssets
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.codexSessions = codexSessions;
12
+ exports.readCodexAssets = readCodexAssets;
13
+ const node_path_1 = require("node:path");
14
+ const node_fs_1 = require("node:fs");
15
+ const codexProfiles_1 = require("../../codexProfiles");
16
+ const sessionAssets_1 = require("../sessionAssets");
17
+ const EXEC_NAMES = new Set(['exec_command', 'shell', 'local_shell', 'container.exec']);
18
+ function dirExists(path) {
19
+ try {
20
+ return (0, node_fs_1.statSync)(path).isDirectory();
21
+ }
22
+ catch {
23
+ return false;
24
+ }
25
+ }
26
+ function firstJsonLine(filePath) {
27
+ let fd;
28
+ try {
29
+ fd = (0, node_fs_1.openSync)(filePath, 'r');
30
+ }
31
+ catch {
32
+ return null;
33
+ }
34
+ const buffer = Buffer.alloc(65536);
35
+ let data = '';
36
+ try {
37
+ let bytesRead;
38
+ while ((bytesRead = (0, node_fs_1.readSync)(fd, buffer, 0, buffer.length, null)) > 0) {
39
+ data += buffer.toString('utf8', 0, bytesRead);
40
+ const newlineIndex = data.indexOf('\n');
41
+ if (newlineIndex >= 0) {
42
+ data = data.slice(0, newlineIndex);
43
+ break;
44
+ }
45
+ if (data.length > 1_000_000)
46
+ break;
47
+ }
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ finally {
53
+ (0, node_fs_1.closeSync)(fd);
54
+ }
55
+ try {
56
+ return JSON.parse(data);
57
+ }
58
+ catch {
59
+ return null;
60
+ }
61
+ }
62
+ function readJsonl(filePath, skip) {
63
+ let raw;
64
+ try {
65
+ raw = (0, node_fs_1.readFileSync)(filePath, 'utf8');
66
+ }
67
+ catch {
68
+ return [];
69
+ }
70
+ const lines = [];
71
+ for (const line of raw.split('\n')) {
72
+ const trimmed = line.trim();
73
+ if (!trimmed)
74
+ continue;
75
+ if (skip?.(trimmed))
76
+ continue;
77
+ try {
78
+ lines.push(JSON.parse(trimmed));
79
+ }
80
+ catch {
81
+ // Ignore partial or malformed JSONL lines.
82
+ }
83
+ }
84
+ return lines;
85
+ }
86
+ function rolloutFiles(limit = 150) {
87
+ const entries = [];
88
+ const seen = new Set();
89
+ const walk = (dir) => {
90
+ let dirEntries;
91
+ try {
92
+ dirEntries = (0, node_fs_1.readdirSync)(dir, { withFileTypes: true });
93
+ }
94
+ catch {
95
+ return;
96
+ }
97
+ for (const entry of dirEntries) {
98
+ const fullPath = (0, node_path_1.join)(dir, entry.name);
99
+ if (entry.isDirectory()) {
100
+ walk(fullPath);
101
+ }
102
+ else if (entry.isFile() && entry.name.startsWith('rollout-') && entry.name.endsWith('.jsonl')) {
103
+ try {
104
+ if (seen.has(fullPath))
105
+ continue;
106
+ seen.add(fullPath);
107
+ entries.push({ path: fullPath, mtime: (0, node_fs_1.statSync)(fullPath).mtimeMs });
108
+ }
109
+ catch {
110
+ // Ignore inaccessible files.
111
+ }
112
+ }
113
+ }
114
+ };
115
+ for (const home of (0, codexProfiles_1.getCodexMonitoringHomes)()) {
116
+ const sessionsDir = (0, node_path_1.join)(home, 'sessions');
117
+ if (dirExists(sessionsDir))
118
+ walk(sessionsDir);
119
+ }
120
+ return entries.sort((a, b) => b.mtime - a.mtime).slice(0, limit).map((entry) => entry.path);
121
+ }
122
+ function codexSessions(cwd, limit = 3) {
123
+ const exactCwd = (0, node_path_1.resolve)(cwd);
124
+ const sessions = [];
125
+ for (const filePath of rolloutFiles()) {
126
+ const meta = firstJsonLine(filePath);
127
+ const payload = meta?.payload;
128
+ if (payload?.cwd === exactCwd) {
129
+ sessions.push(filePath);
130
+ if (sessions.length >= limit)
131
+ break;
132
+ }
133
+ }
134
+ return sessions;
135
+ }
136
+ function parseArgs(value) {
137
+ if (typeof value !== 'string')
138
+ return value && typeof value === 'object' ? value : {};
139
+ try {
140
+ return JSON.parse(value);
141
+ }
142
+ catch {
143
+ return {};
144
+ }
145
+ }
146
+ function asString(value) {
147
+ return typeof value === 'string' ? value : undefined;
148
+ }
149
+ function provenance(sessionPath, source) {
150
+ return { agent: 'codex', sessionPath, source };
151
+ }
152
+ function commandFromLocalShell(item) {
153
+ const action = item.action;
154
+ const command = action?.command;
155
+ if (Array.isArray(command))
156
+ return command.map(String).join(' ');
157
+ return asString(command);
158
+ }
159
+ function patchFiles(patch, cwd) {
160
+ const paths = [];
161
+ for (const match of String(patch).matchAll(/^\*\*\* (?:Update|Add|Delete) File: (.+)$/gm)) {
162
+ for (const filePath of (0, sessionAssets_1.extractFilePaths)(match[1].trim(), cwd)) {
163
+ paths.push(filePath);
164
+ }
165
+ }
166
+ return paths;
167
+ }
168
+ function addMessageAssets(acc, text, cwd, timestamp, meta) {
169
+ for (const url of (0, sessionAssets_1.extractUrls)(text))
170
+ acc.urls.push((0, sessionAssets_1.urlAsset)(url, timestamp, meta));
171
+ for (const filePath of (0, sessionAssets_1.extractFilePaths)(text, cwd))
172
+ acc.paths.push((0, sessionAssets_1.pathAsset)(filePath, timestamp, meta));
173
+ for (const command of (0, sessionAssets_1.extractCommands)(text))
174
+ acc.commands.push((0, sessionAssets_1.commandAsset)(command, timestamp, meta));
175
+ }
176
+ function addExecutedCommandAssets(acc, command, cwd, timestamp, meta) {
177
+ for (const url of (0, sessionAssets_1.extractUrls)(command))
178
+ acc.urls.push((0, sessionAssets_1.urlAsset)(url, timestamp, meta));
179
+ for (const filePath of (0, sessionAssets_1.extractFilePaths)(command, cwd))
180
+ acc.paths.push((0, sessionAssets_1.pathAsset)(filePath, timestamp, meta));
181
+ }
182
+ function readCodexAssets(cwd, limit = 3) {
183
+ const exactCwd = (0, node_path_1.resolve)(cwd);
184
+ const files = codexSessions(exactCwd, limit);
185
+ const acc = { urls: [], paths: [], commands: [], plans: [], hadSession: files.length > 0 };
186
+ const skip = (line) => line.includes('"type":"function_call_output"') ||
187
+ line.includes('"type":"reasoning"') ||
188
+ line.includes('"type":"token_count"');
189
+ for (const filePath of files) {
190
+ for (const line of readJsonl(filePath, skip)) {
191
+ const payload = line.payload;
192
+ if (!payload)
193
+ continue;
194
+ const timestamp = asString(line.timestamp);
195
+ if (payload.type === 'function_call') {
196
+ if (EXEC_NAMES.has(payload.name)) {
197
+ const args = parseArgs(payload.arguments);
198
+ addExecutedCommandAssets(acc, args.cmd ?? args.command, exactCwd, timestamp, provenance(filePath, `tool:${String(payload.name)}`));
199
+ }
200
+ }
201
+ else if (payload.type === 'local_shell_call') {
202
+ addExecutedCommandAssets(acc, commandFromLocalShell(payload), exactCwd, timestamp, provenance(filePath, 'tool:local_shell'));
203
+ }
204
+ else if (payload.type === 'item_completed') {
205
+ const item = payload.item;
206
+ const text = asString(item?.text);
207
+ if (item?.type === 'Plan' && text?.trim())
208
+ acc.plans.push((0, sessionAssets_1.planAsset)(text, timestamp, provenance(filePath, 'plan')));
209
+ }
210
+ else if (payload.type === 'custom_tool_call' && payload.name === 'apply_patch') {
211
+ const meta = provenance(filePath, 'tool:apply_patch');
212
+ for (const file of patchFiles(payload.input, exactCwd))
213
+ acc.paths.push((0, sessionAssets_1.pathAsset)(file, timestamp, meta));
214
+ }
215
+ else if (payload.type === 'message' && Array.isArray(payload.content)) {
216
+ for (const block of payload.content) {
217
+ const typedBlock = block;
218
+ addMessageAssets(acc, typedBlock.text, exactCwd, timestamp, provenance(filePath, 'message'));
219
+ }
220
+ }
221
+ else if (payload.type === 'agent_message') {
222
+ addMessageAssets(acc, payload.message, exactCwd, timestamp, provenance(filePath, 'message'));
223
+ }
224
+ }
225
+ }
226
+ return acc;
227
+ }
package/dist/index.d.ts CHANGED
@@ -124,6 +124,12 @@ export { hydratePricingCatalog, normalizeLiteLlmCatalog, LITELLM_CATALOG_URL } f
124
124
  export type { HydrateOptions, HydrateResult } from './pricingCatalog';
125
125
  export { extractTokenUsage } from './extractors/tokenUsage';
126
126
  export { extractToolCall, extractToolCalls } from './extractors/toolCall';
127
+ export { extractUrls, extractFilePaths, extractCommands, } from './extractors/sessionAssets';
128
+ export type { AssetAgent, ExtractedAsset, ExtractedAssetProvenance, ExtractedAssetType, ExtractedAssets, SourceAssets, } from './extractors/sessionAssets';
129
+ export { readClaudeAssets, claudeSessions } from './extractors/sources/claudeAssets';
130
+ export { readCodexAssets, codexSessions } from './extractors/sources/codexAssets';
131
+ export { gatherAssetsForCwd } from './extractors/gatherAssets';
132
+ export type { GatherAssetsOptions, GatherAssetsResult } from './extractors/gatherAssets';
127
133
  export { messageUsageSchema, sessionMessageSchema, sessionEventSchema, permissionModeSchema, extractSessionEvents, } from './schemas/sessionEvent';
128
134
  export { quotaWindowSchema, quotaStateSchema, quotaFailureKindSchema, quotaProviderIdSchema, quotaSourceSchema, peakHoursStateSchema, quotaFailureDescriptorSchema, runtimeQuotaProviderSchema, providerQuotaStateSchema, claudeProviderQuotaStateSchema, codexProviderQuotaStateSchema, providerQuotaMapSchema, } from './schemas/quota';
129
135
  export { quotaHistoryRuntimeProviderSchema, quotaHistorySampleSchema, quotaHistoryDailyBucketSchema, } from './schemas/quotaHistory';
package/dist/index.js CHANGED
@@ -6,8 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.findActiveClaudeSession = exports.discoverSessionDirectory = exports.getClaudeSessionDirectory = exports.encodeClaudeWorkspacePath = exports.detectSessionActivity = exports.extractTaskInfo = exports.scanSubagentDir = exports.normalizeCodexToolInput = exports.normalizeCodexToolName = exports.extractPatchFilePaths = exports.CodexRolloutParser = exports.parseDbPartData = exports.parseDbMessageData = exports.convertOpenCodeMessage = exports.detectPlanModeFromText = exports.normalizeToolInput = exports.normalizeToolName = exports.TRUNCATION_PATTERNS = exports.JsonlParser = exports.CodexProvider = exports.OpenCodeProvider = exports.ClaudeCodeProvider = exports.getAllDetectedProviders = exports.detectProvider = exports.readClaudeCodePlanFiles = exports.getPlanAnalytics = exports.writePlans = exports.getLatestPlan = exports.readPlans = exports.readLatestHandoff = exports.readHistory = exports.readNotes = exports.readDecisions = exports.readTasks = exports.getProjectSlugRaw = exports.getProjectSlug = exports.encodeWorkspacePath = exports.getGlobalDataPath = exports.getProjectDataPath = exports.getConfigDir = exports.MAX_PLANS_PER_PROJECT = exports.PLAN_SCHEMA_VERSION = exports.createEmptyTokenTotals = exports.HISTORICAL_DATA_SCHEMA_VERSION = exports.STALENESS_THRESHOLDS = exports.IMPORTANCE_DECAY_FACTORS = exports.KNOWLEDGE_NOTE_SCHEMA_VERSION = exports.DECISION_LOG_SCHEMA_VERSION = exports.normalizeTaskStatus = exports.TASK_PERSISTENCE_SCHEMA_VERSION = void 0;
7
7
  exports.clearHighlightCache = exports.highlightEvent = exports.formatSessionJson = exports.formatSessionMarkdown = exports.formatSessionText = exports.classifyNoise = exports.shouldMergeWithPrevious = exports.classifyFollowEvent = exports.classifyMessage = exports.getSoftNoiseReason = exports.isHardNoiseFollowEvent = exports.isHardNoise = exports.formatToolSummary = exports.formatTokenCount = exports.formatDurationMs = exports.createJsonlTail = exports.toFollowEvents = exports.createWatcher = exports.parseChangelog = exports.extractProposedPlanShared = exports.parsePlanMarkdownShared = exports.PlanExtractor = exports.segmentAssistantTurn = exports.reasoningSummary = exports.isAssistantTurnSubagentTool = exports.extractTurnSubagents = exports.assistantTurnEventsFromSessionEvents = exports.readSessionContextSnapshot = exports.createSessionContextProjector = exports.calculateSessionContextPressure = exports.buildSessionContextSnapshot = exports.composeContext = exports.FilterEngine = exports.searchSessions = exports.CodexDatabase = exports.OpenCodeDatabase = exports.discoverDebugLogs = exports.collapseDuplicates = exports.filterByLevel = exports.parseDebugLog = exports.scanSubagentTraces = exports.findAllSessionsWithWorktrees = exports.discoverWorktreeSiblings = exports.resolveWorktreeMainRepo = exports.getAllClaudeProjectFolders = exports.decodeEncodedPath = exports.getMostRecentlyActiveSessionDir = exports.findSubdirectorySessionDirs = exports.findSessionsInDirectory = exports.findAllClaudeSessions = void 0;
8
8
  exports.getCodexExecutionEnv = exports.resolveSidekickCodexHome = exports.getActiveCodexAccount = exports.listCodexAccounts = exports.getSystemCodexHome = exports.getCodexMonitoringHomes = exports.getCodexProfileHome = exports.getCodexProfilesDir = exports.getActiveAccountStatus = exports.removeSavedAccountProfile = exports.replaceSavedAccountProfiles = exports.setActiveSavedAccount = exports.upsertSavedAccountProfile = exports.getActiveSavedAccount = exports.listSavedAccountProfiles = exports.writeSavedAccountRegistry = exports.readSavedAccountRegistry = exports.getAccountsDir = exports.isMultiAccountEnabled = exports.getActiveAccount = exports.listAccounts = exports.removeAccount = exports.switchToAccount = exports.addCurrentAccount = exports.readActiveClaudeAccount = exports.writeAccountRegistry = exports.readAccountRegistry = exports.ensureDefaultAccounts = exports.readClaudeMaxAccessTokenSync = exports.readClaudeMaxCredentials = exports.writeActiveCredentials = exports.readActiveCredentials = exports.openInBrowser = exports.parseTranscriptFromEvents = exports.parseTranscript = exports.generateHtmlReport = exports.PatternExtractor = exports.HeatmapTracker = exports.FrequencyTracker = exports.getSnapshotPath = exports.isSnapshotValid = exports.deleteSnapshot = exports.loadSnapshot = exports.saveSnapshot = exports.parseTodoDependencies = exports.EventAggregator = exports.getRandomPhrase = exports.PHRASE_CATEGORIES = exports.ALL_PHRASES = exports.HIGHLIGHT_CSS = void 0;
9
- exports.quotaProviderIdSchema = exports.quotaFailureKindSchema = exports.quotaStateSchema = exports.quotaWindowSchema = exports.extractSessionEvents = exports.permissionModeSchema = exports.sessionEventSchema = exports.sessionMessageSchema = exports.messageUsageSchema = exports.extractToolCalls = exports.extractToolCall = exports.extractTokenUsage = exports.LITELLM_CATALOG_URL = exports.normalizeLiteLlmCatalog = exports.hydratePricingCatalog = exports.formatCost = exports.sortModelIds = exports.compareModelIds = exports.getModelDisplayInfo = exports.shortModelName = exports.mergeCostSources = exports.calculateCostWithProvenance = exports.calculateCostWithPricing = exports.calculateCost = exports.getModelInfo = exports.getModelPricing = exports.parseModelId = exports.DEFAULT_CONTEXT_WINDOW = exports.getModelContextWindowSize = exports.MultiProviderQuotaService = exports.CodexQuotaWatcher = exports.resolveCodexQuotaFromLocalSources = exports.resolveCodexQuota = exports.readLatestCodexQuotaFromRollouts = exports.quotaFromCodexRateLimits = exports.fetchCodexQuotaFromApi = exports.getWorkspaceIdFromPath = exports.pruneQuotaHistory = exports.readQuotaHistoryDailyBuckets = exports.readQuotaHistoryRange = exports.appendQuotaHistorySample = exports.writeQuotaSnapshot = exports.readQuotaSnapshot = exports.QuotaPoller = exports.describeQuotaFailure = exports.fetchQuota = exports.removeCodexAccount = exports.switchToCodexAccount = exports.finalizeCodexAccount = exports.prepareCodexAccount = void 0;
10
- exports.scopePeakHoursToSessionProvider = exports.isClaudeCodeSessionProvider = exports.fetchPeakHoursStatus = exports.createPeakHoursNotApplicableState = exports.fetchOpenAIStatus = exports.fetchProviderStatus = exports.assistantTurnToolRefSchema = exports.assistantTurnToolGroupStepSchema = exports.assistantTurnTimelineItemSchema = exports.assistantTurnSubagentStatusSchema = exports.assistantTurnSubagentSchema = exports.assistantTurnReasoningTimelineItemSchema = exports.assistantTurnProjectionSchema = exports.assistantTurnProcessStepSchema = exports.assistantTurnProcessSchema = exports.assistantTurnNarrationStepSchema = exports.assistantTurnEventTypeSchema = exports.assistantTurnEventSchema = exports.activeAccountStatusSchema = exports.activeProviderAccountStatusSchema = exports.quotaHistoryDailyBucketSchema = exports.quotaHistorySampleSchema = exports.quotaHistoryRuntimeProviderSchema = exports.providerQuotaMapSchema = exports.codexProviderQuotaStateSchema = exports.claudeProviderQuotaStateSchema = exports.providerQuotaStateSchema = exports.runtimeQuotaProviderSchema = exports.quotaFailureDescriptorSchema = exports.peakHoursStateSchema = exports.quotaSourceSchema = void 0;
9
+ exports.messageUsageSchema = exports.gatherAssetsForCwd = exports.codexSessions = exports.readCodexAssets = exports.claudeSessions = exports.readClaudeAssets = exports.extractCommands = exports.extractFilePaths = exports.extractUrls = exports.extractToolCalls = exports.extractToolCall = exports.extractTokenUsage = exports.LITELLM_CATALOG_URL = exports.normalizeLiteLlmCatalog = exports.hydratePricingCatalog = exports.formatCost = exports.sortModelIds = exports.compareModelIds = exports.getModelDisplayInfo = exports.shortModelName = exports.mergeCostSources = exports.calculateCostWithProvenance = exports.calculateCostWithPricing = exports.calculateCost = exports.getModelInfo = exports.getModelPricing = exports.parseModelId = exports.DEFAULT_CONTEXT_WINDOW = exports.getModelContextWindowSize = exports.MultiProviderQuotaService = exports.CodexQuotaWatcher = exports.resolveCodexQuotaFromLocalSources = exports.resolveCodexQuota = exports.readLatestCodexQuotaFromRollouts = exports.quotaFromCodexRateLimits = exports.fetchCodexQuotaFromApi = exports.getWorkspaceIdFromPath = exports.pruneQuotaHistory = exports.readQuotaHistoryDailyBuckets = exports.readQuotaHistoryRange = exports.appendQuotaHistorySample = exports.writeQuotaSnapshot = exports.readQuotaSnapshot = exports.QuotaPoller = exports.describeQuotaFailure = exports.fetchQuota = exports.removeCodexAccount = exports.switchToCodexAccount = exports.finalizeCodexAccount = exports.prepareCodexAccount = void 0;
10
+ exports.scopePeakHoursToSessionProvider = exports.isClaudeCodeSessionProvider = exports.fetchPeakHoursStatus = exports.createPeakHoursNotApplicableState = exports.fetchOpenAIStatus = exports.fetchProviderStatus = exports.assistantTurnToolRefSchema = exports.assistantTurnToolGroupStepSchema = exports.assistantTurnTimelineItemSchema = exports.assistantTurnSubagentStatusSchema = exports.assistantTurnSubagentSchema = exports.assistantTurnReasoningTimelineItemSchema = exports.assistantTurnProjectionSchema = exports.assistantTurnProcessStepSchema = exports.assistantTurnProcessSchema = exports.assistantTurnNarrationStepSchema = exports.assistantTurnEventTypeSchema = exports.assistantTurnEventSchema = exports.activeAccountStatusSchema = exports.activeProviderAccountStatusSchema = exports.quotaHistoryDailyBucketSchema = exports.quotaHistorySampleSchema = exports.quotaHistoryRuntimeProviderSchema = exports.providerQuotaMapSchema = exports.codexProviderQuotaStateSchema = exports.claudeProviderQuotaStateSchema = exports.providerQuotaStateSchema = exports.runtimeQuotaProviderSchema = exports.quotaFailureDescriptorSchema = exports.peakHoursStateSchema = exports.quotaSourceSchema = exports.quotaProviderIdSchema = exports.quotaFailureKindSchema = exports.quotaStateSchema = exports.quotaWindowSchema = exports.extractSessionEvents = exports.permissionModeSchema = exports.sessionEventSchema = exports.sessionMessageSchema = void 0;
11
11
  var taskPersistence_1 = require("./types/taskPersistence");
12
12
  Object.defineProperty(exports, "TASK_PERSISTENCE_SCHEMA_VERSION", { enumerable: true, get: function () { return taskPersistence_1.TASK_PERSISTENCE_SCHEMA_VERSION; } });
13
13
  Object.defineProperty(exports, "normalizeTaskStatus", { enumerable: true, get: function () { return taskPersistence_1.normalizeTaskStatus; } });
@@ -297,6 +297,20 @@ Object.defineProperty(exports, "extractTokenUsage", { enumerable: true, get: fun
297
297
  var toolCall_1 = require("./extractors/toolCall");
298
298
  Object.defineProperty(exports, "extractToolCall", { enumerable: true, get: function () { return toolCall_1.extractToolCall; } });
299
299
  Object.defineProperty(exports, "extractToolCalls", { enumerable: true, get: function () { return toolCall_1.extractToolCalls; } });
300
+ // Extractors — actionable session assets. Node-only: safe for CLI and
301
+ // extension-host code, not for browser/webview bundles.
302
+ var sessionAssets_1 = require("./extractors/sessionAssets");
303
+ Object.defineProperty(exports, "extractUrls", { enumerable: true, get: function () { return sessionAssets_1.extractUrls; } });
304
+ Object.defineProperty(exports, "extractFilePaths", { enumerable: true, get: function () { return sessionAssets_1.extractFilePaths; } });
305
+ Object.defineProperty(exports, "extractCommands", { enumerable: true, get: function () { return sessionAssets_1.extractCommands; } });
306
+ var claudeAssets_1 = require("./extractors/sources/claudeAssets");
307
+ Object.defineProperty(exports, "readClaudeAssets", { enumerable: true, get: function () { return claudeAssets_1.readClaudeAssets; } });
308
+ Object.defineProperty(exports, "claudeSessions", { enumerable: true, get: function () { return claudeAssets_1.claudeSessions; } });
309
+ var codexAssets_1 = require("./extractors/sources/codexAssets");
310
+ Object.defineProperty(exports, "readCodexAssets", { enumerable: true, get: function () { return codexAssets_1.readCodexAssets; } });
311
+ Object.defineProperty(exports, "codexSessions", { enumerable: true, get: function () { return codexAssets_1.codexSessions; } });
312
+ var gatherAssets_1 = require("./extractors/gatherAssets");
313
+ Object.defineProperty(exports, "gatherAssetsForCwd", { enumerable: true, get: function () { return gatherAssets_1.gatherAssetsForCwd; } });
300
314
  // Schemas — Zod runtime validation for session events
301
315
  var sessionEvent_1 = require("./schemas/sessionEvent");
302
316
  Object.defineProperty(exports, "messageUsageSchema", { enumerable: true, get: function () { return sessionEvent_1.messageUsageSchema; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sidekick-shared",
3
- "version": "0.19.3",
3
+ "version": "0.20.0",
4
4
  "description": "Shared data access layer for Sidekick — readers, types, providers, credentials, quota",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",