pi-readseek 0.1.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 (67) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +41 -0
  3. package/index.ts +142 -0
  4. package/package.json +73 -0
  5. package/prompts/edit.md +113 -0
  6. package/prompts/find.md +19 -0
  7. package/prompts/grep.md +26 -0
  8. package/prompts/ls.md +11 -0
  9. package/prompts/read.md +33 -0
  10. package/prompts/sg.md +25 -0
  11. package/prompts/write.md +46 -0
  12. package/src/binary-detect.ts +22 -0
  13. package/src/binary-resolution.ts +77 -0
  14. package/src/coerce-obvious-int.ts +39 -0
  15. package/src/context-application.ts +70 -0
  16. package/src/context-hygiene.ts +503 -0
  17. package/src/diff-data.ts +303 -0
  18. package/src/doom-loop-suggestions.ts +42 -0
  19. package/src/doom-loop.ts +216 -0
  20. package/src/edit-classify.ts +190 -0
  21. package/src/edit-diff.ts +354 -0
  22. package/src/edit-output.ts +107 -0
  23. package/src/edit-render-helpers.ts +141 -0
  24. package/src/edit-syntax-validate.ts +120 -0
  25. package/src/edit.ts +725 -0
  26. package/src/find-parsers.ts +89 -0
  27. package/src/find-stat.ts +36 -0
  28. package/src/find.ts +613 -0
  29. package/src/grep-budget.ts +79 -0
  30. package/src/grep-output.ts +197 -0
  31. package/src/grep-render-helpers.ts +77 -0
  32. package/src/grep-symbol-scope.ts +197 -0
  33. package/src/grep.ts +792 -0
  34. package/src/hashline.ts +747 -0
  35. package/src/ls.ts +293 -0
  36. package/src/map-cache.ts +152 -0
  37. package/src/path-utils.ts +24 -0
  38. package/src/pending-diff-preview.ts +269 -0
  39. package/src/persistent-map-cache.ts +251 -0
  40. package/src/read-local-bundle.ts +87 -0
  41. package/src/read-output.ts +212 -0
  42. package/src/read-render-helpers.ts +104 -0
  43. package/src/read.ts +748 -0
  44. package/src/readseek/constants.ts +21 -0
  45. package/src/readseek/enums.ts +38 -0
  46. package/src/readseek/formatter.ts +431 -0
  47. package/src/readseek/language-detect.ts +29 -0
  48. package/src/readseek/mapper.ts +69 -0
  49. package/src/readseek/parser-errors.ts +22 -0
  50. package/src/readseek/parser-loader.ts +83 -0
  51. package/src/readseek/symbol-error-format.ts +18 -0
  52. package/src/readseek/symbol-lookup.ts +294 -0
  53. package/src/readseek/types.ts +79 -0
  54. package/src/readseek-client.ts +343 -0
  55. package/src/readseek-error-codes.ts +54 -0
  56. package/src/readseek-settings.ts +287 -0
  57. package/src/readseek-value.ts +144 -0
  58. package/src/replace-symbol.ts +74 -0
  59. package/src/runtime.ts +3 -0
  60. package/src/sg-output.ts +88 -0
  61. package/src/sg.ts +308 -0
  62. package/src/syntax-validate-mode.ts +25 -0
  63. package/src/tool-prompt-metadata.ts +76 -0
  64. package/src/tui-diff-component.ts +86 -0
  65. package/src/tui-diff-renderer.ts +92 -0
  66. package/src/tui-render-utils.ts +129 -0
  67. package/src/write.ts +532 -0
