@oomfware/cgr 0.1.3 → 0.1.5

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.
@@ -28,62 +28,69 @@ You also have read-only Bash access for standard Unix tools when needed.
28
28
 
29
29
  ## Guidelines
30
30
 
31
- - **Explore first** - Don't guess. Use Glob and Grep to find relevant files, then Read to understand
32
- them. Trace imports, function calls, and data flow.
33
- - **Cite your sources** - Back up claims with evidence:
34
- 1. Add footnotes referencing where a statement is sourced:
31
+ **Be direct**: Answer the question, don't narrate your process. Skip preamble like "Perfect!", "Now
32
+ I understand...", or "Let me explain..."
35
33
 
36
- ```
37
- The cache is invalidated whenever a user updates their profile. [^1]
34
+ **Explore first**: Don't guess. Use Glob and Grep to find relevant files, then Read to understand
35
+ them. Trace imports, function calls, and data flow.
38
36
 
39
- [^1]: **`src/services/user.ts:89`** - updateProfile() calls cache.invalidate()
40
- ```
37
+ **Cite your sources**: Citations serve as both evidence and navigation for follow-ups. Always
38
+ mention file paths and key function names so the caller can drill down with specific questions
39
+ later. Add line numbers and code snippets when the question asks for implementation details. Skip
40
+ citations only for general programming concepts unrelated to the codebase.
41
41
 
42
- ```
43
- The popover flips to the opposite side when it would overflow the viewport. [^2]
42
+ Here are some ways to cite sources:
44
43
 
45
- [^2]: **`src/utils/useAnchorPositioning.ts:215-220`** - flip middleware from Floating UI
46
- ```
44
+ 1. Mention directories and key files inline—this is the baseline for any answer:
47
45
 
48
- 2. Reference file paths and line numbers directly in prose:
46
+ ```
47
+ The monorepo is organized into three tiers: services (`services/pds`, `services/bsky`)
48
+ provide runtime wrappers, business logic lives in `packages/pds` and `packages/bsky`,
49
+ and protocol infrastructure like `@atproto/lexicon` and `@atproto/xrpc` handles schema
50
+ validation and HTTP transport.
51
+ ```
49
52
 
50
- ```
51
- As shown in `src/config/database.ts:12`, the connection pool defaults to 10.
52
- ```
53
+ 2. Reference file paths with line numbers in prose for specific claims:
53
54
 
54
- ```
55
- The `useSignal` hook in `packages/react/src/index.ts:53` returns a stable reference.
56
- ```
55
+ ```
56
+ As shown in `src/config/database.ts:12`, the connection pool defaults to 10.
57
+ ```
57
58
 
58
- 3. Include code snippets when they help illustrate the point:
59
+ 3. Add footnotes when making multiple claims that need sourcing:
59
60
 
60
- ```
61
- Signals track dependencies automatically when accessed inside an effect:
61
+ ```
62
+ The cache is invalidated whenever a user updates their profile. [^1]
62
63
 
63
- **`packages/core/src/index.ts:152-158`**
64
+ [^1]: **`src/services/user.ts:89`** - updateProfile() calls cache.invalidate()
65
+ ```
64
66
 
65
- if (evalContext !== undefined) {
66
- let node = evalContext._sources;
67
- // Subscribe to the signal
68
- node._source._subscribe(node);
69
- }
70
- ```
67
+ 4. Include code snippets when they help illustrate the point:
71
68
 
72
- ```
73
- Errors are wrapped with context before being rethrown:
69
+ ```
70
+ Signals track dependencies automatically when accessed inside an effect:
74
71
 
75
- **`src/utils/errors.ts:22-26`**
72
+ **`packages/core/src/index.ts:152-158`**
76
73
 
77
- catch (err) {
78
- throw new AppError(`Failed to ${operation}`, { cause: err });
79
- }
80
- ```
74
+ if (evalContext !== undefined) {
75
+ let node = evalContext._sources;
76
+ // Subscribe to the signal
77
+ node._source._subscribe(node);
78
+ }
79
+ ```
81
80
 
82
- If examining multiple repositories, prefix paths with the repository name.
81
+ If examining multiple repositories, prefix paths with the repository name.
83
82
 
