@simplysm/sd-claude 13.0.69 → 13.0.71

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 (78) hide show
  1. package/README.md +12 -601
  2. package/claude/agents/sd-api-reviewer.md +0 -1
  3. package/claude/agents/sd-code-reviewer.md +0 -1
  4. package/claude/agents/sd-code-simplifier.md +1 -1
  5. package/claude/agents/sd-security-reviewer.md +0 -1
  6. package/claude/refs/sd-angular.md +26 -26
  7. package/claude/refs/sd-orm-v12.md +17 -17
  8. package/claude/rules/sd-refs-linker.md +14 -14
  9. package/claude/sd-statusline.js +21 -21
  10. package/claude/skills/sd-api-name-review/SKILL.md +1 -2
  11. package/claude/skills/sd-brainstorm/SKILL.md +3 -4
  12. package/claude/skills/sd-check/SKILL.md +1 -2
  13. package/claude/skills/sd-commit/SKILL.md +2 -3
  14. package/claude/skills/sd-debug/SKILL.md +1 -2
  15. package/claude/skills/sd-discuss/SKILL.md +1 -3
  16. package/claude/skills/sd-document/SKILL.md +99 -0
  17. package/claude/skills/sd-document/extract_docx.py +92 -0
  18. package/claude/skills/sd-document/extract_pdf.py +102 -0
  19. package/claude/skills/sd-document/extract_pptx.py +77 -0
  20. package/claude/skills/sd-document/extract_xlsx.py +83 -0
  21. package/claude/skills/sd-email-analyze/SKILL.md +6 -6
  22. package/claude/skills/sd-plan/SKILL.md +1 -3
  23. package/claude/skills/sd-plan-dev/SKILL.md +94 -111
  24. package/claude/skills/sd-plan-dev/code-quality-reviewer-prompt.md +1 -1
  25. package/claude/skills/sd-plan-dev/final-review-prompt.md +1 -1
  26. package/claude/skills/sd-plan-dev/spec-reviewer-prompt.md +1 -1
  27. package/claude/skills/sd-readme/SKILL.md +107 -88
  28. package/claude/skills/sd-review/SKILL.md +14 -16
  29. package/claude/skills/sd-skill/SKILL.md +6 -317
  30. package/claude/skills/sd-skill/cso-guide.md +161 -0
  31. package/claude/skills/sd-skill/writing-guide.md +163 -0
  32. package/claude/skills/sd-tdd/SKILL.md +1 -3
  33. package/claude/skills/sd-use/SKILL.md +1 -3
  34. package/claude/skills/sd-worktree/SKILL.md +52 -2
  35. package/dist/commands/auth-add.d.ts +2 -0
  36. package/dist/commands/auth-add.d.ts.map +1 -0
  37. package/dist/commands/auth-add.js +32 -0
  38. package/dist/commands/auth-add.js.map +6 -0
  39. package/dist/commands/auth-list.d.ts +2 -0
  40. package/dist/commands/auth-list.d.ts.map +1 -0
  41. package/dist/commands/auth-list.js +37 -0
  42. package/dist/commands/auth-list.js.map +6 -0
  43. package/dist/commands/auth-remove.d.ts +2 -0
  44. package/dist/commands/auth-remove.d.ts.map +1 -0
  45. package/dist/commands/auth-remove.js +22 -0
  46. package/dist/commands/auth-remove.js.map +6 -0
  47. package/dist/commands/auth-use.d.ts +2 -0
  48. package/dist/commands/auth-use.d.ts.map +1 -0
  49. package/dist/commands/auth-use.js +33 -0
  50. package/dist/commands/auth-use.js.map +6 -0
  51. package/dist/commands/auth-utils.d.ts +11 -0
  52. package/dist/commands/auth-utils.d.ts.map +1 -0
  53. package/dist/commands/auth-utils.js +57 -0
  54. package/dist/commands/auth-utils.js.map +6 -0
  55. package/dist/commands/install.js +3 -3
  56. package/dist/commands/install.js.map +1 -1
  57. package/dist/index.d.ts +5 -0
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +5 -0
  60. package/dist/index.js.map +1 -1
  61. package/dist/sd-claude.js +68 -3
  62. package/dist/sd-claude.js.map +1 -1
  63. package/package.json +3 -2
  64. package/scripts/sync-claude-assets.mjs +1 -1
  65. package/src/commands/auth-add.ts +36 -0
  66. package/src/commands/auth-list.ts +44 -0
  67. package/src/commands/auth-remove.ts +26 -0
  68. package/src/commands/auth-use.ts +53 -0
  69. package/src/commands/auth-utils.ts +65 -0
  70. package/src/commands/install.ts +19 -19
  71. package/src/index.ts +5 -0
  72. package/src/sd-claude.ts +81 -3
  73. package/tests/auth-add.spec.ts +74 -0
  74. package/tests/auth-list.spec.ts +175 -0
  75. package/tests/auth-remove.spec.ts +74 -0
  76. package/tests/auth-use.spec.ts +153 -0
  77. package/tests/auth-utils.spec.ts +173 -0
  78. package/claude/skills/sd-explore/SKILL.md +0 -78