@@ -0,0 +1,89 @@
1
+ const SIZE_MULTIPLIERS: Record<string, number> = {
2
+ "": 1,
3
+ B: 1,
4
+ K: 1024,
5
+ KB: 1024,
6
+ M: 1024 * 1024,
7
+ MB: 1024 * 1024,
8
+ G: 1024 ** 3,
9
+ GB: 1024 ** 3,
10
+ };
11
+
12
+ export function parseSize(field: string, value: number | string): number {
13
+ if (typeof value === "number") {
14
+ if (!Number.isFinite(value) || value < 0) {
15
+ throw new Error(
16
+ `Invalid ${field} value: ${value} (expected a non-negative number of bytes)`,
17
+ );
18
+ }
19
+ return value;
20
+ }
21
+
22
+ const match = /^\s*(\d+(?:\.\d+)?)\s*([a-zA-Z]*)\s*$/.exec(value);
23
+ if (!match) {
24
+ throw new Error(
25
+ `Invalid ${field} value: ${JSON.stringify(value)} ` +
26
+ `(expected a number with optional B/K/KB/M/MB/G/GB suffix; units are 1024-based)`,
27
+ );
28
+ }
29
+
30
+ const num = parseFloat(match[1]);
31
+ const suffix = match[2].toUpperCase();
32
+ const mult = SIZE_MULTIPLIERS[suffix];
33
+ if (mult === undefined) {
34
+ throw new Error(
35
+ `Invalid ${field} value: ${JSON.stringify(value)} ` +
36
+ `(unknown unit '${match[2]}'; accepted: B, K, KB, M, MB, G, GB)`,
37
+ );
38
+ }
39
+
40
+ return Math.round(num * mult);
41
+ }
42
+
43
+ const RELATIVE_UNIT_MS: Record<string, number> = {
44
+ m: 60 * 1000,
45
+ h: 60 * 60 * 1000,
46
+ d: 24 * 60 * 60 * 1000,
47
+ };
48
+
49
+ const ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
50
+ const ISO_TS_RE =
51
+ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
52
+
53
+ export function parseRelativeOrIsoDate(
54
+ field: string,
55
+ value: string,
56
+ now: Date = new Date(),
57
+ ): Date {
58
+ if (typeof value !== "string" || value.length === 0) {
59
+ throw new Error(
60
+ `Invalid ${field} value: ${JSON.stringify(value)} ` +
61
+ `(expected ISO date/timestamp or relative shorthand like '1h', '24h', '7d', '30m')`,
62
+ );
63
+ }
64
+
65
+ const rel = /^\s*(\d+)\s*([mhd])\s*$/.exec(value);
66
+ if (rel) {
67
+ const n = parseInt(rel[1], 10);
68
+ return new Date(now.getTime() - n * RELATIVE_UNIT_MS[rel[2]]);
69
+ }
70
+
71
+ if (ISO_DATE_RE.test(value)) {
72
+ const parsed = new Date(`${value}T00:00:00.000Z`);
73
+ if (!Number.isNaN(parsed.getTime())) {
74
+ return parsed;
75
+ }
76
+ }
77
+
78
+ if (ISO_TS_RE.test(value)) {
79
+ const parsed = new Date(value);
80
+ if (!Number.isNaN(parsed.getTime())) {
81
+ return parsed;
82
+ }
83
+ }
84
+
85
+ throw new Error(
86
+ `Invalid ${field} value: ${JSON.stringify(value)} ` +
87
+ `(expected ISO date/timestamp or relative shorthand like '1h', '24h', '7d', '30m')`,
88
+ );
89
+ }
@@ -0,0 +1,36 @@
1
+ import * as fsPromises from "node:fs/promises";
2
+ import type { Stats } from "node:fs";
3
+ import { resolve as resolvePath } from "node:path";
4
+
5
+ export const DEFAULT_STAT_CONCURRENCY = 32;
6
+ export const _testable = {
7
+ stat: fsPromises.stat,
8
+ };
9
+
10
+ export async function statAllWithConcurrency(
11
+ relPaths: string[],
12
+ baseDir: string,
13
+ concurrency: number = DEFAULT_STAT_CONCURRENCY,
14
+ ): Promise<(Stats | null)[]> {
15
+ const requested = Number.isFinite(concurrency)
16
+ ? concurrency
17
+ : DEFAULT_STAT_CONCURRENCY;
18
+ const limit = Math.max(1, Math.min(requested, DEFAULT_STAT_CONCURRENCY));
19
+ const out: (Stats | null)[] = new Array(relPaths.length).fill(null);
20
+ let next = 0;
21
+
22
+ async function worker() {
23
+ while (true) {
24
+ const i = next++;
25
+ if (i >= relPaths.length) return;
26
+ try {
27
+ out[i] = await _testable.stat(resolvePath(baseDir, relPaths[i]));
28
+ } catch {
29
+ out[i] = null;
30
+ }
31
+ }
32
+ }
33
+
34
+ await Promise.all(Array.from({ length: Math.min(limit, relPaths.length) }, () => worker()));
35
+ return out;
36
+ }