@laitszkin/apollo-toolkit 3.13.2 → 3.14.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/AGENTS.md +7 -7
- package/CHANGELOG.md +27 -0
- package/CLAUDE.md +8 -8
- package/analyse-app-logs/SKILL.md +3 -3
- package/bin/apollo-toolkit.ts +7 -0
- package/codex/codex-memory-manager/SKILL.md +2 -2
- package/codex/learn-skill-from-conversations/SKILL.md +3 -3
- package/dist/bin/apollo-toolkit.d.ts +2 -0
- package/dist/bin/apollo-toolkit.js +7 -0
- package/dist/lib/cli.d.ts +41 -0
- package/dist/lib/cli.js +655 -0
- package/dist/lib/installer.d.ts +59 -0
- package/dist/lib/installer.js +404 -0
- package/dist/lib/tool-runner.d.ts +19 -0
- package/dist/lib/tool-runner.js +536 -0
- package/dist/lib/tools/architecture.d.ts +2 -0
- package/dist/lib/tools/architecture.js +34 -0
- package/dist/lib/tools/create-specs.d.ts +2 -0
- package/dist/lib/tools/create-specs.js +175 -0
- package/dist/lib/tools/docs-to-voice.d.ts +2 -0
- package/dist/lib/tools/docs-to-voice.js +705 -0
- package/dist/lib/tools/enforce-video-aspect-ratio.d.ts +2 -0
- package/dist/lib/tools/enforce-video-aspect-ratio.js +312 -0
- package/dist/lib/tools/extract-conversations.d.ts +2 -0
- package/dist/lib/tools/extract-conversations.js +105 -0
- package/dist/lib/tools/extract-pdf-text.d.ts +2 -0
- package/dist/lib/tools/extract-pdf-text.js +92 -0
- package/dist/lib/tools/filter-logs.d.ts +2 -0
- package/dist/lib/tools/filter-logs.js +94 -0
- package/dist/lib/tools/find-github-issues.d.ts +2 -0
- package/dist/lib/tools/find-github-issues.js +176 -0
- package/dist/lib/tools/generate-storyboard-images.d.ts +2 -0
- package/dist/lib/tools/generate-storyboard-images.js +419 -0
- package/dist/lib/tools/log-cli-utils.d.ts +35 -0
- package/dist/lib/tools/log-cli-utils.js +233 -0
- package/dist/lib/tools/open-github-issue.d.ts +2 -0
- package/dist/lib/tools/open-github-issue.js +750 -0
- package/dist/lib/tools/read-github-issue.d.ts +2 -0
- package/dist/lib/tools/read-github-issue.js +134 -0
- package/dist/lib/tools/render-error-book.d.ts +2 -0
- package/dist/lib/tools/render-error-book.js +265 -0
- package/dist/lib/tools/render-katex.d.ts +2 -0
- package/dist/lib/tools/render-katex.js +294 -0
- package/dist/lib/tools/review-threads.d.ts +2 -0
- package/dist/lib/tools/review-threads.js +491 -0
- package/dist/lib/tools/search-logs.d.ts +2 -0
- package/dist/lib/tools/search-logs.js +164 -0
- package/dist/lib/tools/sync-memory-index.d.ts +2 -0
- package/dist/lib/tools/sync-memory-index.js +113 -0
- package/dist/lib/tools/validate-openai-agent-config.d.ts +2 -0
- package/dist/lib/tools/validate-openai-agent-config.js +184 -0
- package/dist/lib/tools/validate-skill-frontmatter.d.ts +2 -0
- package/dist/lib/tools/validate-skill-frontmatter.js +118 -0
- package/dist/lib/types.d.ts +82 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/updater.d.ts +34 -0
- package/dist/lib/updater.js +112 -0
- package/dist/lib/utils/format.d.ts +2 -0
- package/dist/lib/utils/format.js +6 -0
- package/dist/lib/utils/terminal.d.ts +12 -0
- package/dist/lib/utils/terminal.js +26 -0
- package/docs-to-voice/SKILL.md +0 -1
- package/generate-spec/SKILL.md +1 -1
- package/katex/SKILL.md +1 -2
- package/lib/cli.ts +780 -0
- package/lib/installer.ts +466 -0
- package/lib/tool-runner.ts +561 -0
- package/lib/tools/architecture.ts +34 -0
- package/lib/tools/create-specs.ts +204 -0
- package/lib/tools/docs-to-voice.ts +799 -0
- package/lib/tools/enforce-video-aspect-ratio.ts +368 -0
- package/lib/tools/extract-conversations.ts +114 -0
- package/lib/tools/extract-pdf-text.ts +99 -0
- package/lib/tools/filter-logs.ts +118 -0
- package/lib/tools/find-github-issues.ts +211 -0
- package/lib/tools/generate-storyboard-images.ts +455 -0
- package/lib/tools/log-cli-utils.ts +262 -0
- package/lib/tools/open-github-issue.ts +930 -0
- package/lib/tools/read-github-issue.ts +179 -0
- package/lib/tools/render-error-book.ts +300 -0
- package/lib/tools/render-katex.ts +325 -0
- package/lib/tools/review-threads.ts +590 -0
- package/lib/tools/search-logs.ts +200 -0
- package/lib/tools/sync-memory-index.ts +114 -0
- package/lib/tools/validate-openai-agent-config.ts +209 -0
- package/lib/tools/validate-skill-frontmatter.ts +124 -0
- package/lib/types.ts +90 -0
- package/lib/updater.ts +165 -0
- package/lib/utils/format.ts +7 -0
- package/lib/utils/terminal.ts +22 -0
- package/open-github-issue/SKILL.md +2 -2
- package/optimise-skill/SKILL.md +1 -1
- package/package.json +13 -4
- package/resources/project-architecture/assets/architecture.css +764 -0
- package/resources/project-architecture/assets/viewer.client.js +144 -0
- package/resources/project-architecture/index.html +42 -0
- package/review-spec-related-changes/SKILL.md +1 -1
- package/solve-issues-found-during-review/SKILL.md +2 -1
- package/tsconfig.json +28 -0
- package/analyse-app-logs/scripts/__pycache__/filter_logs_by_time.cpython-312.pyc +0 -0
- package/analyse-app-logs/scripts/__pycache__/log_cli_utils.cpython-312.pyc +0 -0
- package/analyse-app-logs/scripts/__pycache__/search_logs.cpython-312.pyc +0 -0
- package/analyse-app-logs/scripts/filter_logs_by_time.py +0 -64
- package/analyse-app-logs/scripts/log_cli_utils.py +0 -112
- package/analyse-app-logs/scripts/search_logs.py +0 -137
- package/analyse-app-logs/tests/test_filter_logs_by_time.py +0 -95
- package/analyse-app-logs/tests/test_search_logs.py +0 -100
- package/codex/codex-memory-manager/scripts/extract_recent_conversations.py +0 -369
- package/codex/codex-memory-manager/scripts/sync_memory_index.py +0 -130
- package/codex/codex-memory-manager/tests/test_extract_recent_conversations.py +0 -177
- package/codex/codex-memory-manager/tests/test_memory_template.py +0 -37
- package/codex/codex-memory-manager/tests/test_sync_memory_index.py +0 -84
- package/codex/learn-skill-from-conversations/scripts/extract_recent_conversations.py +0 -369
- package/codex/learn-skill-from-conversations/tests/test_extract_recent_conversations.py +0 -177
- package/docs-to-voice/scripts/__pycache__/docs_to_voice.cpython-312.pyc +0 -0
- package/docs-to-voice/scripts/docs_to_voice.py +0 -1385
- package/docs-to-voice/scripts/docs_to_voice.sh +0 -11
- package/docs-to-voice/tests/test_docs_to_voice_api_max_chars.py +0 -210
- package/docs-to-voice/tests/test_docs_to_voice_sentence_timeline.py +0 -115
- package/docs-to-voice/tests/test_docs_to_voice_settings.py +0 -43
- package/docs-to-voice/tests/test_docs_to_voice_shell_wrapper.py +0 -51
- package/docs-to-voice/tests/test_docs_to_voice_speech_rate.py +0 -57
- package/generate-spec/scripts/__pycache__/create-specscpython-312.pyc +0 -0
- package/generate-spec/scripts/create-specs +0 -215
- package/generate-spec/tests/test_create_specs.py +0 -200
- package/init-project-html/scripts/architecture-bootstrap-render.js +0 -16
- package/init-project-html/scripts/architecture.js +0 -296
- package/katex/scripts/__pycache__/render_katex.cpython-312.pyc +0 -0
- package/katex/scripts/render_katex.py +0 -247
- package/katex/scripts/render_katex.sh +0 -11
- package/katex/tests/test_render_katex.py +0 -174
- package/learning-error-book/scripts/render_error_book_json_to_pdf.py +0 -590
- package/learning-error-book/tests/test_render_error_book_json_to_pdf.py +0 -134
- package/open-github-issue/scripts/__pycache__/open_github_issue.cpython-312.pyc +0 -0
- package/open-github-issue/scripts/open_github_issue.py +0 -705
- package/open-github-issue/tests/test_open_github_issue.py +0 -381
- package/openai-text-to-image-storyboard/scripts/generate_storyboard_images.py +0 -763
- package/openai-text-to-image-storyboard/tests/test_generate_storyboard_images.py +0 -177
- package/read-github-issue/scripts/__pycache__/find_issues.cpython-312.pyc +0 -0
- package/read-github-issue/scripts/__pycache__/read_issue.cpython-312.pyc +0 -0
- package/read-github-issue/scripts/find_issues.py +0 -148
- package/read-github-issue/scripts/read_issue.py +0 -108
- package/read-github-issue/tests/test_find_issues.py +0 -127
- package/read-github-issue/tests/test_read_issue.py +0 -109
- package/resolve-review-comments/scripts/__pycache__/review_threads.cpython-312.pyc +0 -0
- package/resolve-review-comments/scripts/review_threads.py +0 -425
- package/resolve-review-comments/tests/test_review_threads.py +0 -74
- package/scripts/validate_openai_agent_config.py +0 -209
- package/scripts/validate_skill_frontmatter.py +0 -131
- package/text-to-short-video/scripts/__pycache__/enforce_video_aspect_ratio.cpython-312.pyc +0 -0
- package/text-to-short-video/scripts/enforce_video_aspect_ratio.py +0 -350
- package/text-to-short-video/tests/test_enforce_video_aspect_ratio.py +0 -194
- package/weekly-financial-event-report/scripts/extract_pdf_text_pdfkit.swift +0 -99
- package/weekly-financial-event-report/tests/test_extract_pdf_text_pdfkit.py +0 -64
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { createReadStream } from 'node:fs';
|
|
2
|
+
import { createInterface } from 'node:readline/promises';
|
|
3
|
+
import { Readable } from 'node:stream';
|
|
4
|
+
|
|
5
|
+
const TIMESTAMP_PATTERN =
|
|
6
|
+
/(?<timestamp>\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[.,]\d+)?(?:Z|[+-]\d{2}:\d{2})?)/;
|
|
7
|
+
|
|
8
|
+
const TIMESTAMP_FORMATS = [
|
|
9
|
+
'%Y-%m-%dT%H:%M:%S.%f%z',
|
|
10
|
+
'%Y-%m-%dT%H:%M:%S%z',
|
|
11
|
+
'%Y-%m-%d %H:%M:%S.%f%z',
|
|
12
|
+
'%Y-%m-%d %H:%M:%S%z',
|
|
13
|
+
'%Y-%m-%dT%H:%M:%S.%f',
|
|
14
|
+
'%Y-%m-%dT%H:%M:%S',
|
|
15
|
+
'%Y-%m-%d %H:%M:%S.%f',
|
|
16
|
+
'%Y-%m-%d %H:%M:%S',
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
/** Convert strftime-style format string to a regex and time-component extractors. */
|
|
20
|
+
function parseWithFormat(
|
|
21
|
+
value: string,
|
|
22
|
+
fmt: string,
|
|
23
|
+
assumeTimezone: string,
|
|
24
|
+
): Date | null {
|
|
25
|
+
// Build a regex from the format string by replacing format specifiers
|
|
26
|
+
let regexStr = '';
|
|
27
|
+
let i = 0;
|
|
28
|
+
const groups: { name: string; width: number }[] = [];
|
|
29
|
+
|
|
30
|
+
while (i < fmt.length) {
|
|
31
|
+
if (fmt[i] === '%' && i + 1 < fmt.length) {
|
|
32
|
+
switch (fmt[i + 1]) {
|
|
33
|
+
case 'Y':
|
|
34
|
+
regexStr += '(\\d{4})';
|
|
35
|
+
groups.push({ name: 'year', width: 4 });
|
|
36
|
+
break;
|
|
37
|
+
case 'm':
|
|
38
|
+
regexStr += '(\\d{2})';
|
|
39
|
+
groups.push({ name: 'month', width: 2 });
|
|
40
|
+
break;
|
|
41
|
+
case 'd':
|
|
42
|
+
regexStr += '(\\d{2})';
|
|
43
|
+
groups.push({ name: 'day', width: 2 });
|
|
44
|
+
break;
|
|
45
|
+
case 'H':
|
|
46
|
+
regexStr += '(\\d{2})';
|
|
47
|
+
groups.push({ name: 'hour', width: 2 });
|
|
48
|
+
break;
|
|
49
|
+
case 'M':
|
|
50
|
+
regexStr += '(\\d{2})';
|
|
51
|
+
groups.push({ name: 'minute', width: 2 });
|
|
52
|
+
break;
|
|
53
|
+
case 'S':
|
|
54
|
+
regexStr += '(\\d{2})';
|
|
55
|
+
groups.push({ name: 'second', width: 2 });
|
|
56
|
+
break;
|
|
57
|
+
case 'f':
|
|
58
|
+
regexStr += '(\\d+)';
|
|
59
|
+
groups.push({ name: 'frac', width: 0 });
|
|
60
|
+
break;
|
|
61
|
+
case 'z':
|
|
62
|
+
regexStr += '([+-]\\d{2}:\\d{2})';
|
|
63
|
+
groups.push({ name: 'tz', width: 0 });
|
|
64
|
+
break;
|
|
65
|
+
default:
|
|
66
|
+
regexStr += '\\' + fmt[i + 1];
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
i += 2;
|
|
70
|
+
} else {
|
|
71
|
+
regexStr += fmt[i].replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
72
|
+
i++;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const match = value.match(new RegExp('^' + regexStr + '$'));
|
|
77
|
+
if (!match) return null;
|
|
78
|
+
|
|
79
|
+
const extract = (name: string): number => {
|
|
80
|
+
const idx = groups.findIndex((g) => g.name === name);
|
|
81
|
+
if (idx === -1) return 0;
|
|
82
|
+
return parseInt(match[idx + 1] || '0', 10);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const hasTimezone = groups.some((g) => g.name === 'tz');
|
|
86
|
+
const tzGroup = hasTimezone ? match[groups.findIndex((g) => g.name === 'tz') + 1] : null;
|
|
87
|
+
const fracRaw = groups.some((g) => g.name === 'frac')
|
|
88
|
+
? match[groups.findIndex((g) => g.name === 'frac') + 1]
|
|
89
|
+
: null;
|
|
90
|
+
|
|
91
|
+
const year = extract('year');
|
|
92
|
+
const month = extract('month') - 1; // 0-indexed
|
|
93
|
+
const day = extract('day');
|
|
94
|
+
const hour = extract('hour');
|
|
95
|
+
const minute = extract('minute');
|
|
96
|
+
const second = extract('second');
|
|
97
|
+
let milliseconds = 0;
|
|
98
|
+
if (fracRaw != null) {
|
|
99
|
+
const padded = fracRaw.padEnd(3, '0').slice(0, 3);
|
|
100
|
+
milliseconds = parseInt(padded, 10);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (tzGroup) {
|
|
104
|
+
const sign = tzGroup[0] === '-' ? -1 : 1;
|
|
105
|
+
const tzHours = parseInt(tzGroup.slice(1, 3), 10);
|
|
106
|
+
const tzMinutes = parseInt(tzGroup.slice(4, 6), 10);
|
|
107
|
+
const offsetMinutes = sign * (tzHours * 60 + tzMinutes);
|
|
108
|
+
const date = new Date(Date.UTC(year, month, day, hour, minute - offsetMinutes, second, milliseconds));
|
|
109
|
+
return date;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// No timezone in format -> assume timezone
|
|
113
|
+
return applyTimezone(
|
|
114
|
+
new Date(year, month, day, hour, minute, second, milliseconds),
|
|
115
|
+
assumeTimezone,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function applyTimezone(date: Date, assumeTimezone: string): Date {
|
|
120
|
+
const tzMinutes = parseTimezoneOffset(assumeTimezone);
|
|
121
|
+
const localMinutes = date.getTimezoneOffset();
|
|
122
|
+
// Convert from local to assumed timezone by adjusting offset difference
|
|
123
|
+
return new Date(date.getTime() + (localMinutes + tzMinutes) * 60 * 1000);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function parseTimezoneOffset(raw: string): number {
|
|
127
|
+
const upper = raw.toUpperCase();
|
|
128
|
+
if (upper === 'UTC' || upper === 'Z') return 0;
|
|
129
|
+
|
|
130
|
+
const match = /^([+-])(\d{2}):(\d{2})$/.exec(raw);
|
|
131
|
+
if (!match) throw new Error(`timezone must be UTC or ±HH:MM, got: ${raw}`);
|
|
132
|
+
|
|
133
|
+
const totalMinutes = parseInt(match[2], 10) * 60 + parseInt(match[3], 10);
|
|
134
|
+
return match[1] === '-' ? -totalMinutes : totalMinutes;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Normalize a raw timestamp string: strip whitespace, replace comma with dot,
|
|
139
|
+
* and convert trailing Z to +00:00.
|
|
140
|
+
*/
|
|
141
|
+
export function normalizeTimestamp(raw: string): string {
|
|
142
|
+
const value = raw.trim().replace(',', '.');
|
|
143
|
+
if (value.endsWith('Z')) {
|
|
144
|
+
return value.slice(0, -1) + '+00:00';
|
|
145
|
+
}
|
|
146
|
+
return value;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Parse a CLI-provided timestamp string into a Date.
|
|
151
|
+
* Naive timestamps are assigned the assumeTimezone offset.
|
|
152
|
+
*/
|
|
153
|
+
export function parseCliTimestamp(raw: string, assumeTimezone: string): Date {
|
|
154
|
+
const normalized = normalizeTimestamp(raw);
|
|
155
|
+
for (const fmt of TIMESTAMP_FORMATS) {
|
|
156
|
+
const parsed = parseWithFormat(normalized, fmt, assumeTimezone);
|
|
157
|
+
if (parsed) {
|
|
158
|
+
return parsed;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
throw new Error(`invalid timestamp: ${raw}`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Extract an ISO 8601 timestamp from a log line and parse it into a Date.
|
|
166
|
+
* Returns null if no timestamp is found or parsing fails.
|
|
167
|
+
*/
|
|
168
|
+
export function extractTimestamp(
|
|
169
|
+
line: string,
|
|
170
|
+
assumeTimezone: string,
|
|
171
|
+
): Date | null {
|
|
172
|
+
const match = TIMESTAMP_PATTERN.exec(line);
|
|
173
|
+
if (!match || !match.groups?.timestamp) return null;
|
|
174
|
+
try {
|
|
175
|
+
return parseCliTimestamp(match.groups.timestamp, assumeTimezone);
|
|
176
|
+
} catch {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Build a timezone offset in minutes from a timezone string.
|
|
183
|
+
* Supports "UTC" and "±HH:MM" formats.
|
|
184
|
+
*/
|
|
185
|
+
export function buildTimezone(raw: string): number {
|
|
186
|
+
return parseTimezoneOffset(raw);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Validate that start is not later than end.
|
|
191
|
+
* Writes an error message to stderr and returns false if the order is inverted.
|
|
192
|
+
*/
|
|
193
|
+
export function validateTimeWindow(
|
|
194
|
+
start: Date | null,
|
|
195
|
+
end: Date | null,
|
|
196
|
+
stderr: NodeJS.WriteStream,
|
|
197
|
+
): boolean {
|
|
198
|
+
if (start && end && start > end) {
|
|
199
|
+
stderr.write('Error: --start must be earlier than or equal to --end.\n');
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Check whether a timestamp falls within a given [start, end] window (inclusive).
|
|
207
|
+
* Returns false if timestamp is null.
|
|
208
|
+
*/
|
|
209
|
+
export function inWindow(
|
|
210
|
+
timestamp: Date | null,
|
|
211
|
+
start: Date | null,
|
|
212
|
+
end: Date | null,
|
|
213
|
+
): boolean {
|
|
214
|
+
if (timestamp === null) return false;
|
|
215
|
+
if (start !== null && timestamp < start) return false;
|
|
216
|
+
if (end !== null && timestamp > end) return false;
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Iterate over lines from file paths or stdin.
|
|
222
|
+
* When paths is empty or contains "-", reads from stdin.
|
|
223
|
+
*/
|
|
224
|
+
export async function* iterInputLines(
|
|
225
|
+
paths: string[],
|
|
226
|
+
): AsyncGenerator<string> {
|
|
227
|
+
if (paths.length === 0) {
|
|
228
|
+
yield* readStdinLines();
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
for (const rawPath of paths) {
|
|
233
|
+
if (rawPath === '-') {
|
|
234
|
+
yield* readStdinLines();
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
yield* readFileLines(rawPath);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
async function* readStdinLines(): AsyncGenerator<string> {
|
|
242
|
+
const rl = createInterface({
|
|
243
|
+
input: process.stdin,
|
|
244
|
+
crlfDelay: Infinity,
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
for await (const line of rl) {
|
|
248
|
+
yield line;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async function* readFileLines(filePath: string): AsyncGenerator<string> {
|
|
253
|
+
const fileStream = createReadStream(filePath, { encoding: 'utf-8' });
|
|
254
|
+
const rl = createInterface({
|
|
255
|
+
input: fileStream,
|
|
256
|
+
crlfDelay: Infinity,
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
for await (const line of rl) {
|
|
260
|
+
yield line;
|
|
261
|
+
}
|
|
262
|
+
}
|