sidekick-shared 0.26.5 → 0.27.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.
Files changed (68) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +98 -59
  3. package/dist/accountChanges.js +21 -2
  4. package/dist/accountHealth.d.ts +72 -0
  5. package/dist/accountHealth.js +286 -0
  6. package/dist/accountLaunch.d.ts +30 -0
  7. package/dist/accountLaunch.js +124 -0
  8. package/dist/accountManager.d.ts +33 -8
  9. package/dist/accountManager.js +183 -50
  10. package/dist/accountRegistry.d.ts +10 -0
  11. package/dist/accountRegistry.js +42 -22
  12. package/dist/accountSwitch.d.ts +43 -0
  13. package/dist/accountSwitch.js +115 -0
  14. package/dist/accountSync.d.ts +30 -0
  15. package/dist/accountSync.js +180 -0
  16. package/dist/accountSyncTypes.d.ts +25 -0
  17. package/dist/accountSyncTypes.js +7 -0
  18. package/dist/accounts.d.ts +58 -6
  19. package/dist/accounts.js +408 -189
  20. package/dist/claudeCredentials.d.ts +38 -0
  21. package/dist/claudeCredentials.js +74 -0
  22. package/dist/claudeProfiles.d.ts +40 -0
  23. package/dist/claudeProfiles.js +102 -10
  24. package/dist/codexAuth.d.ts +32 -0
  25. package/dist/codexAuth.js +127 -0
  26. package/dist/codexPaths.d.ts +21 -0
  27. package/dist/codexPaths.js +117 -0
  28. package/dist/codexProfiles.d.ts +58 -5
  29. package/dist/codexProfiles.js +574 -289
  30. package/dist/credentialIO.d.ts +12 -5
  31. package/dist/credentialIO.js +63 -29
  32. package/dist/credentials.d.ts +8 -0
  33. package/dist/credentials.js +28 -32
  34. package/dist/ensureDefaultAccounts.d.ts +8 -0
  35. package/dist/ensureDefaultAccounts.js +42 -82
  36. package/dist/humanPrompt.d.ts +27 -0
  37. package/dist/humanPrompt.js +93 -0
  38. package/dist/index.d.ts +31 -10
  39. package/dist/index.js +72 -13
  40. package/dist/keepAlive.d.ts +44 -0
  41. package/dist/keepAlive.js +106 -0
  42. package/dist/modelContext.js +4 -0
  43. package/dist/modelInfo.js +26 -1
  44. package/dist/node.d.ts +4 -0
  45. package/dist/node.js +9 -2
  46. package/dist/processDetection.d.ts +32 -0
  47. package/dist/processDetection.js +210 -0
  48. package/dist/promptHistory.d.ts +108 -0
  49. package/dist/promptHistory.js +616 -0
  50. package/dist/schemas/accountManager.d.ts +283 -1
  51. package/dist/schemas/accountManager.js +122 -1
  52. package/dist/schemas/assistantTurn.d.ts +2 -2
  53. package/dist/schemas/index.d.ts +6 -1
  54. package/dist/schemas/index.js +14 -1
  55. package/dist/schemas/observedSessionV1.d.ts +21 -21
  56. package/dist/schemas/quota.d.ts +18 -18
  57. package/dist/schemas/quotaHistory.d.ts +1 -1
  58. package/dist/schemas/sessionEvent.d.ts +25 -0
  59. package/dist/schemas/sessionEvent.js +3 -0
  60. package/dist/schemas/stateFile.d.ts +5 -5
  61. package/dist/terminalSync.d.ts +5 -5
  62. package/dist/terminalSync.js +7 -112
  63. package/dist/transcript.d.ts +6 -0
  64. package/dist/transcript.js +3 -0
  65. package/dist/types/sessionEvent.d.ts +8 -0
  66. package/dist/writers/atomic.d.ts +2 -0
  67. package/dist/writers/atomic.js +49 -2
  68. package/package.json +1 -1
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ACCOUNT_CONSUMER_REACHABILITY = void 0;
37
+ exports.findRunningProcessesSync = findRunningProcessesSync;
38
+ exports.findRunningProcesses = findRunningProcesses;
39
+ exports.detectRunningAccountConsumers = detectRunningAccountConsumers;
40
+ exports.detectRunningAccountConsumersSync = detectRunningAccountConsumersSync;
41
+ exports.describeAccountConsumer = describeAccountConsumer;
42
+ /**
43
+ * Cross-platform detection of running CLI/app processes that hold provider
44
+ * credentials in memory. Bounded, never throws, never spawns a shell.
45
+ */
46
+ const child_process_1 = require("child_process");
47
+ const path = __importStar(require("path"));
48
+ const PROBE_TIMEOUT_MS = 4000;
49
+ const CLAUDE_NPM_ENTRY = /claude-code[\\/]cli\.js/;
50
+ function parseUnixTable(stdout) {
51
+ const rows = [];
52
+ for (const line of stdout.split('\n')) {
53
+ const match = line.match(/^\s*(\d+)\s+(\S+)\s*(.*)$/);
54
+ if (!match)
55
+ continue;
56
+ rows.push({ pid: Number(match[1]), command: match[2], args: match[3] ?? '' });
57
+ }
58
+ return rows;
59
+ }
60
+ function parseWindowsCsv(stdout) {
61
+ const rows = [];
62
+ for (const line of stdout.split(/\r?\n/)) {
63
+ const match = line.match(/^"([^"]+)","(\d+)"/);
64
+ if (!match)
65
+ continue;
66
+ rows.push({ pid: Number(match[2]), command: match[1], args: '' });
67
+ }
68
+ return rows;
69
+ }
70
+ function matchRows(rows, names) {
71
+ const wanted = new Set(names);
72
+ const found = [];
73
+ for (const row of rows) {
74
+ if (!Number.isFinite(row.pid) || row.pid === process.pid)
75
+ continue;
76
+ const base = path.basename(row.command);
77
+ // The native Claude Code binary is invoked through a `claude` symlink but
78
+ // its executable is the versioned file (`.../versions/2.1.273`), so `comm`
79
+ // never says `claude`; argv[0] does.
80
+ const argv0 = row.args.trim().split(/\s+/)[0] ?? '';
81
+ const candidates = [base, base.replace(/\.exe$/i, ''), path.basename(argv0)];
82
+ let name = candidates.find((candidate) => candidate && wanted.has(candidate));
83
+ // An npm-installed `claude` runs under `node`; recognise it by its entry file.
84
+ if (!name &&
85
+ wanted.has('claude') &&
86
+ /^node(\.exe)?$/i.test(base) &&
87
+ CLAUDE_NPM_ENTRY.test(row.args)) {
88
+ name = 'claude';
89
+ }
90
+ if (name)
91
+ found.push({ pid: row.pid, name, command: row.command });
92
+ }
93
+ return found;
94
+ }
95
+ function probeCommand() {
96
+ return process.platform === 'win32'
97
+ ? { command: 'tasklist', args: ['/FO', 'CSV', '/NH'] }
98
+ : { command: 'ps', args: ['-axo', 'pid=,comm=,args='] };
99
+ }
100
+ function parseOutput(stdout) {
101
+ return process.platform === 'win32' ? parseWindowsCsv(stdout) : parseUnixTable(stdout);
102
+ }
103
+ /** Sync sibling of {@link findRunningProcesses}; blocks up to 4 s. */
104
+ function findRunningProcessesSync(names) {
105
+ if (names.length === 0)
106
+ return [];
107
+ try {
108
+ const { command, args } = probeCommand();
109
+ const result = (0, child_process_1.spawnSync)(command, args, {
110
+ encoding: 'utf8',
111
+ maxBuffer: 16 * 1024 * 1024,
112
+ timeout: PROBE_TIMEOUT_MS,
113
+ killSignal: 'SIGKILL',
114
+ windowsHide: true,
115
+ });
116
+ if (result.error || result.status !== 0)
117
+ return [];
118
+ return matchRows(parseOutput(String(result.stdout ?? '')), names);
119
+ }
120
+ catch {
121
+ return [];
122
+ }
123
+ }
124
+ function findRunningProcesses(names) {
125
+ if (names.length === 0)
126
+ return Promise.resolve([]);
127
+ return new Promise((resolve) => {
128
+ try {
129
+ const { command, args } = probeCommand();
130
+ (0, child_process_1.execFile)(command, args, {
131
+ encoding: 'utf8',
132
+ timeout: PROBE_TIMEOUT_MS,
133
+ killSignal: 'SIGKILL',
134
+ windowsHide: true,
135
+ maxBuffer: 16 * 1024 * 1024,
136
+ }, (error, stdout) => {
137
+ resolve(error ? [] : matchRows(parseOutput(String(stdout ?? '')), names));
138
+ });
139
+ }
140
+ catch {
141
+ resolve([]);
142
+ }
143
+ });
144
+ }
145
+ const CONSUMER_PROCESS_NAMES = {
146
+ 'claude-cli': 'claude',
147
+ 'claude-desktop': 'Claude',
148
+ 'codex-cli': 'codex',
149
+ 'codex-app': 'Codex',
150
+ };
151
+ exports.ACCOUNT_CONSUMER_REACHABILITY = {
152
+ 'claude-cli': {
153
+ switched: true,
154
+ reachability: 'Running claude sessions keep the previous account until restarted; a running session can rotate the refresh token of the account you just left.',
155
+ },
156
+ 'claude-desktop': {
157
+ switched: false,
158
+ reachability: 'Claude Desktop is not switched by sidekick (it keeps its own web session) and its embedded engine can rotate the shared CLI token.',
159
+ },
160
+ 'codex-cli': {
161
+ switched: true,
162
+ reachability: 'Running codex sessions keep the previous account until restarted.',
163
+ },
164
+ 'codex-app': {
165
+ switched: true,
166
+ reachability: 'The Codex app shares the CLI login; restart it to pick up the switch. While running it can refresh and rotate the live token.',
167
+ },
168
+ 'vscode-extension-host': {
169
+ switched: true,
170
+ reachability: 'The Claude Code extension host keeps the previous account until the window reloads.',
171
+ },
172
+ };
173
+ function toConsumer(kind, pids) {
174
+ return { kind, pids, ...exports.ACCOUNT_CONSUMER_REACHABILITY[kind] };
175
+ }
176
+ function groupConsumers(processes, kinds) {
177
+ const consumers = [];
178
+ for (const kind of kinds) {
179
+ const pids = processes.filter((p) => p.name === CONSUMER_PROCESS_NAMES[kind]).map((p) => p.pid);
180
+ if (pids.length > 0)
181
+ consumers.push(toConsumer(kind, pids));
182
+ }
183
+ return consumers;
184
+ }
185
+ function kindsForProvider(provider) {
186
+ if (provider === 'claude-code')
187
+ return ['claude-cli', 'claude-desktop'];
188
+ if (provider === 'codex')
189
+ return ['codex-cli', 'codex-app'];
190
+ return ['claude-cli', 'claude-desktop', 'codex-cli', 'codex-app'];
191
+ }
192
+ /**
193
+ * Which credential consumers are running right now, with the reachability
194
+ * sentence to show for each. Optionally scoped to one provider.
195
+ */
196
+ async function detectRunningAccountConsumers(provider) {
197
+ const kinds = kindsForProvider(provider);
198
+ const processes = await findRunningProcesses(kinds.map((kind) => CONSUMER_PROCESS_NAMES[kind]));
199
+ return groupConsumers(processes, kinds);
200
+ }
201
+ /** Sync sibling of {@link detectRunningAccountConsumers}; blocks up to 4 s. */
202
+ function detectRunningAccountConsumersSync(provider) {
203
+ const kinds = kindsForProvider(provider);
204
+ const processes = findRunningProcessesSync(kinds.map((kind) => CONSUMER_PROCESS_NAMES[kind]));
205
+ return groupConsumers(processes, kinds);
206
+ }
207
+ /** Build a consumer entry for a kind the host detects itself (e.g. its own extension host). */
208
+ function describeAccountConsumer(kind, pids = []) {
209
+ return toConsumer(kind, pids);
210
+ }
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Node-only collection of human-typed prompts from Claude Code and Codex
3
+ * session logs, scoped to a set of workspace roots.
4
+ *
5
+ * Parse-only: no redaction and no network I/O. Scope fails closed — a prompt
6
+ * is returned only when the working directory recorded on its log line (or,
7
+ * for Codex, its session/turn context) realpath-resolves to an allowed root
8
+ * or somewhere inside one. Every bound stops cleanly and is reported in
9
+ * `boundsHit`; nothing is silently truncated and no bound throws.
10
+ */
11
+ import { type HumanPromptProvider } from './humanPrompt';
12
+ export type PromptHistoryProvider = HumanPromptProvider;
13
+ export type PromptHistoryBound = 'maxSessions' | 'maxFileBytes' | 'maxTotalBytes' | 'deadline' | 'aborted';
14
+ export interface PromptHistoryBounds {
15
+ /** Session files read in one call (unchanged files do not count). Default 1000. */
16
+ maxSessions?: number;
17
+ /** Bytes a single file may need read in this pass. Default 16 MiB. */
18
+ maxFileBytes?: number;
19
+ /** Bytes read across all files in this call. Default 256 MiB. */
20
+ maxTotalBytes?: number;
21
+ /** Wall-clock budget for the call. Default 30 000 ms. */
22
+ deadlineMs?: number;
23
+ }
24
+ /** Codex parse state carried across resumes (Claude lines are self-describing). */
25
+ export interface PromptHistoryResumeState {
26
+ cwd?: string;
27
+ gitBranch?: string;
28
+ model?: string;
29
+ /** Session is not interactive (non-human source, fork, or missing metadata). */
30
+ excluded?: boolean;
31
+ /** `session_meta` has been seen. */
32
+ meta?: boolean;
33
+ }
34
+ export interface PromptHistoryCursorSession {
35
+ provider: PromptHistoryProvider;
36
+ sessionId: string;
37
+ size: number;
38
+ mtimeMs: number;
39
+ /** Ordinal of the last human prompt seen in this file, or -1 when none. */
40
+ lastOrdinal: number;
41
+ /** Byte offset just past the last complete line processed. */
42
+ offset: number;
43
+ state?: PromptHistoryResumeState;
44
+ }
45
+ /** JSON-serializable resume point. Keys are opaque; they never contain paths. */
46
+ export interface PromptHistoryCursor {
47
+ version: 1;
48
+ sessions: Record<string, PromptHistoryCursorSession>;
49
+ }
50
+ export interface PromptHistoryUsage {
51
+ /** Uncached input tokens. */
52
+ inputTokens?: number;
53
+ outputTokens?: number;
54
+ cacheReadTokens?: number;
55
+ cacheWriteTokens?: number;
56
+ }
57
+ export interface PromptHistoryEntry {
58
+ provider: PromptHistoryProvider;
59
+ sessionId: string;
60
+ /** Stable index of this prompt among the session's human prompts (0-based). */
61
+ ordinal: number;
62
+ /** ISO timestamp from the log line; never synthesized. */
63
+ timestamp: string;
64
+ /** Full prompt text, untruncated. */
65
+ text: string;
66
+ /** Realpath of the working directory; always inside an allowed root. */
67
+ cwd: string;
68
+ gitBranch?: string;
69
+ /** Model of the first assistant response to this prompt, when known. */
70
+ model?: string;
71
+ /** Usage of that first answering model call, when known. */
72
+ usage?: PromptHistoryUsage;
73
+ }
74
+ export interface PromptHistoryStats {
75
+ sessionsScanned: number;
76
+ sessionsSkippedUnchanged: number;
77
+ /** Scanned sessions with human prompts but none inside the allowed roots. */
78
+ sessionsOutOfScope: number;
79
+ filesOverSizeLimit: number;
80
+ /** Codex sessions skipped as non-interactive (subagent, fork, unknown source). */
81
+ sessionsNotInteractive: number;
82
+ /** Human prompts dropped because the log line had no usable timestamp. */
83
+ promptsMissingTimestamp: number;
84
+ /** Human prompts dropped because their cwd was missing or outside the roots. */
85
+ promptsOutOfScope: number;
86
+ }
87
+ export interface CollectPromptHistoryOptions {
88
+ /** Absolute workspace roots; realpath-normalized internally. */
89
+ workspacePaths: string[];
90
+ /** Add git worktree siblings of each root. Default true. */
91
+ includeWorktrees?: boolean;
92
+ /** Default both. */
93
+ providers?: PromptHistoryProvider[];
94
+ /** Drop prompts older than this (and skip files not modified since). */
95
+ since?: Date;
96
+ cursor?: PromptHistoryCursor;
97
+ bounds?: PromptHistoryBounds;
98
+ signal?: AbortSignal;
99
+ }
100
+ export interface PromptHistoryResult {
101
+ /** Ordered by provider, session, then ordinal. */
102
+ entries: PromptHistoryEntry[];
103
+ cursor: PromptHistoryCursor;
104
+ stats: PromptHistoryStats;
105
+ boundsHit: PromptHistoryBound[];
106
+ }
107
+ /** Collect human-typed prompts from Claude Code and Codex logs under the given roots. */
108
+ export declare function collectPromptHistory(options: CollectPromptHistoryOptions): Promise<PromptHistoryResult>;