@@ -0,0 +1,74 @@
1
+ import { describe, test, expect, beforeEach, afterEach, vi } from "vitest";
2
+ import path from "path";
3
+ import fs from "fs";
4
+ import os from "os";
5
+ import { runAuthRemove } from "../src/commands/auth-remove";
6
+
7
+ describe("runAuthRemove", () => {
8
+ let tmpDir: string;
9
+
10
+ beforeEach(() => {
11
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sd-claude-auth-remove-test-"));
12
+ });
13
+
14
+ afterEach(() => {
15
+ fs.rmSync(tmpDir, { recursive: true, force: true });
16
+ vi.restoreAllMocks();
17
+ });
18
+
19
+ test("removes profile directory successfully", () => {
20
+ // Set up a profile directory with auth.json
21
+ const profileDir = path.join(tmpDir, ".sd-claude", "auth", "work");
22
+ fs.mkdirSync(profileDir, { recursive: true });
23
+ fs.writeFileSync(
24
+ path.join(profileDir, "auth.json"),
25
+ JSON.stringify({ userID: "user-123", oauthAccount: {} }),
26
+ );
27
+ fs.writeFileSync(
28
+ path.join(profileDir, "credentials.json"),
29
+ JSON.stringify({ accessToken: "abc" }),
30
+ );
31
+
32
+ // Set up .claude.json with a DIFFERENT userID (not active)
33
+ fs.writeFileSync(path.join(tmpDir, ".claude.json"), JSON.stringify({ userID: "user-999" }));
34
+
35
+ const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
36
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
37
+
38
+ runAuthRemove("work", tmpDir);
39
+
40
+ expect(fs.existsSync(profileDir)).toBe(false);
41
+ expect(logSpy).toHaveBeenCalledWith("Removed profile 'work'");
42
+ expect(warnSpy).not.toHaveBeenCalled();
43
+ });
44
+
45
+ test("warns when removing active profile (still removes it)", () => {
46
+ // Set up a profile directory with auth.json
47
+ const profileDir = path.join(tmpDir, ".sd-claude", "auth", "work");
48
+ fs.mkdirSync(profileDir, { recursive: true });
49
+ fs.writeFileSync(
50
+ path.join(profileDir, "auth.json"),
51
+ JSON.stringify({ userID: "user-123", oauthAccount: {} }),
52
+ );
53
+
54
+ // Set up .claude.json with the SAME userID (active)
55
+ fs.writeFileSync(path.join(tmpDir, ".claude.json"), JSON.stringify({ userID: "user-123" }));
56
+
57
+ const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
58
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
59
+
60
+ runAuthRemove("work", tmpDir);
61
+
62
+ expect(fs.existsSync(profileDir)).toBe(false);
63
+ expect(warnSpy).toHaveBeenCalledWith("Warning: 'work' is currently active.");
64
+ expect(logSpy).toHaveBeenCalledWith("Removed profile 'work'");
65
+ });
66
+
67
+ test("throws when profile not found", () => {
68
+ expect(() => runAuthRemove("nonexistent", tmpDir)).toThrow("Profile 'nonexistent' not found.");
69
+ });
70
+
71
+ test("throws with invalid name", () => {
72
+ expect(() => runAuthRemove("BAD NAME!", tmpDir)).toThrow("Invalid name");
73
+ });
74
+ });
@@ -0,0 +1,153 @@
1
+ import { describe, test, expect, beforeEach, afterEach, vi } from "vitest";
2
+ import path from "path";
3
+ import fs from "fs";
4
+ import os from "os";
5
+ import { runAuthUse } from "../src/commands/auth-use";
6
+
7
+ describe("runAuthUse", () => {
8
+ let tmpDir: string;
9
+
10
+ beforeEach(() => {
11
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sd-claude-auth-use-test-"));
12
+ });
13
+
14
+ afterEach(() => {
15
+ fs.rmSync(tmpDir, { recursive: true });
16
+ vi.restoreAllMocks();
17
+ });
18
+
19
+ function setupProfile(name: string, opts?: { expiresAt?: number }): void {
20
+ const profileDir = path.join(tmpDir, ".sd-claude", "auth", name);
21
+ fs.mkdirSync(profileDir, { recursive: true });
22
+
23
+ const authJson = {
24
+ oauthAccount: { emailAddress: "work@example.com", token: "oauth-work" },
25
+ userID: "user-work-456",
26
+ };
27
+ fs.writeFileSync(path.join(profileDir, "auth.json"), JSON.stringify(authJson));
28
+
29
+ const credJson = {
30
+ claudeAiOauth: {
31
+ accessToken: "saved-access-token",
32
+ refreshToken: "saved-refresh-token",
33
+ expiresAt: opts?.expiresAt ?? Date.now() + 3_600_000,
34
+ },
35
+ };
36
+ fs.writeFileSync(path.join(profileDir, "credentials.json"), JSON.stringify(credJson));
37
+ }
38
+
39
+ function setupClaudeJson(extra?: Record<string, unknown>): void {
40
+ const claudeJson = {
41
+ oauthAccount: { emailAddress: "old@example.com", token: "old-token" },
42
+ userID: "user-old-111",
43
+ someCustomSetting: "preserve-me",
44
+ anotherField: 42,
45
+ ...extra,
46
+ };
47
+ fs.writeFileSync(path.join(tmpDir, ".claude.json"), JSON.stringify(claudeJson));
48
+ }
49
+
50
+ function setupCredentialsJson(): void {
51
+ const claudeDir = path.join(tmpDir, ".claude");
52
+ fs.mkdirSync(claudeDir, { recursive: true });
53
+ const credentials = { oldKey: "old-value", claudeAiOauth: { accessToken: "old-access" } };
54
+ fs.writeFileSync(path.join(claudeDir, ".credentials.json"), JSON.stringify(credentials));
55
+ }
56
+
57
+ test("replaces oauthAccount and userID while preserving other fields in ~/.claude.json", () => {
58
+ setupProfile("work");
59
+ setupClaudeJson();
60
+ setupCredentialsJson();
61
+
62
+ const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
63
+
64
+ runAuthUse("work", tmpDir);
65
+
66
+ const result = JSON.parse(
67
+ fs.readFileSync(path.join(tmpDir, ".claude.json"), "utf-8"),
68
+ ) as Record<string, unknown>;
69
+
70
+ // oauthAccount and userID should be replaced
71
+ expect(result["oauthAccount"]).toEqual({
72
+ emailAddress: "work@example.com",
73
+ token: "oauth-work",
74
+ });
75
+ expect(result["userID"]).toBe("user-work-456");
76
+
77
+ // Other fields must be preserved
78
+ expect(result["someCustomSetting"]).toBe("preserve-me");
79
+ expect(result["anotherField"]).toBe(42);
80
+
81
+ logSpy.mockRestore();
82
+ });
83
+
84
+ test("replaces credentials.json entirely", () => {
85
+ setupProfile("work");
86
+ setupClaudeJson();
87
+ setupCredentialsJson();
88
+
89
+ const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
90
+
91
+ runAuthUse("work", tmpDir);
92
+
93
+ const result = JSON.parse(
94
+ fs.readFileSync(path.join(tmpDir, ".claude", ".credentials.json"), "utf-8"),
95
+ ) as Record<string, unknown>;
96
+
97
+ // Should be entirely replaced with saved credentials (no oldKey)
98
+ expect(result).toEqual({
99
+ claudeAiOauth: {
100
+ accessToken: "saved-access-token",
101
+ refreshToken: "saved-refresh-token",
102
+ expiresAt: expect.any(Number) as number,
103
+ },
104
+ });
105
+ expect(result["oldKey"]).toBeUndefined();
106
+
107
+ logSpy.mockRestore();
108
+ });
109
+
110
+ test("warns when token is expired (should not throw)", () => {
111
+ const expiredTime = Date.now() - 1_000;
112
+ setupProfile("work", { expiresAt: expiredTime });
113
+ setupClaudeJson();
114
+ setupCredentialsJson();
115
+
116
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
117
+ const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
118
+
119
+ // Should NOT throw
120
+ expect(() => runAuthUse("work", tmpDir)).not.toThrow();
121
+
122
+ // Should warn about expired token
123
+ expect(warnSpy).toHaveBeenCalledWith("Warning: Token expired. Run /login after switching.");
124
+
125
+ warnSpy.mockRestore();
126
+ logSpy.mockRestore();
127
+ });
128
+
129
+ test("throws when profile not found", () => {
130
+ setupClaudeJson();
131
+ setupCredentialsJson();
132
+
133
+ expect(() => runAuthUse("nonexistent", tmpDir)).toThrow("Profile 'nonexistent' not found.");
134
+ });
135
+
136
+ test("throws with invalid name", () => {
137
+ expect(() => runAuthUse("BAD NAME!", tmpDir)).toThrow("Invalid name");
138
+ });
139
+
140
+ test("logs switched message with name and email", () => {
141
+ setupProfile("work");
142
+ setupClaudeJson();
143
+ setupCredentialsJson();
144
+
145
+ const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
146
+
147
+ runAuthUse("work", tmpDir);
148
+
149
+ expect(logSpy).toHaveBeenCalledWith("Switched to work (work@example.com)");
150
+
151
+ logSpy.mockRestore();
152
+ });
153
+ });
@@ -0,0 +1,173 @@
1
+ import { describe, test, expect, beforeEach, afterEach } from "vitest";
2
+ import path from "path";
3
+ import fs from "fs";
4
+ import os from "os";
5
+ import {
6
+ validateName,
7
+ getProfileDir,
8
+ profileExists,
9
+ listProfiles,
10
+ readCurrentAuth,
11
+ readCurrentCredentials,
12
+ getCurrentUserID,
13
+ } from "../src/commands/auth-utils";
14
+
15
+ describe("auth-utils", () => {
16
+ let tmpDir: string;
17
+
18
+ beforeEach(() => {
19
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sd-claude-auth-test-"));
20
+ });
21
+
22
+ afterEach(() => {
23
+ fs.rmSync(tmpDir, { recursive: true });
24
+ });
25
+
26
+ describe("validateName", () => {
27
+ test("accepts lowercase letters", () => {
28
+ expect(() => validateName("abc")).not.toThrow();
29
+ });
30
+
31
+ test("accepts digits", () => {
32
+ expect(() => validateName("123")).not.toThrow();
33
+ });
34
+
35
+ test("accepts hyphens and underscores", () => {
36
+ expect(() => validateName("my-profile_1")).not.toThrow();
37
+ });
38
+
39
+ test("rejects uppercase letters", () => {
40
+ expect(() => validateName("ABC")).toThrow();
41
+ });
42
+
43
+ test("rejects spaces", () => {
44
+ expect(() => validateName("my profile")).toThrow();
45
+ });
46
+
47
+ test("rejects special characters", () => {
48
+ expect(() => validateName("my@profile")).toThrow();
49
+ });
50
+
51
+ test("rejects empty string", () => {
52
+ expect(() => validateName("")).toThrow();
53
+ });
54
+
55
+ test("error message includes the invalid name", () => {
56
+ expect(() => validateName("BAD!")).toThrow(/BAD!/);
57
+ });
58
+ });
59
+
60
+ describe("getProfileDir", () => {
61
+ test("returns correct path with homeDir", () => {
62
+ const result = getProfileDir("work", tmpDir);
63
+ expect(result).toBe(path.join(tmpDir, ".sd-claude", "auth", "work"));
64
+ });
65
+
66
+ test("uses os.homedir when homeDir is not provided", () => {
67
+ const result = getProfileDir("test");
68
+ expect(result).toBe(path.join(os.homedir(), ".sd-claude", "auth", "test"));
69
+ });
70
+ });
71
+
72
+ describe("profileExists", () => {
73
+ test("returns false when profile directory does not exist", () => {
74
+ expect(profileExists("nonexistent", tmpDir)).toBe(false);
75
+ });
76
+
77
+ test("returns true when profile directory exists", () => {
78
+ const profileDir = path.join(tmpDir, ".sd-claude", "auth", "work");
79
+ fs.mkdirSync(profileDir, { recursive: true });
80
+ expect(profileExists("work", tmpDir)).toBe(true);
81
+ });
82
+ });
83
+
84
+ describe("listProfiles", () => {
85
+ test("returns empty array when auth directory does not exist", () => {
86
+ expect(listProfiles(tmpDir)).toEqual([]);
87
+ });
88
+
89
+ test("returns subdirectory names", () => {
90
+ const authDir = path.join(tmpDir, ".sd-claude", "auth");
91
+ fs.mkdirSync(path.join(authDir, "work"), { recursive: true });
92
+ fs.mkdirSync(path.join(authDir, "personal"), { recursive: true });
93
+
94
+ const result = listProfiles(tmpDir);
95
+ expect(result.sort()).toEqual(["personal", "work"]);
96
+ });
97
+
98
+ test("ignores files in auth directory", () => {
99
+ const authDir = path.join(tmpDir, ".sd-claude", "auth");
100
+ fs.mkdirSync(authDir, { recursive: true });
101
+ fs.writeFileSync(path.join(authDir, "some-file.txt"), "data");
102
+ fs.mkdirSync(path.join(authDir, "profile1"), { recursive: true });
103
+
104
+ expect(listProfiles(tmpDir)).toEqual(["profile1"]);
105
+ });
106
+ });
107
+
108
+ describe("readCurrentAuth", () => {
109
+ test("reads oauthAccount and userID from .claude.json", () => {
110
+ const claudeJson = {
111
+ oauthAccount: { email: "test@example.com", token: "abc" },
112
+ userID: "user-123",
113
+ };
114
+ fs.writeFileSync(path.join(tmpDir, ".claude.json"), JSON.stringify(claudeJson));
115
+
116
+ const result = readCurrentAuth(tmpDir);
117
+ expect(result.oauthAccount).toEqual({ email: "test@example.com", token: "abc" });
118
+ expect(result.userID).toBe("user-123");
119
+ });
120
+
121
+ test("throws when .claude.json does not exist", () => {
122
+ expect(() => readCurrentAuth(tmpDir)).toThrow();
123
+ });
124
+
125
+ test("throws when oauthAccount is missing", () => {
126
+ fs.writeFileSync(path.join(tmpDir, ".claude.json"), JSON.stringify({ userID: "user-123" }));
127
+ expect(() => readCurrentAuth(tmpDir)).toThrow("Not logged in");
128
+ });
129
+
130
+ test("throws when userID is missing", () => {
131
+ fs.writeFileSync(
132
+ path.join(tmpDir, ".claude.json"),
133
+ JSON.stringify({ oauthAccount: { email: "test@example.com" } }),
134
+ );
135
+ expect(() => readCurrentAuth(tmpDir)).toThrow("Not logged in");
136
+ });
137
+ });
138
+
139
+ describe("readCurrentCredentials", () => {
140
+ test("reads credentials from .claude/.credentials.json", () => {
141
+ const credentials = { key: "value", secret: "s3cret" };
142
+ const claudeDir = path.join(tmpDir, ".claude");
143
+ fs.mkdirSync(claudeDir, { recursive: true });
144
+ fs.writeFileSync(path.join(claudeDir, ".credentials.json"), JSON.stringify(credentials));
145
+
146
+ const result = readCurrentCredentials(tmpDir);
147
+ expect(result).toEqual({ key: "value", secret: "s3cret" });
148
+ });
149
+
150
+ test("throws when .credentials.json does not exist", () => {
151
+ expect(() => readCurrentCredentials(tmpDir)).toThrow();
152
+ });
153
+ });
154
+
155
+ describe("getCurrentUserID", () => {
156
+ test("returns userID from .claude.json", () => {
157
+ fs.writeFileSync(path.join(tmpDir, ".claude.json"), JSON.stringify({ userID: "user-456" }));
158
+ expect(getCurrentUserID(tmpDir)).toBe("user-456");
159
+ });
160
+
161
+ test("returns undefined when .claude.json does not exist", () => {
162
+ expect(getCurrentUserID(tmpDir)).toBeUndefined();
163
+ });
164
+
165
+ test("returns undefined when userID is missing from .claude.json", () => {
166
+ fs.writeFileSync(
167
+ path.join(tmpDir, ".claude.json"),
168
+ JSON.stringify({ someOtherField: "value" }),
169
+ );
170
+ expect(getCurrentUserID(tmpDir)).toBeUndefined();
171
+ });
172
+ });
173
+ });
@@ -1,78 +0,0 @@
1
- ---
2
- name: sd-explore
3
- description: Deep codebase analysis - execution paths, architecture, dependencies
4
- disable-model-invocation: true
5
- model: sonnet
6
- context: fork
7
- allowed-tools: Read, Glob, Grep
8
- user-invocable: false
9
- ---
10
-
11
- # sd-explore
12
-
13
- You are an expert code analyst specializing in tracing and understanding feature implementations across codebases.
14
-
15
- ## Target Selection
16
-
17
- **When invoked with `$ARGUMENTS`:**
18
-
19
- - If path is provided → **Immediately start analysis** (don't ask clarifying questions)
20
- - If path is a package directory → Trace all major features, architecture, and patterns
21
- - If path is a single file → Trace its role, dependencies, and usage
22
-
23
- **Critical**: This skill is `user-invocable: false` — you are called programmatically by other agents. Start analysis immediately without user interaction.
24
-
25
- ## Core Mission
26
-
27
- Provide a complete understanding of how the target code works by tracing its implementation from entry points to data storage, through all abstraction layers. **Analysis only — no code modifications.**
28
-
29
- When analyzing a package/directory, cover:
30
-
31
- - Overall architecture and design patterns
32
- - Major features and entry points
33
- - Key abstractions and interfaces
34
- - Cross-cutting concerns
35
- - Critical files with file:line references
36
-
37
- ## Analysis Approach
38
-
39
- ### 1. Feature Discovery
40
-
41
- - Find entry points (APIs, UI components, CLI commands)
42
- - Locate core implementation files
43
- - Map feature boundaries and configuration
44
-
45
- ### 2. Code Flow Tracing
46
-
47
- - Follow call chains from entry to output
48
- - Trace data transformations at each step
49
- - Identify all dependencies and integrations
50
- - Document state changes and side effects
51
-
52
- ### 3. Architecture Analysis
53
-
54
- - Map abstraction layers (presentation → business logic → data)
55
- - Identify design patterns and architectural decisions
56
- - Document interfaces between components
57
- - Note cross-cutting concerns (auth, logging, caching)
58
-
59
- ### 4. Implementation Details
60
-
61
- - Key algorithms and data structures
62
- - Error handling and edge cases
63
- - Performance considerations
64
- - Technical debt or improvement areas
65
-
66
- ## Output Guidance
67
-
68
- Provide a comprehensive analysis that helps developers understand the code deeply enough to modify or extend it. Include:
69
-
70
- - Entry points with file:line references
71
- - Step-by-step execution flow with data transformations
72
- - Key components and their responsibilities
73
- - Architecture insights: patterns, layers, design decisions
74
- - Dependencies (external and internal)
75
- - Observations about strengths, issues, or opportunities
76
- - List of files absolutely essential to understanding the target
77
-
78
- Structure your response for maximum clarity and usefulness. Always include specific file paths and line numbers.