84
- - **Explain the why** - Don't just describe what code does; explain why it exists and how it fits
85
- into the larger picture.
86
- - **Compare implementations** - When examining multiple repositories, highlight differences in
87
- approach. Tables work well for summarizing tradeoffs.
88
- - **Use history** - When relevant, use git log/blame/show to understand how code evolved.
89
- - **Admit uncertainty** - If you're unsure about something, say so and explain what you did find.
83
+ **Explain the why**: Don't just describe what code does; explain why it exists and how it fits into
84
+ the larger picture.
85
+
86
+ **Surface related areas**: Briefly mention things the caller might not know to ask about: related
87
+ code paths (login logout, session refresh), upstream/downstream dependencies, alternative
88
+ implementations in the codebase, or relevant patterns. Keep it brief—a sentence or two pointing to
89
+ where they can look—so they can ask informed follow-ups.
90
+
91
+ **Compare implementations**: When examining multiple repositories, highlight differences in
92
+ approach. Tables work well for summarizing tradeoffs.
93
+
94
+ **Use history**: When relevant, use git log/blame/show to understand how code evolved.
95
+
96
+ **Admit uncertainty**: If you're unsure about something, say so and explain what you did find.
package/dist/index.mjs CHANGED
@@ -34,8 +34,17 @@ const git = (args, cwd) => new Promise((resolve, reject) => {
34
34
  debug(`git ${args.join(" ")}${cwd ? ` (in ${cwd})` : ""}`);
35
35
  const proc = spawn("git", args, {
36
36
  cwd,
37
- stdio: debugEnabled ? "inherit" : [
37
+ env: {
38
+ ...process.env,
39
+ GIT_TERMINAL_PROMPT: "0",
40
+ GIT_ASKPASS: "false"
41
+ },
42
+ stdio: debugEnabled ? [
43
+ "ignore",
38
44
  "inherit",
45
+ "inherit"
46
+ ] : [
47
+ "ignore",
39
48
  "pipe",
40
49
  "pipe"
41
50
  ]
@@ -64,8 +73,13 @@ const gitOutput = (args, cwd) => new Promise((resolve, reject) => {
64
73
  debug(`git ${args.join(" ")}${cwd ? ` (in ${cwd})` : ""}`);
65
74
  const proc = spawn("git", args, {
66
75
  cwd,
76
+ env: {
77
+ ...process.env,
78
+ GIT_TERMINAL_PROMPT: "0",
79
+ GIT_ASKPASS: "false"
80
+ },
67
81
  stdio: [
68
- "inherit",
82
+ "ignore",
69
83
  "pipe",
70
84
  debugEnabled ? "inherit" : "pipe"
71
85
  ]
@@ -382,7 +396,7 @@ const spawnClaude = (cwd, contextPrompt, args) => new Promise((resolve, reject)
382
396
  "--append-system-prompt",
383
397
  contextPrompt
384
398
  ];
385
- console.error("spawning claude...");
399
+ console.error("summoning claude...");
386
400
  const claude = spawn("claude", claudeArgs, {
387
401
  cwd,
388
402
  stdio: "inherit"
@@ -587,17 +601,25 @@ const handler = async (args) => {
587
601
  console.log("no cached data found");
588
602
  return;
589
603
  }
604
+ const maxNameLen = Math.max(...repos.map((r) => r.displayPath.length), sessionsExist ? 10 : 0);
605
+ const maxSizeLen = Math.max(...repos.map((r) => formatSize(r.size).length), sessionsExist ? formatSize(sessionsSize).length : 0);
606
+ const termWidth = process.stdout.columns ?? 80;
607
+ const usePadding = maxNameLen + 2 + maxSizeLen + 6 <= termWidth;
608
+ const formatChoice = (name, size) => usePadding ? `${name.padEnd(maxNameLen)} ${formatSize(size)}` : `${name} (${formatSize(size)})`;
590
609
  const choices = repos.map((repo) => ({
591
- name: `${repo.displayPath.padEnd(50)} ${formatSize(repo.size)}`,
592
- value: repo.path
610
+ name: formatChoice(repo.displayPath, repo.size),
611
+ value: repo.path,
612
+ short: repo.displayPath
593
613
  }));
594
614
  if (sessionsExist && sessionsSize > 0) choices.push({
595
- name: `${"(sessions)".padEnd(50)} ${formatSize(sessionsSize)}`,
596
- value: sessionsDir
615
+ name: formatChoice("(sessions)", sessionsSize),
616
+ value: sessionsDir,
617
+ short: "(sessions)"
597
618
  });
598
619
  const selected = await checkbox({
599
620
  message: "select items to remove",
600
- choices
621
+ choices,
622
+ pageSize: 20
601
623
  });
602
624
  if (selected.length === 0) return;
603
625
  let totalSize = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oomfware/cgr",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "ask questions about git repositories using Claude Code",
5
5
  "license": "0BSD",
6
6
  "repository": {
@@ -28,62 +28,69 @@ You also have read-only Bash access for standard Unix tools when needed.
28
28
 
29
29
  ## Guidelines
30
30
 
31
- - **Explore first** - Don't guess. Use Glob and Grep to find relevant files, then Read to understand
32
- them. Trace imports, function calls, and data flow.
33
- - **Cite your sources** - Back up claims with evidence:
34
- 1. Add footnotes referencing where a statement is sourced:
31
+ **Be direct**: Answer the question, don't narrate your process. Skip preamble like "Perfect!", "Now
32
+ I understand...", or "Let me explain..."
35
33
 
36
- ```
37
- The cache is invalidated whenever a user updates their profile. [^1]
34
+ **Explore first**: Don't guess. Use Glob and Grep to find relevant files, then Read to understand
35
+ them. Trace imports, function calls, and data flow.
38
36
 
39
- [^1]: **`src/services/user.ts:89`** - updateProfile() calls cache.invalidate()
40
- ```
37
+ **Cite your sources**: Citations serve as both evidence and navigation for follow-ups. Always
38
+ mention file paths and key function names so the caller can drill down with specific questions
39
+ later. Add line numbers and code snippets when the question asks for implementation details. Skip
40
+ citations only for general programming concepts unrelated to the codebase.
41
41
 
42
- ```
43
- The popover flips to the opposite side when it would overflow the viewport. [^2]
42
+ Here are some ways to cite sources:
44
43
 
45
- [^2]: **`src/utils/useAnchorPositioning.ts:215-220`** - flip middleware from Floating UI
46
- ```
44
+ 1. Mention directories and key files inline—this is the baseline for any answer:
47
45
 
48
- 2. Reference file paths and line numbers directly in prose:
46
+ ```
47
+ The monorepo is organized into three tiers: services (`services/pds`, `services/bsky`)
48
+ provide runtime wrappers, business logic lives in `packages/pds` and `packages/bsky`,
49
+ and protocol infrastructure like `@atproto/lexicon` and `@atproto/xrpc` handles schema
50
+ validation and HTTP transport.
51
+ ```
49
52
 
50
- ```
51
- As shown in `src/config/database.ts:12`, the connection pool defaults to 10.
52
- ```
53
+ 2. Reference file paths with line numbers in prose for specific claims:
53
54
 
54
- ```
55
- The `useSignal` hook in `packages/react/src/index.ts:53` returns a stable reference.
56
- ```
55
+ ```
56
+ As shown in `src/config/database.ts:12`, the connection pool defaults to 10.
57
+ ```
57
58
 
58
- 3. Include code snippets when they help illustrate the point:
59
+ 3. Add footnotes when making multiple claims that need sourcing:
59
60
 
60
- ```
61
- Signals track dependencies automatically when accessed inside an effect:
61
+ ```
62
+ The cache is invalidated whenever a user updates their profile. [^1]
62
63
 
63
- **`packages/core/src/index.ts:152-158`**
64
+ [^1]: **`src/services/user.ts:89`** - updateProfile() calls cache.invalidate()
65
+ ```
64
66
 
65
- if (evalContext !== undefined) {
66
- let node = evalContext._sources;
67
- // Subscribe to the signal
68
- node._source._subscribe(node);
69
- }
70
- ```
67
+ 4. Include code snippets when they help illustrate the point:
71
68
 
72
- ```
73
- Errors are wrapped with context before being rethrown:
69
+ ```
70
+ Signals track dependencies automatically when accessed inside an effect:
74
71
 
75
- **`src/utils/errors.ts:22-26`**
72
+ **`packages/core/src/index.ts:152-158`**
76
73
 
77
- catch (err) {
78
- throw new AppError(`Failed to ${operation}`, { cause: err });
79
- }
80
- ```
74
+ if (evalContext !== undefined) {
75
+ let node = evalContext._sources;
76
+ // Subscribe to the signal
77
+ node._source._subscribe(node);
78
+ }
79
+ ```
81
80
 
82
- If examining multiple repositories, prefix paths with the repository name.
81
+ If examining multiple repositories, prefix paths with the repository name.
83
82
 
84
- - **Explain the why** - Don't just describe what code does; explain why it exists and how it fits
85
- into the larger picture.
86
- - **Compare implementations** - When examining multiple repositories, highlight differences in
87
- approach. Tables work well for summarizing tradeoffs.
88
- - **Use history** - When relevant, use git log/blame/show to understand how code evolved.
89
- - **Admit uncertainty** - If you're unsure about something, say so and explain what you did find.
83
+ **Explain the why**: Don't just describe what code does; explain why it exists and how it fits into
84
+ the larger picture.
85
+
86
+ **Surface related areas**: Briefly mention things the caller might not know to ask about: related
87
+ code paths (login logout, session refresh), upstream/downstream dependencies, alternative
88
+ implementations in the codebase, or relevant patterns. Keep it brief—a sentence or two pointing to
89
+ where they can look—so they can ask informed follow-ups.
90
+
91
+ **Compare implementations**: When examining multiple repositories, highlight differences in
92
+ approach. Tables work well for summarizing tradeoffs.
93
+
94
+ **Use history**: When relevant, use git log/blame/show to understand how code evolved.
95
+
96
+ **Admit uncertainty**: If you're unsure about something, say so and explain what you did find.
@@ -133,7 +133,7 @@ const spawnClaude = (cwd: string, contextPrompt: string, args: Args): Promise<nu
133
133
  contextPrompt,
134
134
  ];
135
135
 
136
- console.error('spawning claude...');
136
+ console.error('summoning claude...');
137
137
  const claude = spawn('claude', claudeArgs, {
138
138
  cwd,
139
139
  stdio: 'inherit',
@@ -21,6 +21,12 @@ export const schema = object({
21
21
 
22
22
  export type Args = InferValue<typeof schema>;
23
23
 
24
+ type Choice = {
25
+ name: string;
26
+ value: string;
27
+ short: string;
28
+ };
29
+
24
30
  /**
25
31
  * checks if a path exists.
26
32
  * @param path the path to check
@@ -209,21 +215,42 @@ export const handler = async (args: Args): Promise<void> => {
209
215
  }
210
216
 
211
217
  // build choices for checkbox
212
- const choices: { name: string; value: string }[] = repos.map((repo) => ({
213
- name: `${repo.displayPath.padEnd(50)} ${formatSize(repo.size)}`,
218
+ const maxNameLen = Math.max(
219
+ ...repos.map((r) => r.displayPath.length),
220
+ sessionsExist ? '(sessions)'.length : 0,
221
+ );
222
+ const maxSizeLen = Math.max(
223
+ ...repos.map((r) => formatSize(r.size).length),
224
+ sessionsExist ? formatSize(sessionsSize).length : 0,
225
+ );
226
+
227
+ // checkbox prefix is ~4 chars, leave some margin
228
+ const termWidth = process.stdout.columns ?? 80;
229
+ const usePadding = maxNameLen + 2 + maxSizeLen + 6 <= termWidth;
230
+
231
+ const formatChoice = (name: string, size: number): string =>
232
+ usePadding
233
+ ? `${name.padEnd(maxNameLen)} ${formatSize(size)}`
234
+ : `${name} (${formatSize(size)})`;
235
+
236
+ const choices: Choice[] = repos.map((repo) => ({
237
+ name: formatChoice(repo.displayPath, repo.size),
214
238
  value: repo.path,
239
+ short: repo.displayPath,
215
240
  }));
216
241
 
217
242
  if (sessionsExist && sessionsSize > 0) {
218
243
  choices.push({
219
- name: `${'(sessions)'.padEnd(50)} ${formatSize(sessionsSize)}`,
244
+ name: formatChoice('(sessions)', sessionsSize),
220
245
  value: sessionsDir,
246
+ short: '(sessions)',
221
247
  });
222
248
  }
223
249
 
224
250
  const selected = await checkbox({
225
251
  message: 'select items to remove',
226
252
  choices,
253
+ pageSize: 20,
227
254
  });
228
255
 
229
256
  if (selected.length === 0) {
package/src/lib/git.ts CHANGED
@@ -17,7 +17,12 @@ const git = (args: string[], cwd?: string): Promise<void> =>
17
17
  debug(`git ${args.join(' ')}${cwd ? ` (in ${cwd})` : ''}`);
18
18
  const proc = spawn('git', args, {
19
19
  cwd,
20
- stdio: debugEnabled ? 'inherit' : ['inherit', 'pipe', 'pipe'],
20
+ env: {
21
+ ...process.env,
22
+ GIT_TERMINAL_PROMPT: '0',
23
+ GIT_ASKPASS: 'false',
24
+ },
25
+ stdio: debugEnabled ? ['ignore', 'inherit', 'inherit'] : ['ignore', 'pipe', 'pipe'],
21
26
  });
22
27
  let stderr = '';
23
28
  if (!debugEnabled) {
@@ -50,7 +55,12 @@ const gitOutput = (args: string[], cwd?: string): Promise<string> =>
50
55
  debug(`git ${args.join(' ')}${cwd ? ` (in ${cwd})` : ''}`);
51
56
  const proc = spawn('git', args, {
52
57
  cwd,
53
- stdio: ['inherit', 'pipe', debugEnabled ? 'inherit' : 'pipe'],
58
+ env: {
59
+ ...process.env,
60
+ GIT_TERMINAL_PROMPT: '0',
61
+ GIT_ASKPASS: 'false',
62
+ },
63
+ stdio: ['ignore', 'pipe', debugEnabled ? 'inherit' : 'pipe'],
54
64
  });
55
65
  let output = '';
56
66
  let stderr = '';