@eldrforge/kodrdriv 0.0.19 → 0.0.24

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 (64) hide show
  1. package/dist/arguments.js +664 -0
  2. package/dist/arguments.js.map +1 -0
  3. package/dist/commands/audio-commit.js +99 -0
  4. package/dist/commands/audio-commit.js.map +1 -0
  5. package/dist/commands/audio-review.js +110 -0
  6. package/dist/commands/audio-review.js.map +1 -0
  7. package/dist/commands/clean.js +36 -0
  8. package/dist/commands/clean.js.map +1 -0
  9. package/dist/commands/commit.js +125 -0
  10. package/dist/commands/commit.js.map +1 -0
  11. package/dist/commands/link.js +184 -0
  12. package/dist/commands/link.js.map +1 -0
  13. package/dist/commands/publish.js +301 -0
  14. package/dist/commands/publish.js.map +1 -0
  15. package/dist/commands/release.js +85 -0
  16. package/dist/commands/release.js.map +1 -0
  17. package/dist/commands/review.js +268 -0
  18. package/dist/commands/review.js.map +1 -0
  19. package/dist/commands/select-audio.js +29 -0
  20. package/dist/commands/select-audio.js.map +1 -0
  21. package/dist/commands/unlink.js +180 -0
  22. package/dist/commands/unlink.js.map +1 -0
  23. package/dist/constants.js +154 -0
  24. package/dist/constants.js.map +1 -0
  25. package/dist/content/diff.js +220 -0
  26. package/dist/content/diff.js.map +1 -0
  27. package/dist/content/issues.js +360 -0
  28. package/dist/content/issues.js.map +1 -0
  29. package/dist/content/log.js +53 -0
  30. package/dist/content/log.js.map +1 -0
  31. package/dist/content/releaseNotes.js +90 -0
  32. package/dist/content/releaseNotes.js.map +1 -0
  33. package/dist/error/ExitError.js +9 -0
  34. package/dist/error/ExitError.js.map +1 -0
  35. package/dist/logging.js +103 -0
  36. package/dist/logging.js.map +1 -0
  37. package/dist/main.js +30 -3707
  38. package/dist/main.js.map +1 -1
  39. package/dist/prompt/commit.js +56 -0
  40. package/dist/prompt/commit.js.map +1 -0
  41. package/dist/prompt/release.js +52 -0
  42. package/dist/prompt/release.js.map +1 -0
  43. package/dist/prompt/review.js +64 -0
  44. package/dist/prompt/review.js.map +1 -0
  45. package/dist/types.js +88 -0
  46. package/dist/types.js.map +1 -0
  47. package/dist/util/child.js +23 -0
  48. package/dist/util/child.js.map +1 -0
  49. package/dist/util/general.js +96 -0
  50. package/dist/util/general.js.map +1 -0
  51. package/dist/util/github.js +208 -0
  52. package/dist/util/github.js.map +1 -0
  53. package/dist/util/openai.js +146 -0
  54. package/dist/util/openai.js.map +1 -0
  55. package/dist/util/stdin.js +101 -0
  56. package/dist/util/stdin.js.map +1 -0
  57. package/dist/util/storage.js +149 -0
  58. package/dist/util/storage.js.map +1 -0
  59. package/package.json +5 -5
  60. /package/dist/{src/prompt → prompt}/instructions/commit.md +0 -0
  61. /package/dist/{src/prompt → prompt}/instructions/release.md +0 -0
  62. /package/dist/{src/prompt → prompt}/instructions/review.md +0 -0
  63. /package/dist/{src/prompt → prompt}/personas/releaser.md +0 -0
  64. /package/dist/{src/prompt → prompt}/personas/you.md +0 -0
@@ -0,0 +1,208 @@
1
+ import { Octokit } from '@octokit/rest';
2
+ import { getLogger } from '../logging.js';
3
+ import { run } from './child.js';
4
+
5
+ const getOctokit = ()=>{
6
+ const logger = getLogger();
7
+ const token = process.env.GITHUB_TOKEN;
8
+ if (!token) {
9
+ logger.error('GITHUB_TOKEN environment variable is not set.');
10
+ throw new Error('GITHUB_TOKEN is not set.');
11
+ }
12
+ return new Octokit({
13
+ auth: token
14
+ });
15
+ };
16
+ const getCurrentBranchName = async ()=>{
17
+ const { stdout } = await run('git rev-parse --abbrev-ref HEAD');
18
+ return stdout.trim();
19
+ };
20
+ const getRepoDetails = async ()=>{
21
+ const { stdout } = await run('git remote get-url origin');
22
+ const url = stdout.trim();
23
+ // git@github.com:owner/repo.git or https://github.com/owner/repo.git
24
+ const match = url.match(/github\.com[/:]([\w-]+)\/([\w.-]+)\.git/);
25
+ if (!match) {
26
+ throw new Error(`Could not parse repository owner and name from origin URL: "${url}". Expected format: git@github.com:owner/repo.git or https://github.com/owner/repo.git`);
27
+ }
28
+ return {
29
+ owner: match[1],
30
+ repo: match[2]
31
+ };
32
+ };
33
+ const createPullRequest = async (title, body, head, base = 'main')=>{
34
+ const octokit = getOctokit();
35
+ const { owner, repo } = await getRepoDetails();
36
+ const response = await octokit.pulls.create({
37
+ owner,
38
+ repo,
39
+ title,
40
+ body,
41
+ head,
42
+ base
43
+ });
44
+ return response.data;
45
+ };
46
+ const findOpenPullRequestByHeadRef = async (head)=>{
47
+ const octokit = getOctokit();
48
+ const { owner, repo } = await getRepoDetails();
49
+ const logger = getLogger();
50
+ try {
51
+ logger.debug(`Searching for open pull requests with head: ${owner}:${head} in ${owner}/${repo}`);
52
+ const response = await octokit.pulls.list({
53
+ owner,
54
+ repo,
55
+ state: 'open',
56
+ head: `${owner}:${head}`
57
+ });
58
+ logger.debug(`Found ${response.data.length} open pull requests`);
59
+ var _response_data_;
60
+ return (_response_data_ = response.data[0]) !== null && _response_data_ !== void 0 ? _response_data_ : null;
61
+ } catch (error) {
62
+ logger.error(`Failed to find open pull requests: ${error.message}`);
63
+ if (error.status === 404) {
64
+ logger.error(`Repository ${owner}/${repo} not found or access denied. Please check your GITHUB_TOKEN permissions.`);
65
+ }
66
+ throw error;
67
+ }
68
+ };
69
+ const delay = (ms)=>new Promise((resolve)=>setTimeout(resolve, ms));
70
+ const waitForPullRequestChecks = async (prNumber)=>{
71
+ const octokit = getOctokit();
72
+ const { owner, repo } = await getRepoDetails();
73
+ const logger = getLogger();
74
+ while(true){
75
+ const pr = await octokit.pulls.get({
76
+ owner,
77
+ repo,
78
+ pull_number: prNumber
79
+ });
80
+ const checkRunsResponse = await octokit.checks.listForRef({
81
+ owner,
82
+ repo,
83
+ ref: pr.data.head.sha
84
+ });
85
+ const checkRuns = checkRunsResponse.data.check_runs;
86
+ if (checkRuns.length === 0) {
87
+ logger.info(`PR #${prNumber}: No checks found. Waiting...`);
88
+ await delay(10000);
89
+ continue;
90
+ }
91
+ const failingChecks = checkRuns.filter((cr)=>cr.conclusion && [
92
+ 'failure',
93
+ 'timed_out',
94
+ 'cancelled'
95
+ ].includes(cr.conclusion));
96
+ if (failingChecks.length > 0) {
97
+ logger.error(`PR #${prNumber} has failing checks:`);
98
+ for (const check of failingChecks){
99
+ logger.error(`- ${check.name}: ${check.conclusion}`);
100
+ }
101
+ throw new Error(`PR #${prNumber} checks failed.`);
102
+ }
103
+ const allChecksCompleted = checkRuns.every((cr)=>cr.status === 'completed');
104
+ if (allChecksCompleted) {
105
+ logger.info(`All checks for PR #${prNumber} have completed successfully.`);
106
+ return;
107
+ }
108
+ const completedCount = checkRuns.filter((cr)=>cr.status === 'completed').length;
109
+ logger.info(`PR #${prNumber} checks: ${completedCount}/${checkRuns.length} completed. Waiting...`);
110
+ await delay(10000); // wait 10 seconds
111
+ }
112
+ };
113
+ const mergePullRequest = async (prNumber, mergeMethod = 'squash')=>{
114
+ const octokit = getOctokit();
115
+ const { owner, repo } = await getRepoDetails();
116
+ const logger = getLogger();
117
+ logger.info(`Merging PR #${prNumber} using ${mergeMethod} method...`);
118
+ const pr = await octokit.pulls.get({
119
+ owner,
120
+ repo,
121
+ pull_number: prNumber
122
+ });
123
+ const headBranch = pr.data.head.ref;
124
+ await octokit.pulls.merge({
125
+ owner,
126
+ repo,
127
+ pull_number: prNumber,
128
+ merge_method: mergeMethod
129
+ });
130
+ logger.info(`PR #${prNumber} merged using ${mergeMethod} method.`);
131
+ logger.info(`Deleting branch ${headBranch}...`);
132
+ await octokit.git.deleteRef({
133
+ owner,
134
+ repo,
135
+ ref: `heads/${headBranch}`
136
+ });
137
+ logger.info(`Branch ${headBranch} deleted.`);
138
+ };
139
+ const createRelease = async (tagName, title, notes)=>{
140
+ const octokit = getOctokit();
141
+ const { owner, repo } = await getRepoDetails();
142
+ const logger = getLogger();
143
+ logger.info(`Creating release for tag ${tagName}...`);
144
+ await octokit.repos.createRelease({
145
+ owner,
146
+ repo,
147
+ tag_name: tagName,
148
+ name: title,
149
+ body: notes
150
+ });
151
+ logger.info(`Release ${tagName} created.`);
152
+ };
153
+ const getOpenIssues = async (limit = 20)=>{
154
+ const octokit = getOctokit();
155
+ const { owner, repo } = await getRepoDetails();
156
+ const logger = getLogger();
157
+ try {
158
+ logger.debug(`Fetching up to ${limit} open GitHub issues...`);
159
+ const response = await octokit.issues.listForRepo({
160
+ owner,
161
+ repo,
162
+ state: 'open',
163
+ per_page: Math.min(limit, 100),
164
+ sort: 'updated',
165
+ direction: 'desc'
166
+ });
167
+ const issues = response.data.filter((issue)=>!issue.pull_request); // Filter out PRs
168
+ if (issues.length === 0) {
169
+ logger.debug('No open issues found');
170
+ return '';
171
+ }
172
+ const issueStrings = issues.slice(0, limit).map((issue)=>{
173
+ var _issue_body;
174
+ const labels = issue.labels.map((label)=>typeof label === 'string' ? label : label.name).join(', ');
175
+ return [
176
+ `Issue #${issue.number}: ${issue.title}`,
177
+ `Labels: ${labels || 'none'}`,
178
+ `Created: ${issue.created_at}`,
179
+ `Updated: ${issue.updated_at}`,
180
+ `Body: ${((_issue_body = issue.body) === null || _issue_body === void 0 ? void 0 : _issue_body.substring(0, 500)) || 'No description'}${issue.body && issue.body.length > 500 ? '...' : ''}`,
181
+ '---'
182
+ ].join('\n');
183
+ });
184
+ logger.debug(`Fetched ${issues.length} open issues`);
185
+ return issueStrings.join('\n\n');
186
+ } catch (error) {
187
+ logger.warn('Failed to fetch GitHub issues: %s', error.message);
188
+ return '';
189
+ }
190
+ };
191
+ const createIssue = async (title, body, labels)=>{
192
+ const octokit = getOctokit();
193
+ const { owner, repo } = await getRepoDetails();
194
+ const response = await octokit.issues.create({
195
+ owner,
196
+ repo,
197
+ title,
198
+ body,
199
+ labels: labels || []
200
+ });
201
+ return {
202
+ number: response.data.number,
203
+ html_url: response.data.html_url
204
+ };
205
+ };
206
+
207
+ export { createIssue, createPullRequest, createRelease, findOpenPullRequestByHeadRef, getCurrentBranchName, getOctokit, getOpenIssues, getRepoDetails, mergePullRequest, waitForPullRequestChecks };
208
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sources":["../../src/util/github.ts"],"sourcesContent":["import { Octokit } from '@octokit/rest';\nimport { getLogger } from '../logging';\nimport { PullRequest, MergeMethod } from '../types';\nimport { run } from './child';\n\nexport const getOctokit = (): Octokit => {\n const logger = getLogger();\n const token = process.env.GITHUB_TOKEN;\n\n if (!token) {\n logger.error('GITHUB_TOKEN environment variable is not set.');\n throw new Error('GITHUB_TOKEN is not set.');\n }\n\n return new Octokit({\n auth: token,\n });\n};\n\nexport const getCurrentBranchName = async (): Promise<string> => {\n const { stdout } = await run('git rev-parse --abbrev-ref HEAD');\n return stdout.trim();\n};\n\nexport const getRepoDetails = async (): Promise<{ owner: string; repo: string }> => {\n const { stdout } = await run('git remote get-url origin');\n const url = stdout.trim();\n // git@github.com:owner/repo.git or https://github.com/owner/repo.git\n const match = url.match(/github\\.com[/:]([\\w-]+)\\/([\\w.-]+)\\.git/);\n if (!match) {\n throw new Error(`Could not parse repository owner and name from origin URL: \"${url}\". Expected format: git@github.com:owner/repo.git or https://github.com/owner/repo.git`);\n }\n return { owner: match[1], repo: match[2] };\n};\n\nexport const createPullRequest = async (\n title: string,\n body: string,\n head: string,\n base: string = 'main'\n): Promise<PullRequest> => {\n const octokit = getOctokit();\n const { owner, repo } = await getRepoDetails();\n\n const response = await octokit.pulls.create({\n owner,\n repo,\n title,\n body,\n head,\n base,\n });\n\n return response.data;\n};\n\nexport const findOpenPullRequestByHeadRef = async (head: string): Promise<PullRequest | null> => {\n const octokit = getOctokit();\n const { owner, repo } = await getRepoDetails();\n const logger = getLogger();\n\n try {\n logger.debug(`Searching for open pull requests with head: ${owner}:${head} in ${owner}/${repo}`);\n\n const response = await octokit.pulls.list({\n owner,\n repo,\n state: 'open',\n head: `${owner}:${head}`,\n });\n\n logger.debug(`Found ${response.data.length} open pull requests`);\n return response.data[0] ?? null;\n } catch (error: any) {\n logger.error(`Failed to find open pull requests: ${error.message}`);\n if (error.status === 404) {\n logger.error(`Repository ${owner}/${repo} not found or access denied. Please check your GITHUB_TOKEN permissions.`);\n }\n throw error;\n }\n};\n\nconst delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));\n\nexport const waitForPullRequestChecks = async (prNumber: number): Promise<void> => {\n const octokit = getOctokit();\n const { owner, repo } = await getRepoDetails();\n const logger = getLogger();\n\n while (true) {\n const pr = await octokit.pulls.get({\n owner,\n repo,\n pull_number: prNumber,\n });\n\n const checkRunsResponse = await octokit.checks.listForRef({\n owner,\n repo,\n ref: pr.data.head.sha,\n });\n\n const checkRuns = checkRunsResponse.data.check_runs;\n\n if (checkRuns.length === 0) {\n logger.info(`PR #${prNumber}: No checks found. Waiting...`);\n await delay(10000);\n continue;\n }\n\n const failingChecks = checkRuns.filter(\n (cr) => cr.conclusion && ['failure', 'timed_out', 'cancelled'].includes(cr.conclusion)\n );\n\n if (failingChecks.length > 0) {\n logger.error(`PR #${prNumber} has failing checks:`);\n for (const check of failingChecks) {\n logger.error(`- ${check.name}: ${check.conclusion}`);\n }\n throw new Error(`PR #${prNumber} checks failed.`);\n }\n\n const allChecksCompleted = checkRuns.every((cr) => cr.status === 'completed');\n\n if (allChecksCompleted) {\n logger.info(`All checks for PR #${prNumber} have completed successfully.`);\n return;\n }\n\n const completedCount = checkRuns.filter(cr => cr.status === 'completed').length;\n logger.info(`PR #${prNumber} checks: ${completedCount}/${checkRuns.length} completed. Waiting...`);\n\n await delay(10000); // wait 10 seconds\n }\n};\n\nexport const mergePullRequest = async (prNumber: number, mergeMethod: MergeMethod = 'squash'): Promise<void> => {\n const octokit = getOctokit();\n const { owner, repo } = await getRepoDetails();\n const logger = getLogger();\n\n logger.info(`Merging PR #${prNumber} using ${mergeMethod} method...`);\n const pr = await octokit.pulls.get({\n owner,\n repo,\n pull_number: prNumber,\n });\n const headBranch = pr.data.head.ref;\n\n await octokit.pulls.merge({\n owner,\n repo,\n pull_number: prNumber,\n merge_method: mergeMethod,\n });\n logger.info(`PR #${prNumber} merged using ${mergeMethod} method.`);\n\n logger.info(`Deleting branch ${headBranch}...`);\n await octokit.git.deleteRef({\n owner,\n repo,\n ref: `heads/${headBranch}`,\n });\n logger.info(`Branch ${headBranch} deleted.`);\n};\n\nexport const createRelease = async (tagName: string, title: string, notes: string): Promise<void> => {\n const octokit = getOctokit();\n const { owner, repo } = await getRepoDetails();\n const logger = getLogger();\n\n logger.info(`Creating release for tag ${tagName}...`);\n await octokit.repos.createRelease({\n owner,\n repo,\n tag_name: tagName,\n name: title,\n body: notes,\n });\n logger.info(`Release ${tagName} created.`);\n};\n\nexport const getOpenIssues = async (limit: number = 20): Promise<string> => {\n const octokit = getOctokit();\n const { owner, repo } = await getRepoDetails();\n const logger = getLogger();\n\n try {\n logger.debug(`Fetching up to ${limit} open GitHub issues...`);\n\n const response = await octokit.issues.listForRepo({\n owner,\n repo,\n state: 'open',\n per_page: Math.min(limit, 100), // GitHub API limit\n sort: 'updated',\n direction: 'desc',\n });\n\n const issues = response.data.filter(issue => !issue.pull_request); // Filter out PRs\n\n if (issues.length === 0) {\n logger.debug('No open issues found');\n return '';\n }\n\n const issueStrings = issues.slice(0, limit).map(issue => {\n const labels = issue.labels.map(label =>\n typeof label === 'string' ? label : label.name\n ).join(', ');\n\n return [\n `Issue #${issue.number}: ${issue.title}`,\n `Labels: ${labels || 'none'}`,\n `Created: ${issue.created_at}`,\n `Updated: ${issue.updated_at}`,\n `Body: ${issue.body?.substring(0, 500) || 'No description'}${issue.body && issue.body.length > 500 ? '...' : ''}`,\n '---'\n ].join('\\n');\n });\n\n logger.debug(`Fetched ${issues.length} open issues`);\n return issueStrings.join('\\n\\n');\n } catch (error: any) {\n logger.warn('Failed to fetch GitHub issues: %s', error.message);\n return '';\n }\n};\n\nexport const createIssue = async (\n title: string,\n body: string,\n labels?: string[]\n): Promise<{ number: number; html_url: string }> => {\n const octokit = getOctokit();\n const { owner, repo } = await getRepoDetails();\n\n const response = await octokit.issues.create({\n owner,\n repo,\n title,\n body,\n labels: labels || [],\n });\n\n return {\n number: response.data.number,\n html_url: response.data.html_url,\n };\n}; "],"names":["getOctokit","logger","getLogger","token","process","env","GITHUB_TOKEN","error","Error","Octokit","auth","getCurrentBranchName","stdout","run","trim","getRepoDetails","url","match","owner","repo","createPullRequest","title","body","head","base","octokit","response","pulls","create","data","findOpenPullRequestByHeadRef","debug","list","state","length","message","status","delay","ms","Promise","resolve","setTimeout","waitForPullRequestChecks","prNumber","pr","get","pull_number","checkRunsResponse","checks","listForRef","ref","sha","checkRuns","check_runs","info","failingChecks","filter","cr","conclusion","includes","check","name","allChecksCompleted","every","completedCount","mergePullRequest","mergeMethod","headBranch","merge","merge_method","git","deleteRef","createRelease","tagName","notes","repos","tag_name","getOpenIssues","limit","issues","listForRepo","per_page","Math","min","sort","direction","issue","pull_request","issueStrings","slice","map","labels","label","join","number","created_at","updated_at","substring","warn","createIssue","html_url"],"mappings":"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"}
@@ -0,0 +1,146 @@
1
+ import { OpenAI } from 'openai';
2
+ import { create } from './storage.js';
3
+ import { getLogger } from '../logging.js';
4
+
5
+ class OpenAIError extends Error {
6
+ constructor(message){
7
+ super(message);
8
+ this.name = 'OpenAIError';
9
+ }
10
+ }
11
+ async function createCompletion(messages, options = {
12
+ model: "gpt-4o-mini"
13
+ }) {
14
+ const logger = getLogger();
15
+ const storage = create({
16
+ log: logger.debug
17
+ });
18
+ let openai = null;
19
+ try {
20
+ var _completion_choices__message_content, _completion_choices__message, _completion_choices_;
21
+ const apiKey = process.env.OPENAI_API_KEY;
22
+ if (!apiKey) {
23
+ throw new OpenAIError('OPENAI_API_KEY environment variable is not set');
24
+ }
25
+ // Create the client which we'll close in the finally block.
26
+ openai = new OpenAI({
27
+ apiKey: apiKey,
28
+ timeout: 180000
29
+ });
30
+ logger.debug('Sending prompt to OpenAI: %j', messages);
31
+ // Save request debug file if enabled
32
+ if (options.debug && (options.debugRequestFile || options.debugFile)) {
33
+ const requestData = {
34
+ model: options.model || "gpt-4o-mini",
35
+ messages,
36
+ max_completion_tokens: 10000,
37
+ response_format: options.responseFormat
38
+ };
39
+ const debugFile = options.debugRequestFile || options.debugFile;
40
+ await storage.writeFile(debugFile, JSON.stringify(requestData, null, 2), 'utf8');
41
+ logger.debug('Wrote request debug file to %s', debugFile);
42
+ }
43
+ // Add timeout wrapper to the OpenAI API call
44
+ const completionPromise = openai.chat.completions.create({
45
+ model: options.model || "gpt-4o-mini",
46
+ messages,
47
+ max_completion_tokens: 10000,
48
+ response_format: options.responseFormat
49
+ });
50
+ const timeoutPromise = new Promise((_, reject)=>{
51
+ setTimeout(()=>reject(new OpenAIError('OpenAI API call timed out after 180 seconds')), 180000);
52
+ });
53
+ const completion = await Promise.race([
54
+ completionPromise,
55
+ timeoutPromise
56
+ ]);
57
+ // Save response debug file if enabled
58
+ if (options.debug && (options.debugResponseFile || options.debugFile)) {
59
+ const debugFile = options.debugResponseFile || options.debugFile;
60
+ await storage.writeFile(debugFile, JSON.stringify(completion, null, 2), 'utf8');
61
+ logger.debug('Wrote response debug file to %s', debugFile);
62
+ }
63
+ const response = (_completion_choices_ = completion.choices[0]) === null || _completion_choices_ === void 0 ? void 0 : (_completion_choices__message = _completion_choices_.message) === null || _completion_choices__message === void 0 ? void 0 : (_completion_choices__message_content = _completion_choices__message.content) === null || _completion_choices__message_content === void 0 ? void 0 : _completion_choices__message_content.trim();
64
+ if (!response) {
65
+ throw new OpenAIError('No response received from OpenAI');
66
+ }
67
+ logger.debug('Received response from OpenAI: %s...', response.substring(0, 30));
68
+ if (options.responseFormat) {
69
+ return JSON.parse(response);
70
+ } else {
71
+ return response;
72
+ }
73
+ } catch (error) {
74
+ logger.error('Error calling OpenAI API: %s %s', error.message, error.stack);
75
+ throw new OpenAIError(`Failed to create completion: ${error.message}`);
76
+ } finally{
77
+ // OpenAI client cleanup is handled automatically by the library
78
+ // No manual cleanup needed for newer versions
79
+ }
80
+ }
81
+ async function transcribeAudio(filePath, options = {
82
+ model: "whisper-1"
83
+ }) {
84
+ const logger = getLogger();
85
+ const storage = create({
86
+ log: logger.debug
87
+ });
88
+ let openai = null;
89
+ let audioStream = null;
90
+ try {
91
+ const apiKey = process.env.OPENAI_API_KEY;
92
+ if (!apiKey) {
93
+ throw new OpenAIError('OPENAI_API_KEY environment variable is not set');
94
+ }
95
+ openai = new OpenAI({
96
+ apiKey: apiKey
97
+ });
98
+ logger.debug('Transcribing audio file: %s', filePath);
99
+ // Save request debug file if enabled
100
+ if (options.debug && (options.debugRequestFile || options.debugFile)) {
101
+ const requestData = {
102
+ model: options.model || "whisper-1",
103
+ file: filePath,
104
+ response_format: "json"
105
+ };
106
+ const debugFile = options.debugRequestFile || options.debugFile;
107
+ await storage.writeFile(debugFile, JSON.stringify(requestData, null, 2), 'utf8');
108
+ logger.debug('Wrote request debug file to %s', debugFile);
109
+ }
110
+ audioStream = await storage.readStream(filePath);
111
+ const transcription = await openai.audio.transcriptions.create({
112
+ model: options.model || "whisper-1",
113
+ file: audioStream,
114
+ response_format: "json"
115
+ });
116
+ // Save response debug file if enabled
117
+ if (options.debug && (options.debugResponseFile || options.debugFile)) {
118
+ const debugFile = options.debugResponseFile || options.debugFile;
119
+ await storage.writeFile(debugFile, JSON.stringify(transcription, null, 2), 'utf8');
120
+ logger.debug('Wrote response debug file to %s', debugFile);
121
+ }
122
+ const response = transcription;
123
+ if (!response) {
124
+ throw new OpenAIError('No transcription received from OpenAI');
125
+ }
126
+ logger.debug('Received transcription from OpenAI: %s', response);
127
+ return response;
128
+ } catch (error) {
129
+ logger.error('Error transcribing audio file: %s %s', error.message, error.stack);
130
+ throw new OpenAIError(`Failed to transcribe audio: ${error.message}`);
131
+ } finally{
132
+ // Ensure the audio stream is properly closed to release file handles
133
+ try {
134
+ if (audioStream) {
135
+ audioStream.close();
136
+ }
137
+ } catch (streamErr) {
138
+ logger.debug('Failed to close audio read stream: %s', streamErr.message);
139
+ }
140
+ // OpenAI client cleanup is handled automatically by the library
141
+ // No manual cleanup needed for newer versions
142
+ }
143
+ }
144
+
145
+ export { OpenAIError, createCompletion, transcribeAudio };
146
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sources":["../../src/util/openai.ts"],"sourcesContent":["import { OpenAI } from 'openai';\nimport { ChatCompletionMessageParam } from 'openai/resources';\nimport * as Storage from './storage';\nimport { getLogger } from '../logging';\n// eslint-disable-next-line no-restricted-imports\nimport fs from 'fs';\n\nexport interface Transcription {\n text: string;\n}\n\nexport class OpenAIError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'OpenAIError';\n }\n}\n\nexport async function createCompletion(messages: ChatCompletionMessageParam[], options: { responseFormat?: any, model?: string, debug?: boolean, debugFile?: string, debugRequestFile?: string, debugResponseFile?: string } = { model: \"gpt-4o-mini\" }): Promise<string | any> {\n const logger = getLogger();\n const storage = Storage.create({ log: logger.debug });\n let openai: OpenAI | null = null;\n try {\n const apiKey = process.env.OPENAI_API_KEY;\n if (!apiKey) {\n throw new OpenAIError('OPENAI_API_KEY environment variable is not set');\n }\n\n // Create the client which we'll close in the finally block.\n openai = new OpenAI({\n apiKey: apiKey,\n timeout: 180000, // 180 seconds timeout\n });\n\n logger.debug('Sending prompt to OpenAI: %j', messages);\n\n // Save request debug file if enabled\n if (options.debug && (options.debugRequestFile || options.debugFile)) {\n const requestData = {\n model: options.model || \"gpt-4o-mini\",\n messages,\n max_completion_tokens: 10000,\n response_format: options.responseFormat,\n };\n const debugFile = options.debugRequestFile || options.debugFile;\n await storage.writeFile(debugFile!, JSON.stringify(requestData, null, 2), 'utf8');\n logger.debug('Wrote request debug file to %s', debugFile);\n }\n\n // Add timeout wrapper to the OpenAI API call\n const completionPromise = openai.chat.completions.create({\n model: options.model || \"gpt-4o-mini\",\n messages,\n max_completion_tokens: 10000,\n response_format: options.responseFormat,\n });\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => reject(new OpenAIError('OpenAI API call timed out after 180 seconds')), 180000);\n });\n\n const completion = await Promise.race([completionPromise, timeoutPromise]);\n\n // Save response debug file if enabled\n if (options.debug && (options.debugResponseFile || options.debugFile)) {\n const debugFile = options.debugResponseFile || options.debugFile;\n await storage.writeFile(debugFile!, JSON.stringify(completion, null, 2), 'utf8');\n logger.debug('Wrote response debug file to %s', debugFile);\n }\n\n const response = completion.choices[0]?.message?.content?.trim();\n if (!response) {\n throw new OpenAIError('No response received from OpenAI');\n }\n\n logger.debug('Received response from OpenAI: %s...', response.substring(0, 30));\n if (options.responseFormat) {\n return JSON.parse(response);\n } else {\n return response;\n }\n\n } catch (error: any) {\n logger.error('Error calling OpenAI API: %s %s', error.message, error.stack);\n throw new OpenAIError(`Failed to create completion: ${error.message}`);\n } finally {\n // OpenAI client cleanup is handled automatically by the library\n // No manual cleanup needed for newer versions\n }\n}\n\nexport async function transcribeAudio(filePath: string, options: { model?: string, debug?: boolean, debugFile?: string, debugRequestFile?: string, debugResponseFile?: string } = { model: \"whisper-1\" }): Promise<Transcription> {\n const logger = getLogger();\n const storage = Storage.create({ log: logger.debug });\n let openai: OpenAI | null = null;\n let audioStream: fs.ReadStream | null = null;\n try {\n const apiKey = process.env.OPENAI_API_KEY;\n if (!apiKey) {\n throw new OpenAIError('OPENAI_API_KEY environment variable is not set');\n }\n\n openai = new OpenAI({\n apiKey: apiKey,\n });\n\n logger.debug('Transcribing audio file: %s', filePath);\n\n // Save request debug file if enabled\n if (options.debug && (options.debugRequestFile || options.debugFile)) {\n const requestData = {\n model: options.model || \"whisper-1\",\n file: filePath, // Can't serialize the stream, so just save the file path\n response_format: \"json\",\n };\n const debugFile = options.debugRequestFile || options.debugFile;\n await storage.writeFile(debugFile!, JSON.stringify(requestData, null, 2), 'utf8');\n logger.debug('Wrote request debug file to %s', debugFile);\n }\n\n audioStream = await storage.readStream(filePath);\n const transcription = await openai.audio.transcriptions.create({\n model: options.model || \"whisper-1\",\n file: audioStream,\n response_format: \"json\",\n });\n\n // Save response debug file if enabled\n if (options.debug && (options.debugResponseFile || options.debugFile)) {\n const debugFile = options.debugResponseFile || options.debugFile;\n await storage.writeFile(debugFile!, JSON.stringify(transcription, null, 2), 'utf8');\n logger.debug('Wrote response debug file to %s', debugFile);\n }\n\n const response = transcription;\n if (!response) {\n throw new OpenAIError('No transcription received from OpenAI');\n }\n\n logger.debug('Received transcription from OpenAI: %s', response);\n return response;\n\n } catch (error: any) {\n logger.error('Error transcribing audio file: %s %s', error.message, error.stack);\n throw new OpenAIError(`Failed to transcribe audio: ${error.message}`);\n } finally {\n // Ensure the audio stream is properly closed to release file handles\n try {\n if (audioStream) {\n audioStream.close();\n }\n } catch (streamErr) {\n logger.debug('Failed to close audio read stream: %s', (streamErr as Error).message);\n }\n // OpenAI client cleanup is handled automatically by the library\n // No manual cleanup needed for newer versions\n }\n}\n"],"names":["OpenAIError","Error","message","name","createCompletion","messages","options","model","logger","getLogger","storage","Storage","log","debug","openai","completion","apiKey","process","env","OPENAI_API_KEY","OpenAI","timeout","debugRequestFile","debugFile","requestData","max_completion_tokens","response_format","responseFormat","writeFile","JSON","stringify","completionPromise","chat","completions","create","timeoutPromise","Promise","_","reject","setTimeout","race","debugResponseFile","response","choices","content","trim","substring","parse","error","stack","transcribeAudio","filePath","audioStream","file","readStream","transcription","audio","transcriptions","close","streamErr"],"mappings":";;;;AAWO,MAAMA,WAAAA,SAAoBC,KAAAA,CAAAA;AAC7B,IAAA,WAAA,CAAYC,OAAe,CAAE;AACzB,QAAA,KAAK,CAACA,OAAAA,CAAAA;QACN,IAAI,CAACC,IAAI,GAAG,aAAA;AAChB,IAAA;AACJ;AAEO,eAAeC,gBAAAA,CAAiBC,QAAsC,EAAEC,OAAAA,GAAgJ;IAAEC,KAAAA,EAAO;AAAc,CAAC,EAAA;AACnP,IAAA,MAAMC,MAAAA,GAASC,SAAAA,EAAAA;IACf,MAAMC,OAAAA,GAAUC,MAAc,CAAC;AAAEC,QAAAA,GAAAA,EAAKJ,OAAOK;AAAM,KAAA,CAAA;AACnD,IAAA,IAAIC,MAAAA,GAAwB,IAAA;IAC5B,IAAI;AAgDiBC,QAAAA,IAAAA,oCAAAA,EAAAA,4BAAAA,EAAAA,oBAAAA;AA/CjB,QAAA,MAAMC,MAAAA,GAASC,OAAAA,CAAQC,GAAG,CAACC,cAAc;AACzC,QAAA,IAAI,CAACH,MAAAA,EAAQ;AACT,YAAA,MAAM,IAAIhB,WAAAA,CAAY,gDAAA,CAAA;AAC1B,QAAA;;AAGAc,QAAAA,MAAAA,GAAS,IAAIM,MAAAA,CAAO;YAChBJ,MAAAA,EAAQA,MAAAA;YACRK,OAAAA,EAAS;AACb,SAAA,CAAA;QAEAb,MAAAA,CAAOK,KAAK,CAAC,8BAAA,EAAgCR,QAAAA,CAAAA;;QAG7C,IAAIC,OAAAA,CAAQO,KAAK,KAAKP,OAAAA,CAAQgB,gBAAgB,IAAIhB,OAAAA,CAAQiB,SAAQ,CAAA,EAAI;AAClE,YAAA,MAAMC,WAAAA,GAAc;gBAChBjB,KAAAA,EAAOD,OAAAA,CAAQC,KAAK,IAAI,aAAA;AACxBF,gBAAAA,QAAAA;gBACAoB,qBAAAA,EAAuB,KAAA;AACvBC,gBAAAA,eAAAA,EAAiBpB,QAAQqB;AAC7B,aAAA;AACA,YAAA,MAAMJ,SAAAA,GAAYjB,OAAAA,CAAQgB,gBAAgB,IAAIhB,QAAQiB,SAAS;YAC/D,MAAMb,OAAAA,CAAQkB,SAAS,CAACL,SAAAA,EAAYM,KAAKC,SAAS,CAACN,WAAAA,EAAa,IAAA,EAAM,CAAA,CAAA,EAAI,MAAA,CAAA;YAC1EhB,MAAAA,CAAOK,KAAK,CAAC,gCAAA,EAAkCU,SAAAA,CAAAA;AACnD,QAAA;;AAGA,QAAA,MAAMQ,oBAAoBjB,MAAAA,CAAOkB,IAAI,CAACC,WAAW,CAACC,MAAM,CAAC;YACrD3B,KAAAA,EAAOD,OAAAA,CAAQC,KAAK,IAAI,aAAA;AACxBF,YAAAA,QAAAA;YACAoB,qBAAAA,EAAuB,KAAA;AACvBC,YAAAA,eAAAA,EAAiBpB,QAAQqB;AAC7B,SAAA,CAAA;AAEA,QAAA,MAAMQ,cAAAA,GAAiB,IAAIC,OAAAA,CAAe,CAACC,CAAAA,EAAGC,MAAAA,GAAAA;AAC1CC,YAAAA,UAAAA,CAAW,IAAMD,MAAAA,CAAO,IAAItC,WAAAA,CAAY,6CAAA,CAAA,CAAA,EAAiD,MAAA,CAAA;AAC7F,QAAA,CAAA,CAAA;AAEA,QAAA,MAAMe,UAAAA,GAAa,MAAMqB,OAAAA,CAAQI,IAAI,CAAC;AAACT,YAAAA,iBAAAA;AAAmBI,YAAAA;AAAe,SAAA,CAAA;;QAGzE,IAAI7B,OAAAA,CAAQO,KAAK,KAAKP,OAAAA,CAAQmC,iBAAiB,IAAInC,OAAAA,CAAQiB,SAAQ,CAAA,EAAI;AACnE,YAAA,MAAMA,SAAAA,GAAYjB,OAAAA,CAAQmC,iBAAiB,IAAInC,QAAQiB,SAAS;YAChE,MAAMb,OAAAA,CAAQkB,SAAS,CAACL,SAAAA,EAAYM,KAAKC,SAAS,CAACf,UAAAA,EAAY,IAAA,EAAM,CAAA,CAAA,EAAI,MAAA,CAAA;YACzEP,MAAAA,CAAOK,KAAK,CAAC,iCAAA,EAAmCU,SAAAA,CAAAA;AACpD,QAAA;AAEA,QAAA,MAAMmB,YAAW3B,oBAAAA,GAAAA,UAAAA,CAAW4B,OAAO,CAAC,CAAA,CAAE,cAArB5B,oBAAAA,KAAAA,KAAAA,CAAAA,GAAAA,KAAAA,CAAAA,GAAAA,CAAAA,4BAAAA,GAAAA,qBAAuBb,OAAO,MAAA,IAAA,IAA9Ba,oDAAAA,oCAAAA,GAAAA,4BAAAA,CAAgC6B,OAAO,MAAA,IAAA,IAAvC7B,oCAAAA,KAAAA,KAAAA,CAAAA,GAAAA,KAAAA,CAAAA,GAAAA,qCAAyC8B,IAAI,EAAA;AAC9D,QAAA,IAAI,CAACH,QAAAA,EAAU;AACX,YAAA,MAAM,IAAI1C,WAAAA,CAAY,kCAAA,CAAA;AAC1B,QAAA;AAEAQ,QAAAA,MAAAA,CAAOK,KAAK,CAAC,sCAAA,EAAwC6B,QAAAA,CAASI,SAAS,CAAC,CAAA,EAAG,EAAA,CAAA,CAAA;QAC3E,IAAIxC,OAAAA,CAAQqB,cAAc,EAAE;YACxB,OAAOE,IAAAA,CAAKkB,KAAK,CAACL,QAAAA,CAAAA;QACtB,CAAA,MAAO;YACH,OAAOA,QAAAA;AACX,QAAA;AAEJ,IAAA,CAAA,CAAE,OAAOM,KAAAA,EAAY;AACjBxC,QAAAA,MAAAA,CAAOwC,KAAK,CAAC,iCAAA,EAAmCA,MAAM9C,OAAO,EAAE8C,MAAMC,KAAK,CAAA;AAC1E,QAAA,MAAM,IAAIjD,WAAAA,CAAY,CAAC,6BAA6B,EAAEgD,KAAAA,CAAM9C,OAAO,CAAA,CAAE,CAAA;IACzE,CAAA,QAAU;;;AAGV,IAAA;AACJ;AAEO,eAAegD,eAAAA,CAAgBC,QAAgB,EAAE7C,OAAAA,GAA0H;IAAEC,KAAAA,EAAO;AAAY,CAAC,EAAA;AACpM,IAAA,MAAMC,MAAAA,GAASC,SAAAA,EAAAA;IACf,MAAMC,OAAAA,GAAUC,MAAc,CAAC;AAAEC,QAAAA,GAAAA,EAAKJ,OAAOK;AAAM,KAAA,CAAA;AACnD,IAAA,IAAIC,MAAAA,GAAwB,IAAA;AAC5B,IAAA,IAAIsC,WAAAA,GAAoC,IAAA;IACxC,IAAI;AACA,QAAA,MAAMpC,MAAAA,GAASC,OAAAA,CAAQC,GAAG,CAACC,cAAc;AACzC,QAAA,IAAI,CAACH,MAAAA,EAAQ;AACT,YAAA,MAAM,IAAIhB,WAAAA,CAAY,gDAAA,CAAA;AAC1B,QAAA;AAEAc,QAAAA,MAAAA,GAAS,IAAIM,MAAAA,CAAO;YAChBJ,MAAAA,EAAQA;AACZ,SAAA,CAAA;QAEAR,MAAAA,CAAOK,KAAK,CAAC,6BAAA,EAA+BsC,QAAAA,CAAAA;;QAG5C,IAAI7C,OAAAA,CAAQO,KAAK,KAAKP,OAAAA,CAAQgB,gBAAgB,IAAIhB,OAAAA,CAAQiB,SAAQ,CAAA,EAAI;AAClE,YAAA,MAAMC,WAAAA,GAAc;gBAChBjB,KAAAA,EAAOD,OAAAA,CAAQC,KAAK,IAAI,WAAA;gBACxB8C,IAAAA,EAAMF,QAAAA;gBACNzB,eAAAA,EAAiB;AACrB,aAAA;AACA,YAAA,MAAMH,SAAAA,GAAYjB,OAAAA,CAAQgB,gBAAgB,IAAIhB,QAAQiB,SAAS;YAC/D,MAAMb,OAAAA,CAAQkB,SAAS,CAACL,SAAAA,EAAYM,KAAKC,SAAS,CAACN,WAAAA,EAAa,IAAA,EAAM,CAAA,CAAA,EAAI,MAAA,CAAA;YAC1EhB,MAAAA,CAAOK,KAAK,CAAC,gCAAA,EAAkCU,SAAAA,CAAAA;AACnD,QAAA;QAEA6B,WAAAA,GAAc,MAAM1C,OAAAA,CAAQ4C,UAAU,CAACH,QAAAA,CAAAA;QACvC,MAAMI,aAAAA,GAAgB,MAAMzC,MAAAA,CAAO0C,KAAK,CAACC,cAAc,CAACvB,MAAM,CAAC;YAC3D3B,KAAAA,EAAOD,OAAAA,CAAQC,KAAK,IAAI,WAAA;YACxB8C,IAAAA,EAAMD,WAAAA;YACN1B,eAAAA,EAAiB;AACrB,SAAA,CAAA;;QAGA,IAAIpB,OAAAA,CAAQO,KAAK,KAAKP,OAAAA,CAAQmC,iBAAiB,IAAInC,OAAAA,CAAQiB,SAAQ,CAAA,EAAI;AACnE,YAAA,MAAMA,SAAAA,GAAYjB,OAAAA,CAAQmC,iBAAiB,IAAInC,QAAQiB,SAAS;YAChE,MAAMb,OAAAA,CAAQkB,SAAS,CAACL,SAAAA,EAAYM,KAAKC,SAAS,CAACyB,aAAAA,EAAe,IAAA,EAAM,CAAA,CAAA,EAAI,MAAA,CAAA;YAC5E/C,MAAAA,CAAOK,KAAK,CAAC,iCAAA,EAAmCU,SAAAA,CAAAA;AACpD,QAAA;AAEA,QAAA,MAAMmB,QAAAA,GAAWa,aAAAA;AACjB,QAAA,IAAI,CAACb,QAAAA,EAAU;AACX,YAAA,MAAM,IAAI1C,WAAAA,CAAY,uCAAA,CAAA;AAC1B,QAAA;QAEAQ,MAAAA,CAAOK,KAAK,CAAC,wCAAA,EAA0C6B,QAAAA,CAAAA;QACvD,OAAOA,QAAAA;AAEX,IAAA,CAAA,CAAE,OAAOM,KAAAA,EAAY;AACjBxC,QAAAA,MAAAA,CAAOwC,KAAK,CAAC,sCAAA,EAAwCA,MAAM9C,OAAO,EAAE8C,MAAMC,KAAK,CAAA;AAC/E,QAAA,MAAM,IAAIjD,WAAAA,CAAY,CAAC,4BAA4B,EAAEgD,KAAAA,CAAM9C,OAAO,CAAA,CAAE,CAAA;IACxE,CAAA,QAAU;;QAEN,IAAI;AACA,YAAA,IAAIkD,WAAAA,EAAa;AACbA,gBAAAA,WAAAA,CAAYM,KAAK,EAAA;AACrB,YAAA;AACJ,QAAA,CAAA,CAAE,OAAOC,SAAAA,EAAW;AAChBnD,YAAAA,MAAAA,CAAOK,KAAK,CAAC,uCAAA,EAA0C8C,UAAoBzD,OAAO,CAAA;AACtF,QAAA;;;AAGJ,IAAA;AACJ;;;;"}
@@ -0,0 +1,101 @@
1
+ // Function to read from STDIN if available
2
+ async function readStdin() {
3
+ // In test environment, allow mocking to work by skipping TTY check
4
+ if (process.env.NODE_ENV === 'test' || process.env.VITEST === 'true') {
5
+ return new Promise((resolve)=>{
6
+ let input = '';
7
+ let hasData = false;
8
+ let resolved = false;
9
+ const timeout = setTimeout(()=>{
10
+ if (!hasData && !resolved) {
11
+ resolved = true;
12
+ cleanup();
13
+ resolve(null);
14
+ }
15
+ }, 10); // Very short timeout for tests
16
+ const onData = (chunk)=>{
17
+ hasData = true;
18
+ clearTimeout(timeout);
19
+ input += chunk;
20
+ };
21
+ const onEnd = ()=>{
22
+ if (!resolved) {
23
+ resolved = true;
24
+ cleanup();
25
+ resolve(input.trim() || null);
26
+ }
27
+ };
28
+ const onError = ()=>{
29
+ if (!resolved) {
30
+ resolved = true;
31
+ clearTimeout(timeout);
32
+ cleanup();
33
+ resolve(null);
34
+ }
35
+ };
36
+ const cleanup = ()=>{
37
+ process.stdin.removeListener('data', onData);
38
+ process.stdin.removeListener('end', onEnd);
39
+ process.stdin.removeListener('error', onError);
40
+ process.stdin.pause();
41
+ };
42
+ process.stdin.setEncoding('utf8');
43
+ process.stdin.on('data', onData);
44
+ process.stdin.on('end', onEnd);
45
+ process.stdin.on('error', onError);
46
+ process.stdin.resume();
47
+ });
48
+ }
49
+ return new Promise((resolve)=>{
50
+ // Check if stdin is TTY (interactive terminal)
51
+ if (process.stdin.isTTY) {
52
+ resolve(null);
53
+ return;
54
+ }
55
+ let input = '';
56
+ let hasData = false;
57
+ let resolved = false;
58
+ const timeout = setTimeout(()=>{
59
+ if (!hasData && !resolved) {
60
+ resolved = true;
61
+ cleanup();
62
+ resolve(null);
63
+ }
64
+ }, 100); // Short timeout to detect if data is available
65
+ const onData = (chunk)=>{
66
+ hasData = true;
67
+ clearTimeout(timeout);
68
+ input += chunk;
69
+ };
70
+ const onEnd = ()=>{
71
+ if (!resolved) {
72
+ resolved = true;
73
+ cleanup();
74
+ resolve(input.trim() || null);
75
+ }
76
+ };
77
+ const onError = ()=>{
78
+ if (!resolved) {
79
+ resolved = true;
80
+ clearTimeout(timeout);
81
+ cleanup();
82
+ resolve(null);
83
+ }
84
+ };
85
+ const cleanup = ()=>{
86
+ process.stdin.removeListener('data', onData);
87
+ process.stdin.removeListener('end', onEnd);
88
+ process.stdin.removeListener('error', onError);
89
+ process.stdin.pause();
90
+ };
91
+ process.stdin.setEncoding('utf8');
92
+ process.stdin.on('data', onData);
93
+ process.stdin.on('end', onEnd);
94
+ process.stdin.on('error', onError);
95
+ // If no data comes in quickly, assume no stdin
96
+ process.stdin.resume();
97
+ });
98
+ }
99
+
100
+ export { readStdin };
101
+ //# sourceMappingURL=stdin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdin.js","sources":["../../src/util/stdin.ts"],"sourcesContent":["// Function to read from STDIN if available\nexport async function readStdin(): Promise<string | null> {\n // In test environment, allow mocking to work by skipping TTY check\n if (process.env.NODE_ENV === 'test' || process.env.VITEST === 'true') {\n return new Promise((resolve) => {\n let input = '';\n let hasData = false;\n let resolved = false;\n\n const timeout = setTimeout(() => {\n if (!hasData && !resolved) {\n resolved = true;\n cleanup();\n resolve(null);\n }\n }, 10); // Very short timeout for tests\n\n const onData = (chunk: string) => {\n hasData = true;\n clearTimeout(timeout);\n input += chunk;\n };\n\n const onEnd = () => {\n if (!resolved) {\n resolved = true;\n cleanup();\n resolve(input.trim() || null);\n }\n };\n\n const onError = () => {\n if (!resolved) {\n resolved = true;\n clearTimeout(timeout);\n cleanup();\n resolve(null);\n }\n };\n\n const cleanup = () => {\n process.stdin.removeListener('data', onData);\n process.stdin.removeListener('end', onEnd);\n process.stdin.removeListener('error', onError);\n process.stdin.pause();\n };\n\n process.stdin.setEncoding('utf8');\n process.stdin.on('data', onData);\n process.stdin.on('end', onEnd);\n process.stdin.on('error', onError);\n process.stdin.resume();\n });\n }\n\n return new Promise((resolve) => {\n // Check if stdin is TTY (interactive terminal)\n if (process.stdin.isTTY) {\n resolve(null);\n return;\n }\n\n let input = '';\n let hasData = false;\n let resolved = false;\n\n const timeout = setTimeout(() => {\n if (!hasData && !resolved) {\n resolved = true;\n cleanup();\n resolve(null);\n }\n }, 100); // Short timeout to detect if data is available\n\n const onData = (chunk: string) => {\n hasData = true;\n clearTimeout(timeout);\n input += chunk;\n };\n\n const onEnd = () => {\n if (!resolved) {\n resolved = true;\n cleanup();\n resolve(input.trim() || null);\n }\n };\n\n const onError = () => {\n if (!resolved) {\n resolved = true;\n clearTimeout(timeout);\n cleanup();\n resolve(null);\n }\n };\n\n const cleanup = () => {\n process.stdin.removeListener('data', onData);\n process.stdin.removeListener('end', onEnd);\n process.stdin.removeListener('error', onError);\n process.stdin.pause();\n };\n\n process.stdin.setEncoding('utf8');\n process.stdin.on('data', onData);\n process.stdin.on('end', onEnd);\n process.stdin.on('error', onError);\n\n // If no data comes in quickly, assume no stdin\n process.stdin.resume();\n });\n} "],"names":["readStdin","process","env","NODE_ENV","VITEST","Promise","resolve","input","hasData","resolved","timeout","setTimeout","cleanup","onData","chunk","clearTimeout","onEnd","trim","onError","stdin","removeListener","pause","setEncoding","on","resume","isTTY"],"mappings":"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"}