codewalk 0.1.0 → 0.1.2
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/dist/index.js +342 -121
- package/package.json +1 -1
- package/dist/commands/init.d.ts +0 -5
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js +0 -163
- package/dist/commands/visualize.d.ts +0 -5
- package/dist/commands/visualize.d.ts.map +0 -1
- package/dist/commands/visualize.js +0 -79
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/tui/app.d.ts +0 -13
- package/dist/tui/app.d.ts.map +0 -1
- package/dist/tui/app.js +0 -11
- package/dist/tui/tree-view.d.ts +0 -24
- package/dist/tui/tree-view.d.ts.map +0 -1
- package/dist/tui/tree-view.js +0 -274
- package/dist/types/codewalker.d.ts +0 -15
- package/dist/types/codewalker.d.ts.map +0 -1
- package/dist/types/codewalker.js +0 -1
- package/dist/utils/git.d.ts +0 -24
- package/dist/utils/git.d.ts.map +0 -1
- package/dist/utils/git.js +0 -132
- package/dist/utils/tracking.d.ts +0 -23
- package/dist/utils/tracking.d.ts.map +0 -1
- package/dist/utils/tracking.js +0 -85
package/dist/index.js
CHANGED
|
@@ -1948,9 +1948,9 @@ var {
|
|
|
1948
1948
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
1949
1949
|
import * as fs from "fs/promises";
|
|
1950
1950
|
import * as path from "path";
|
|
1951
|
-
var SKILL_TEMPLATE = `#
|
|
1951
|
+
var SKILL_TEMPLATE = `# codewalk
|
|
1952
1952
|
|
|
1953
|
-
You are
|
|
1953
|
+
You are codewalk, an AI programming assistant built on top of Claude Code.
|
|
1954
1954
|
|
|
1955
1955
|
Your purpose is to give the user more visibility into the changes you are making.
|
|
1956
1956
|
|
|
@@ -2021,18 +2021,18 @@ If it's a distinct new task, create a new commit and new tracking file.
|
|
|
2021
2021
|
## Instructions
|
|
2022
2022
|
|
|
2023
2023
|
1. Before committing, check if a git repo exists with \`git status\`. Only run \`git init\` if there isn't one.
|
|
2024
|
-
2. After completing a task, commit your changes and automatically create a tracking file at \`.
|
|
2024
|
+
2. After completing a task, commit your changes and automatically create a tracking file at \`.codewalk/<commit-hash>.json\`
|
|
2025
2025
|
3. Group hunks by their logical purpose\u2014one reasoning per logical change, even if it spans multiple hunks or multiple files. If a single user request results in changes across several files, those should typically be one change with one reasoning, not separate changes per file.
|
|
2026
2026
|
4. Write reasoning that explains *why*, not just *what* (the diff already shows what)
|
|
2027
2027
|
5. If a follow-up request refines previous work, amend the commit and update the tracking file
|
|
2028
2028
|
6. If a follow-up request is a new task, create a new commit and new tracking file
|
|
2029
|
-
7. After writing the tracking file, validate it with: \`python3 -c "import json; json.load(open('.
|
|
2029
|
+
7. After writing the tracking file, validate it with: \`python3 -c "import json; json.load(open('.codewalk/<commit-hash>.json'))"\`
|
|
2030
2030
|
|
|
2031
2031
|
Do not wait for the user to ask for the tracking file\u2014create it automatically as part of finishing each task.
|
|
2032
2032
|
|
|
2033
2033
|
**Important:** Always complete the tracking step after every task, even in long conversations with multiple tasks. Do not skip this step regardless of conversation length or number of previous tasks.
|
|
2034
2034
|
`;
|
|
2035
|
-
var CLAUDE_MD_CONTENT = `#
|
|
2035
|
+
var CLAUDE_MD_CONTENT = `# codewalk
|
|
2036
2036
|
|
|
2037
2037
|
**CRITICAL REQUIREMENT**: You MUST create git commits for your changes AND create tracking files after EVERY task. No exceptions.
|
|
2038
2038
|
|
|
@@ -2040,13 +2040,13 @@ var CLAUDE_MD_CONTENT = `# Code Walker
|
|
|
2040
2040
|
1. Make your code changes using Write/Edit tools
|
|
2041
2041
|
2. **COMMIT the changes**: \`git add -A && git commit -m "descriptive message"\`
|
|
2042
2042
|
3. Get the commit hash: \`git rev-parse --short HEAD\`
|
|
2043
|
-
4. **IMMEDIATELY** create \`.
|
|
2044
|
-
5. Commit the tracking file: \`git add .
|
|
2043
|
+
4. **IMMEDIATELY** create \`.codewalk/<commit-hash>.json\` with the tracking data
|
|
2044
|
+
5. Commit the tracking file: \`git add .codewalk/<hash>.json && git commit -m "Add tracking file for <hash>"\`
|
|
2045
2045
|
6. Only THEN respond to the user
|
|
2046
2046
|
|
|
2047
2047
|
**DO NOT** skip commits. **DO NOT** respond to the user until both the code commit AND tracking file commit are done.
|
|
2048
2048
|
|
|
2049
|
-
See \`.claude/skills/
|
|
2049
|
+
See \`.claude/skills/codewalk.md\` for the complete schema and examples.
|
|
2050
2050
|
`;
|
|
2051
2051
|
var SETTINGS_CONTENT = {
|
|
2052
2052
|
hooks: {
|
|
@@ -2055,7 +2055,7 @@ var SETTINGS_CONTENT = {
|
|
|
2055
2055
|
hooks: [
|
|
2056
2056
|
{
|
|
2057
2057
|
type: "prompt",
|
|
2058
|
-
prompt: "Check if the assistant made code changes in this session. If code changes were made, verify: 1) Changes were committed with git, 2) A tracking file was created at .
|
|
2058
|
+
prompt: "Check if the assistant made code changes in this session. If code changes were made, verify: 1) Changes were committed with git, 2) A tracking file was created at .codewalk/<commit-hash>.json, 3) The tracking file was also committed. If any of these are missing, block stopping and instruct to complete the codewalk workflow. If no code changes were made, or all steps are complete, approve stopping.",
|
|
2059
2059
|
timeout: 30
|
|
2060
2060
|
}
|
|
2061
2061
|
]
|
|
@@ -2073,39 +2073,39 @@ async function fileExists(filePath) {
|
|
|
2073
2073
|
}
|
|
2074
2074
|
async function initCommand(options) {
|
|
2075
2075
|
const { cwd } = options;
|
|
2076
|
-
console.log(import_picocolors.default.bold(`Initializing
|
|
2076
|
+
console.log(import_picocolors.default.bold(`Initializing codewalk...
|
|
2077
2077
|
`));
|
|
2078
2078
|
const skillsDir = path.join(cwd, ".claude", "skills");
|
|
2079
2079
|
await fs.mkdir(skillsDir, { recursive: true });
|
|
2080
|
-
const skillPath = path.join(skillsDir, "
|
|
2080
|
+
const skillPath = path.join(skillsDir, "codewalk.md");
|
|
2081
2081
|
const skillExists = await fileExists(skillPath);
|
|
2082
2082
|
if (!skillExists) {
|
|
2083
2083
|
await fs.writeFile(skillPath, SKILL_TEMPLATE);
|
|
2084
|
-
console.log(import_picocolors.default.green("\u2713") + " Created .claude/skills/
|
|
2084
|
+
console.log(import_picocolors.default.green("\u2713") + " Created .claude/skills/codewalk.md");
|
|
2085
2085
|
} else {
|
|
2086
|
-
console.log(import_picocolors.default.yellow("\u25CB") + " .claude/skills/
|
|
2086
|
+
console.log(import_picocolors.default.yellow("\u25CB") + " .claude/skills/codewalk.md already exists, skipping");
|
|
2087
2087
|
}
|
|
2088
2088
|
const claudePath = path.join(cwd, "CLAUDE.md");
|
|
2089
2089
|
let claudeContent = "";
|
|
2090
2090
|
try {
|
|
2091
2091
|
claudeContent = await fs.readFile(claudePath, "utf-8");
|
|
2092
2092
|
} catch {}
|
|
2093
|
-
if (!claudeContent.includes(".claude/skills/
|
|
2093
|
+
if (!claudeContent.includes(".claude/skills/codewalk.md")) {
|
|
2094
2094
|
const newContent = claudeContent ? claudeContent + `
|
|
2095
2095
|
|
|
2096
2096
|
` + CLAUDE_MD_CONTENT : CLAUDE_MD_CONTENT;
|
|
2097
2097
|
await fs.writeFile(claudePath, newContent);
|
|
2098
|
-
console.log(import_picocolors.default.green("\u2713") + " Updated CLAUDE.md with
|
|
2098
|
+
console.log(import_picocolors.default.green("\u2713") + " Updated CLAUDE.md with codewalk instructions");
|
|
2099
2099
|
} else {
|
|
2100
|
-
console.log(import_picocolors.default.yellow("\u25CB") + " CLAUDE.md already references
|
|
2100
|
+
console.log(import_picocolors.default.yellow("\u25CB") + " CLAUDE.md already references codewalk, skipping");
|
|
2101
2101
|
}
|
|
2102
|
-
const
|
|
2103
|
-
const
|
|
2104
|
-
await fs.mkdir(
|
|
2105
|
-
if (!
|
|
2106
|
-
console.log(import_picocolors.default.green("\u2713") + " Created .
|
|
2102
|
+
const codewalkDir = path.join(cwd, ".codewalk");
|
|
2103
|
+
const codewalkExists = await fileExists(codewalkDir);
|
|
2104
|
+
await fs.mkdir(codewalkDir, { recursive: true });
|
|
2105
|
+
if (!codewalkExists) {
|
|
2106
|
+
console.log(import_picocolors.default.green("\u2713") + " Created .codewalk/ directory");
|
|
2107
2107
|
} else {
|
|
2108
|
-
console.log(import_picocolors.default.yellow("\u25CB") + " .
|
|
2108
|
+
console.log(import_picocolors.default.yellow("\u25CB") + " .codewalk/ directory already exists");
|
|
2109
2109
|
}
|
|
2110
2110
|
const settingsPath = path.join(cwd, ".claude", "settings.local.json");
|
|
2111
2111
|
let existingSettings = {};
|
|
@@ -2129,20 +2129,20 @@ async function initCommand(options) {
|
|
|
2129
2129
|
console.log(import_picocolors.default.yellow("\u25CB") + " Stop hook already configured, skipping");
|
|
2130
2130
|
}
|
|
2131
2131
|
console.log(import_picocolors.default.bold(`
|
|
2132
|
-
|
|
2132
|
+
codewalk initialized successfully!`));
|
|
2133
2133
|
console.log(`
|
|
2134
2134
|
Next steps:`);
|
|
2135
2135
|
console.log(" 1. Start Claude Code in this directory");
|
|
2136
2136
|
console.log(" 2. Make changes - Claude will automatically track them");
|
|
2137
|
-
console.log(" 3. Run " + import_picocolors.default.cyan("
|
|
2137
|
+
console.log(" 3. Run " + import_picocolors.default.cyan("codewalk visualize") + " to browse changes");
|
|
2138
2138
|
}
|
|
2139
2139
|
|
|
2140
2140
|
// src/commands/visualize.ts
|
|
2141
2141
|
var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
2142
|
-
import * as
|
|
2143
|
-
import * as
|
|
2142
|
+
import * as fs5 from "fs";
|
|
2143
|
+
import * as path7 from "path";
|
|
2144
2144
|
|
|
2145
|
-
// ../../node_modules/@opentui/core/index-
|
|
2145
|
+
// ../../node_modules/@opentui/core/index-cr95zpf8.js
|
|
2146
2146
|
import { Buffer as Buffer2 } from "buffer";
|
|
2147
2147
|
import { EventEmitter } from "events";
|
|
2148
2148
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
@@ -2183,7 +2183,7 @@ var highlights_default5 = "./highlights-hk7bwhj4.scm";
|
|
|
2183
2183
|
// ../../node_modules/@opentui/core/assets/zig/tree-sitter-zig.wasm
|
|
2184
2184
|
var tree_sitter_zig_default = "./tree-sitter-zig-e78zbjpm.wasm";
|
|
2185
2185
|
|
|
2186
|
-
// ../../node_modules/@opentui/core/index-
|
|
2186
|
+
// ../../node_modules/@opentui/core/index-cr95zpf8.js
|
|
2187
2187
|
import { resolve as resolve2, isAbsolute, parse } from "path";
|
|
2188
2188
|
import { existsSync } from "fs";
|
|
2189
2189
|
import { basename, join as join2 } from "path";
|
|
@@ -4525,6 +4525,7 @@ class KeyEvent {
|
|
|
4525
4525
|
baseCode;
|
|
4526
4526
|
repeated;
|
|
4527
4527
|
_defaultPrevented = false;
|
|
4528
|
+
_propagationStopped = false;
|
|
4528
4529
|
constructor(key) {
|
|
4529
4530
|
this.name = key.name;
|
|
4530
4531
|
this.ctrl = key.ctrl;
|
|
@@ -4547,23 +4548,36 @@ class KeyEvent {
|
|
|
4547
4548
|
get defaultPrevented() {
|
|
4548
4549
|
return this._defaultPrevented;
|
|
4549
4550
|
}
|
|
4551
|
+
get propagationStopped() {
|
|
4552
|
+
return this._propagationStopped;
|
|
4553
|
+
}
|
|
4550
4554
|
preventDefault() {
|
|
4551
4555
|
this._defaultPrevented = true;
|
|
4552
4556
|
}
|
|
4557
|
+
stopPropagation() {
|
|
4558
|
+
this._propagationStopped = true;
|
|
4559
|
+
}
|
|
4553
4560
|
}
|
|
4554
4561
|
|
|
4555
4562
|
class PasteEvent {
|
|
4556
4563
|
text;
|
|
4557
4564
|
_defaultPrevented = false;
|
|
4565
|
+
_propagationStopped = false;
|
|
4558
4566
|
constructor(text) {
|
|
4559
4567
|
this.text = text;
|
|
4560
4568
|
}
|
|
4561
4569
|
get defaultPrevented() {
|
|
4562
4570
|
return this._defaultPrevented;
|
|
4563
4571
|
}
|
|
4572
|
+
get propagationStopped() {
|
|
4573
|
+
return this._propagationStopped;
|
|
4574
|
+
}
|
|
4564
4575
|
preventDefault() {
|
|
4565
4576
|
this._defaultPrevented = true;
|
|
4566
4577
|
}
|
|
4578
|
+
stopPropagation() {
|
|
4579
|
+
this._propagationStopped = true;
|
|
4580
|
+
}
|
|
4567
4581
|
}
|
|
4568
4582
|
|
|
4569
4583
|
class KeyHandler extends EventEmitter {
|
|
@@ -4615,10 +4629,22 @@ class InternalKeyHandler extends KeyHandler {
|
|
|
4615
4629
|
}
|
|
4616
4630
|
emitWithPriority(event, ...args) {
|
|
4617
4631
|
let hasGlobalListeners = false;
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4632
|
+
const globalListeners = this.listeners(event);
|
|
4633
|
+
if (globalListeners.length > 0) {
|
|
4634
|
+
hasGlobalListeners = true;
|
|
4635
|
+
for (const listener of globalListeners) {
|
|
4636
|
+
try {
|
|
4637
|
+
listener(...args);
|
|
4638
|
+
} catch (error) {
|
|
4639
|
+
console.error(`[KeyHandler] Error in global ${event} handler:`, error);
|
|
4640
|
+
}
|
|
4641
|
+
if (event === "keypress" || event === "keyrelease" || event === "paste") {
|
|
4642
|
+
const keyEvent = args[0];
|
|
4643
|
+
if (keyEvent.propagationStopped) {
|
|
4644
|
+
return hasGlobalListeners;
|
|
4645
|
+
}
|
|
4646
|
+
}
|
|
4647
|
+
}
|
|
4622
4648
|
}
|
|
4623
4649
|
const renderableSet = this.renderableHandlers.get(event);
|
|
4624
4650
|
const renderableHandlers = renderableSet && renderableSet.size > 0 ? [...renderableSet] : [];
|
|
@@ -4629,6 +4655,8 @@ class InternalKeyHandler extends KeyHandler {
|
|
|
4629
4655
|
const keyEvent = args[0];
|
|
4630
4656
|
if (keyEvent.defaultPrevented)
|
|
4631
4657
|
return hasGlobalListeners || hasRenderableListeners;
|
|
4658
|
+
if (keyEvent.propagationStopped)
|
|
4659
|
+
return hasGlobalListeners || hasRenderableListeners;
|
|
4632
4660
|
}
|
|
4633
4661
|
for (const handler of renderableHandlers) {
|
|
4634
4662
|
try {
|
|
@@ -4636,6 +4664,12 @@ class InternalKeyHandler extends KeyHandler {
|
|
|
4636
4664
|
} catch (error) {
|
|
4637
4665
|
console.error(`[KeyHandler] Error in renderable ${event} handler:`, error);
|
|
4638
4666
|
}
|
|
4667
|
+
if (event === "keypress" || event === "keyrelease" || event === "paste") {
|
|
4668
|
+
const keyEvent = args[0];
|
|
4669
|
+
if (keyEvent.propagationStopped) {
|
|
4670
|
+
return hasGlobalListeners || hasRenderableListeners;
|
|
4671
|
+
}
|
|
4672
|
+
}
|
|
4639
4673
|
}
|
|
4640
4674
|
}
|
|
4641
4675
|
return hasGlobalListeners || hasRenderableListeners;
|
|
@@ -8658,6 +8692,26 @@ function getOpenTUILib(libPath) {
|
|
|
8658
8692
|
args: ["ptr", "i32", "i32", "u32", "u32", "u32"],
|
|
8659
8693
|
returns: "void"
|
|
8660
8694
|
},
|
|
8695
|
+
clearCurrentHitGrid: {
|
|
8696
|
+
args: ["ptr"],
|
|
8697
|
+
returns: "void"
|
|
8698
|
+
},
|
|
8699
|
+
hitGridPushScissorRect: {
|
|
8700
|
+
args: ["ptr", "i32", "i32", "u32", "u32"],
|
|
8701
|
+
returns: "void"
|
|
8702
|
+
},
|
|
8703
|
+
hitGridPopScissorRect: {
|
|
8704
|
+
args: ["ptr"],
|
|
8705
|
+
returns: "void"
|
|
8706
|
+
},
|
|
8707
|
+
hitGridClearScissorRects: {
|
|
8708
|
+
args: ["ptr"],
|
|
8709
|
+
returns: "void"
|
|
8710
|
+
},
|
|
8711
|
+
addToCurrentHitGridClipped: {
|
|
8712
|
+
args: ["ptr", "i32", "i32", "u32", "u32", "u32"],
|
|
8713
|
+
returns: "void"
|
|
8714
|
+
},
|
|
8661
8715
|
checkHit: {
|
|
8662
8716
|
args: ["ptr", "u32", "u32"],
|
|
8663
8717
|
returns: "u32"
|
|
@@ -9754,6 +9808,21 @@ class FFIRenderLib {
|
|
|
9754
9808
|
addToHitGrid(renderer, x, y, width, height, id) {
|
|
9755
9809
|
this.opentui.symbols.addToHitGrid(renderer, x, y, width, height, id);
|
|
9756
9810
|
}
|
|
9811
|
+
clearCurrentHitGrid(renderer) {
|
|
9812
|
+
this.opentui.symbols.clearCurrentHitGrid(renderer);
|
|
9813
|
+
}
|
|
9814
|
+
hitGridPushScissorRect(renderer, x, y, width, height) {
|
|
9815
|
+
this.opentui.symbols.hitGridPushScissorRect(renderer, x, y, width, height);
|
|
9816
|
+
}
|
|
9817
|
+
hitGridPopScissorRect(renderer) {
|
|
9818
|
+
this.opentui.symbols.hitGridPopScissorRect(renderer);
|
|
9819
|
+
}
|
|
9820
|
+
hitGridClearScissorRects(renderer) {
|
|
9821
|
+
this.opentui.symbols.hitGridClearScissorRects(renderer);
|
|
9822
|
+
}
|
|
9823
|
+
addToCurrentHitGridClipped(renderer, x, y, width, height, id) {
|
|
9824
|
+
this.opentui.symbols.addToCurrentHitGridClipped(renderer, x, y, width, height, id);
|
|
9825
|
+
}
|
|
9757
9826
|
checkHit(renderer, x, y) {
|
|
9758
9827
|
return this.opentui.symbols.checkHit(renderer, x, y);
|
|
9759
9828
|
}
|
|
@@ -11134,9 +11203,9 @@ class Renderable extends BaseRenderable {
|
|
|
11134
11203
|
if (this._translateX === value)
|
|
11135
11204
|
return;
|
|
11136
11205
|
this._translateX = value;
|
|
11137
|
-
this.requestRender();
|
|
11138
11206
|
if (this.parent)
|
|
11139
11207
|
this.parent.childrenPrimarySortDirty = true;
|
|
11208
|
+
this.requestRender();
|
|
11140
11209
|
}
|
|
11141
11210
|
get translateY() {
|
|
11142
11211
|
return this._translateY;
|
|
@@ -11145,9 +11214,9 @@ class Renderable extends BaseRenderable {
|
|
|
11145
11214
|
if (this._translateY === value)
|
|
11146
11215
|
return;
|
|
11147
11216
|
this._translateY = value;
|
|
11148
|
-
this.requestRender();
|
|
11149
11217
|
if (this.parent)
|
|
11150
11218
|
this.parent.childrenPrimarySortDirty = true;
|
|
11219
|
+
this.requestRender();
|
|
11151
11220
|
}
|
|
11152
11221
|
get x() {
|
|
11153
11222
|
if (this.parent) {
|
|
@@ -11780,7 +11849,9 @@ class Renderable extends BaseRenderable {
|
|
|
11780
11849
|
x: scissorRect.x,
|
|
11781
11850
|
y: scissorRect.y,
|
|
11782
11851
|
width: scissorRect.width,
|
|
11783
|
-
height: scissorRect.height
|
|
11852
|
+
height: scissorRect.height,
|
|
11853
|
+
screenX: this.x,
|
|
11854
|
+
screenY: this.y
|
|
11784
11855
|
});
|
|
11785
11856
|
}
|
|
11786
11857
|
const visibleChildren = this._getVisibleChildren();
|
|
@@ -11996,6 +12067,7 @@ class RootRenderable extends Renderable {
|
|
|
11996
12067
|
}
|
|
11997
12068
|
this.renderList.length = 0;
|
|
11998
12069
|
this.updateLayout(deltaTime, this.renderList);
|
|
12070
|
+
this._ctx.clearHitGridScissorRects();
|
|
11999
12071
|
for (let i = 1;i < this.renderList.length; i++) {
|
|
12000
12072
|
const command = this.renderList[i];
|
|
12001
12073
|
switch (command.action) {
|
|
@@ -12006,9 +12078,11 @@ class RootRenderable extends Renderable {
|
|
|
12006
12078
|
break;
|
|
12007
12079
|
case "pushScissorRect":
|
|
12008
12080
|
buffer.pushScissorRect(command.x, command.y, command.width, command.height);
|
|
12081
|
+
this._ctx.pushHitGridScissorRect(command.screenX, command.screenY, command.width, command.height);
|
|
12009
12082
|
break;
|
|
12010
12083
|
case "popScissorRect":
|
|
12011
12084
|
buffer.popScissorRect();
|
|
12085
|
+
this._ctx.popHitGridScissorRect();
|
|
12012
12086
|
break;
|
|
12013
12087
|
case "pushOpacity":
|
|
12014
12088
|
buffer.pushOpacity(command.opacity);
|
|
@@ -13524,6 +13598,8 @@ class CliRenderer extends EventEmitter9 {
|
|
|
13524
13598
|
exitSignals;
|
|
13525
13599
|
_exitListenersAdded = false;
|
|
13526
13600
|
_isDestroyed = false;
|
|
13601
|
+
_destroyPending = false;
|
|
13602
|
+
_destroyFinalized = false;
|
|
13527
13603
|
nextRenderBuffer;
|
|
13528
13604
|
currentRenderBuffer;
|
|
13529
13605
|
_isRunning = false;
|
|
@@ -13609,6 +13685,7 @@ class CliRenderer extends EventEmitter9 {
|
|
|
13609
13685
|
}).bind(this);
|
|
13610
13686
|
_capabilities = null;
|
|
13611
13687
|
_latestPointer = { x: 0, y: 0 };
|
|
13688
|
+
_hasPointer = false;
|
|
13612
13689
|
_currentFocusedRenderable = null;
|
|
13613
13690
|
lifecyclePasses = new Set;
|
|
13614
13691
|
_openConsoleOnError = true;
|
|
@@ -13790,11 +13867,26 @@ Captured output:
|
|
|
13790
13867
|
}
|
|
13791
13868
|
this._currentFocusedRenderable = renderable;
|
|
13792
13869
|
}
|
|
13870
|
+
setCapturedRenderable(renderable) {
|
|
13871
|
+
if (this.capturedRenderable === renderable) {
|
|
13872
|
+
return;
|
|
13873
|
+
}
|
|
13874
|
+
this.capturedRenderable = renderable;
|
|
13875
|
+
}
|
|
13793
13876
|
addToHitGrid(x, y, width, height, id) {
|
|
13794
13877
|
if (id !== this.capturedRenderable?.num) {
|
|
13795
13878
|
this.lib.addToHitGrid(this.rendererPtr, x, y, width, height, id);
|
|
13796
13879
|
}
|
|
13797
13880
|
}
|
|
13881
|
+
pushHitGridScissorRect(x, y, width, height) {
|
|
13882
|
+
this.lib.hitGridPushScissorRect(this.rendererPtr, x, y, width, height);
|
|
13883
|
+
}
|
|
13884
|
+
popHitGridScissorRect() {
|
|
13885
|
+
this.lib.hitGridPopScissorRect(this.rendererPtr);
|
|
13886
|
+
}
|
|
13887
|
+
clearHitGridScissorRects() {
|
|
13888
|
+
this.lib.hitGridClearScissorRects(this.rendererPtr);
|
|
13889
|
+
}
|
|
13798
13890
|
get widthMethod() {
|
|
13799
13891
|
const caps = this.capabilities;
|
|
13800
13892
|
return caps?.unicode === "wcwidth" ? "wcwidth" : "unicode";
|
|
@@ -13989,7 +14081,11 @@ Captured output:
|
|
|
13989
14081
|
const backgroundColor = this.backgroundColor.toInts();
|
|
13990
14082
|
const newlines = " ".repeat(this.width) + `
|
|
13991
14083
|
`.repeat(space);
|
|
13992
|
-
|
|
14084
|
+
if (backgroundColor[3] === 0) {
|
|
14085
|
+
clear = newlines;
|
|
14086
|
+
} else {
|
|
14087
|
+
clear = ANSI.setRgbBackground(backgroundColor[0], backgroundColor[1], backgroundColor[2]) + newlines + ANSI.resetBackground;
|
|
14088
|
+
}
|
|
13993
14089
|
}
|
|
13994
14090
|
this.writeOut(flush + move + output + clear);
|
|
13995
14091
|
return true;
|
|
@@ -14000,7 +14096,7 @@ Captured output:
|
|
|
14000
14096
|
}
|
|
14001
14097
|
disableMouse() {
|
|
14002
14098
|
this._useMouse = false;
|
|
14003
|
-
this.
|
|
14099
|
+
this.setCapturedRenderable(undefined);
|
|
14004
14100
|
this.mouseParser.reset();
|
|
14005
14101
|
this.lib.disableMouse(this.rendererPtr);
|
|
14006
14102
|
}
|
|
@@ -14118,6 +14214,7 @@ Captured output:
|
|
|
14118
14214
|
}
|
|
14119
14215
|
this._latestPointer.x = mouseEvent.x;
|
|
14120
14216
|
this._latestPointer.y = mouseEvent.y;
|
|
14217
|
+
this._hasPointer = true;
|
|
14121
14218
|
if (this._console.visible) {
|
|
14122
14219
|
const consoleBounds = this._console.bounds;
|
|
14123
14220
|
if (mouseEvent.x >= consoleBounds.x && mouseEvent.x < consoleBounds.x + consoleBounds.width && mouseEvent.y >= consoleBounds.y && mouseEvent.y < consoleBounds.y + consoleBounds.height) {
|
|
@@ -14128,7 +14225,7 @@ Captured output:
|
|
|
14128
14225
|
}
|
|
14129
14226
|
}
|
|
14130
14227
|
if (mouseEvent.type === "scroll") {
|
|
14131
|
-
const maybeRenderableId2 = this.
|
|
14228
|
+
const maybeRenderableId2 = this.hitTest(mouseEvent.x, mouseEvent.y);
|
|
14132
14229
|
const maybeRenderable2 = Renderable.renderablesByNumber.get(maybeRenderableId2);
|
|
14133
14230
|
if (maybeRenderable2) {
|
|
14134
14231
|
const event2 = new MouseEvent(maybeRenderable2, mouseEvent);
|
|
@@ -14136,7 +14233,7 @@ Captured output:
|
|
|
14136
14233
|
}
|
|
14137
14234
|
return true;
|
|
14138
14235
|
}
|
|
14139
|
-
const maybeRenderableId = this.
|
|
14236
|
+
const maybeRenderableId = this.hitTest(mouseEvent.x, mouseEvent.y);
|
|
14140
14237
|
const sameElement = maybeRenderableId === this.lastOverRenderableNum;
|
|
14141
14238
|
this.lastOverRenderableNum = maybeRenderableId;
|
|
14142
14239
|
const maybeRenderable = Renderable.renderablesByNumber.get(maybeRenderableId);
|
|
@@ -14205,20 +14302,20 @@ Captured output:
|
|
|
14205
14302
|
}
|
|
14206
14303
|
this.lastOverRenderable = this.capturedRenderable;
|
|
14207
14304
|
this.lastOverRenderableNum = this.capturedRenderable.num;
|
|
14208
|
-
this.
|
|
14305
|
+
this.setCapturedRenderable(undefined);
|
|
14209
14306
|
this.requestRender();
|
|
14210
14307
|
}
|
|
14211
14308
|
let event = undefined;
|
|
14212
14309
|
if (maybeRenderable) {
|
|
14213
14310
|
if (mouseEvent.type === "drag" && mouseEvent.button === 0) {
|
|
14214
|
-
this.
|
|
14311
|
+
this.setCapturedRenderable(maybeRenderable);
|
|
14215
14312
|
} else {
|
|
14216
|
-
this.
|
|
14313
|
+
this.setCapturedRenderable(undefined);
|
|
14217
14314
|
}
|
|
14218
14315
|
event = new MouseEvent(maybeRenderable, mouseEvent);
|
|
14219
14316
|
maybeRenderable.processMouseEvent(event);
|
|
14220
14317
|
} else {
|
|
14221
|
-
this.
|
|
14318
|
+
this.setCapturedRenderable(undefined);
|
|
14222
14319
|
this.lastOverRenderable = undefined;
|
|
14223
14320
|
}
|
|
14224
14321
|
if (!event?.defaultPrevented && mouseEvent.type === "down" && this.currentSelection) {
|
|
@@ -14228,6 +14325,9 @@ Captured output:
|
|
|
14228
14325
|
}
|
|
14229
14326
|
return false;
|
|
14230
14327
|
}
|
|
14328
|
+
hitTest(x, y) {
|
|
14329
|
+
return this.lib.checkHit(this.rendererPtr, x, y);
|
|
14330
|
+
}
|
|
14231
14331
|
takeMemorySnapshot() {
|
|
14232
14332
|
if (this._isDestroyed)
|
|
14233
14333
|
return;
|
|
@@ -14288,7 +14388,7 @@ Captured output:
|
|
|
14288
14388
|
this._terminalWidth = width;
|
|
14289
14389
|
this._terminalHeight = height;
|
|
14290
14390
|
this.queryPixelResolution();
|
|
14291
|
-
this.
|
|
14391
|
+
this.setCapturedRenderable(undefined);
|
|
14292
14392
|
this.mouseParser.reset();
|
|
14293
14393
|
if (this._splitHeight > 0) {
|
|
14294
14394
|
if (width < prevWidth) {
|
|
@@ -14500,6 +14600,17 @@ Captured output:
|
|
|
14500
14600
|
if (this._isDestroyed)
|
|
14501
14601
|
return;
|
|
14502
14602
|
this._isDestroyed = true;
|
|
14603
|
+
this._destroyPending = true;
|
|
14604
|
+
if (this.rendering) {
|
|
14605
|
+
return;
|
|
14606
|
+
}
|
|
14607
|
+
this.finalizeDestroy();
|
|
14608
|
+
}
|
|
14609
|
+
finalizeDestroy() {
|
|
14610
|
+
if (this._destroyFinalized)
|
|
14611
|
+
return;
|
|
14612
|
+
this._destroyFinalized = true;
|
|
14613
|
+
this._destroyPending = false;
|
|
14503
14614
|
process.removeListener("SIGWINCH", this.sigwinchHandler);
|
|
14504
14615
|
process.removeListener("uncaughtException", this.handleError);
|
|
14505
14616
|
process.removeListener("unhandledRejection", this.handleError);
|
|
@@ -14531,7 +14642,7 @@ Captured output:
|
|
|
14531
14642
|
}
|
|
14532
14643
|
this._isRunning = false;
|
|
14533
14644
|
this.waitingForPixelResolution = false;
|
|
14534
|
-
this.
|
|
14645
|
+
this.setCapturedRenderable(undefined);
|
|
14535
14646
|
try {
|
|
14536
14647
|
this.root.destroyRecursively();
|
|
14537
14648
|
} catch (e) {
|
|
@@ -14576,65 +14687,71 @@ Captured output:
|
|
|
14576
14687
|
clearTimeout(this.renderTimeout);
|
|
14577
14688
|
this.renderTimeout = null;
|
|
14578
14689
|
}
|
|
14579
|
-
|
|
14580
|
-
|
|
14581
|
-
|
|
14582
|
-
|
|
14583
|
-
|
|
14584
|
-
|
|
14585
|
-
this.
|
|
14586
|
-
|
|
14587
|
-
|
|
14588
|
-
|
|
14589
|
-
|
|
14590
|
-
|
|
14591
|
-
|
|
14592
|
-
|
|
14593
|
-
|
|
14594
|
-
|
|
14595
|
-
|
|
14596
|
-
callback
|
|
14597
|
-
|
|
14598
|
-
|
|
14599
|
-
|
|
14600
|
-
|
|
14601
|
-
|
|
14602
|
-
|
|
14603
|
-
|
|
14604
|
-
|
|
14605
|
-
|
|
14606
|
-
|
|
14607
|
-
|
|
14608
|
-
|
|
14609
|
-
|
|
14610
|
-
|
|
14611
|
-
|
|
14612
|
-
|
|
14613
|
-
postProcessFn
|
|
14614
|
-
|
|
14615
|
-
|
|
14616
|
-
|
|
14617
|
-
this.
|
|
14618
|
-
|
|
14619
|
-
|
|
14620
|
-
|
|
14621
|
-
this.
|
|
14622
|
-
|
|
14623
|
-
|
|
14624
|
-
|
|
14625
|
-
|
|
14626
|
-
|
|
14627
|
-
|
|
14690
|
+
try {
|
|
14691
|
+
const now = Date.now();
|
|
14692
|
+
const elapsed = now - this.lastTime;
|
|
14693
|
+
const deltaTime = elapsed;
|
|
14694
|
+
this.lastTime = now;
|
|
14695
|
+
this.frameCount++;
|
|
14696
|
+
if (now - this.lastFpsTime >= 1000) {
|
|
14697
|
+
this.currentFps = this.frameCount;
|
|
14698
|
+
this.frameCount = 0;
|
|
14699
|
+
this.lastFpsTime = now;
|
|
14700
|
+
}
|
|
14701
|
+
this.renderStats.frameCount++;
|
|
14702
|
+
this.renderStats.fps = this.currentFps;
|
|
14703
|
+
const overallStart = performance.now();
|
|
14704
|
+
const frameRequests = Array.from(this.animationRequest.values());
|
|
14705
|
+
this.animationRequest.clear();
|
|
14706
|
+
const animationRequestStart = performance.now();
|
|
14707
|
+
for (const callback of frameRequests) {
|
|
14708
|
+
callback(deltaTime);
|
|
14709
|
+
this.dropLive();
|
|
14710
|
+
}
|
|
14711
|
+
const animationRequestEnd = performance.now();
|
|
14712
|
+
const animationRequestTime = animationRequestEnd - animationRequestStart;
|
|
14713
|
+
const start = performance.now();
|
|
14714
|
+
for (const frameCallback of this.frameCallbacks) {
|
|
14715
|
+
try {
|
|
14716
|
+
await frameCallback(deltaTime);
|
|
14717
|
+
} catch (error) {
|
|
14718
|
+
console.error("Error in frame callback:", error);
|
|
14719
|
+
}
|
|
14720
|
+
}
|
|
14721
|
+
const end = performance.now();
|
|
14722
|
+
this.renderStats.frameCallbackTime = end - start;
|
|
14723
|
+
this.root.render(this.nextRenderBuffer, deltaTime);
|
|
14724
|
+
for (const postProcessFn of this.postProcessFns) {
|
|
14725
|
+
postProcessFn(this.nextRenderBuffer, deltaTime);
|
|
14726
|
+
}
|
|
14727
|
+
this._console.renderToBuffer(this.nextRenderBuffer);
|
|
14728
|
+
if (!this._isDestroyed) {
|
|
14729
|
+
this.renderNative();
|
|
14730
|
+
const overallFrameTime = performance.now() - overallStart;
|
|
14731
|
+
this.lib.updateStats(this.rendererPtr, overallFrameTime, this.renderStats.fps, this.renderStats.frameCallbackTime);
|
|
14732
|
+
if (this.gatherStats) {
|
|
14733
|
+
this.collectStatSample(overallFrameTime);
|
|
14734
|
+
}
|
|
14735
|
+
if (this._isRunning || this.immediateRerenderRequested) {
|
|
14736
|
+
const targetFrameTime = this.immediateRerenderRequested ? this.minTargetFrameTime : this.targetFrameTime;
|
|
14737
|
+
const delay = Math.max(1, targetFrameTime - Math.floor(overallFrameTime));
|
|
14738
|
+
this.immediateRerenderRequested = false;
|
|
14739
|
+
this.renderTimeout = setTimeout(() => {
|
|
14740
|
+
this.renderTimeout = null;
|
|
14741
|
+
this.loop();
|
|
14742
|
+
}, delay);
|
|
14743
|
+
} else {
|
|
14744
|
+
clearTimeout(this.renderTimeout);
|
|
14628
14745
|
this.renderTimeout = null;
|
|
14629
|
-
|
|
14630
|
-
}, delay);
|
|
14631
|
-
} else {
|
|
14632
|
-
clearTimeout(this.renderTimeout);
|
|
14633
|
-
this.renderTimeout = null;
|
|
14746
|
+
}
|
|
14634
14747
|
}
|
|
14748
|
+
} finally {
|
|
14749
|
+
this.rendering = false;
|
|
14750
|
+
if (this._destroyPending) {
|
|
14751
|
+
this.finalizeDestroy();
|
|
14752
|
+
}
|
|
14753
|
+
this.resolveIdleIfNeeded();
|
|
14635
14754
|
}
|
|
14636
|
-
this.rendering = false;
|
|
14637
|
-
this.resolveIdleIfNeeded();
|
|
14638
14755
|
}
|
|
14639
14756
|
intermediateRender() {
|
|
14640
14757
|
this.immediateRerenderRequested = true;
|
|
@@ -14739,7 +14856,7 @@ Captured output:
|
|
|
14739
14856
|
requestSelectionUpdate() {
|
|
14740
14857
|
if (this.currentSelection?.isSelecting) {
|
|
14741
14858
|
const pointer = this._latestPointer;
|
|
14742
|
-
const maybeRenderableId = this.
|
|
14859
|
+
const maybeRenderableId = this.hitTest(pointer.x, pointer.y);
|
|
14743
14860
|
const maybeRenderable = Renderable.renderablesByNumber.get(maybeRenderableId);
|
|
14744
14861
|
this.updateSelection(maybeRenderable, pointer.x, pointer.y);
|
|
14745
14862
|
}
|
|
@@ -17950,7 +18067,8 @@ class TextRenderable extends TextBufferRenderable {
|
|
|
17950
18067
|
const chunks = this.rootTextNode.gatherWithInheritedStyle({
|
|
17951
18068
|
fg: this._defaultFg,
|
|
17952
18069
|
bg: this._defaultBg,
|
|
17953
|
-
attributes: this._defaultAttributes
|
|
18070
|
+
attributes: this._defaultAttributes,
|
|
18071
|
+
link: undefined
|
|
17954
18072
|
});
|
|
17955
18073
|
this.textBuffer.setStyledText(new StyledText(chunks));
|
|
17956
18074
|
this.refreshLocalSelection();
|
|
@@ -20664,6 +20782,16 @@ function isGitRepo(cwd) {
|
|
|
20664
20782
|
return false;
|
|
20665
20783
|
}
|
|
20666
20784
|
}
|
|
20785
|
+
function getRepoRoot(cwd) {
|
|
20786
|
+
try {
|
|
20787
|
+
return execSync("git rev-parse --show-toplevel", {
|
|
20788
|
+
cwd,
|
|
20789
|
+
encoding: "utf-8"
|
|
20790
|
+
}).trim();
|
|
20791
|
+
} catch {
|
|
20792
|
+
throw new Error("Not a git repository");
|
|
20793
|
+
}
|
|
20794
|
+
}
|
|
20667
20795
|
function getMainBranch(cwd) {
|
|
20668
20796
|
try {
|
|
20669
20797
|
const result = execSync('git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null || echo "refs/heads/main"', {
|
|
@@ -20746,10 +20874,10 @@ function getCommitFileDiffs(cwd, commitSha) {
|
|
|
20746
20874
|
// src/utils/tracking.ts
|
|
20747
20875
|
import * as fs3 from "fs/promises";
|
|
20748
20876
|
import * as path3 from "path";
|
|
20749
|
-
async function loadTrackingFiles(
|
|
20877
|
+
async function loadTrackingFiles(trackingDir, commits) {
|
|
20750
20878
|
const result = [];
|
|
20751
20879
|
for (const commit of commits) {
|
|
20752
|
-
const trackingPath = path3.join(
|
|
20880
|
+
const trackingPath = path3.join(trackingDir, `${commit.shortSha}.json`);
|
|
20753
20881
|
let tracking = null;
|
|
20754
20882
|
try {
|
|
20755
20883
|
const content = await fs3.readFile(trackingPath, "utf-8");
|
|
@@ -20809,11 +20937,89 @@ function aggregateByReasoning(cwd, trackedCommits) {
|
|
|
20809
20937
|
return Array.from(reasoningMap.values()).filter((group) => group.files.length > 0).sort((a, b) => b.files.length - a.files.length);
|
|
20810
20938
|
}
|
|
20811
20939
|
|
|
20940
|
+
// src/utils/settings.ts
|
|
20941
|
+
import * as fs4 from "fs/promises";
|
|
20942
|
+
import * as path5 from "path";
|
|
20943
|
+
import * as os2 from "os";
|
|
20944
|
+
import { execSync as execSync2 } from "child_process";
|
|
20945
|
+
var DEFAULT_SETTINGS = {
|
|
20946
|
+
storage: "local",
|
|
20947
|
+
autoCommit: true,
|
|
20948
|
+
globalDir: "~/.codewalk"
|
|
20949
|
+
};
|
|
20950
|
+
function parseYamlFrontmatter(content) {
|
|
20951
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
20952
|
+
if (!match)
|
|
20953
|
+
return null;
|
|
20954
|
+
const yaml = match[1];
|
|
20955
|
+
const result = {};
|
|
20956
|
+
for (const line of yaml.split(`
|
|
20957
|
+
`)) {
|
|
20958
|
+
const colonIndex = line.indexOf(":");
|
|
20959
|
+
if (colonIndex === -1)
|
|
20960
|
+
continue;
|
|
20961
|
+
const key = line.slice(0, colonIndex).trim();
|
|
20962
|
+
let value = line.slice(colonIndex + 1).trim();
|
|
20963
|
+
if (value === "true")
|
|
20964
|
+
value = true;
|
|
20965
|
+
else if (value === "false")
|
|
20966
|
+
value = false;
|
|
20967
|
+
result[key] = value;
|
|
20968
|
+
}
|
|
20969
|
+
return result;
|
|
20970
|
+
}
|
|
20971
|
+
function expandTilde(filepath) {
|
|
20972
|
+
if (filepath.startsWith("~/")) {
|
|
20973
|
+
return path5.join(os2.homedir(), filepath.slice(2));
|
|
20974
|
+
}
|
|
20975
|
+
if (filepath === "~") {
|
|
20976
|
+
return os2.homedir();
|
|
20977
|
+
}
|
|
20978
|
+
return filepath;
|
|
20979
|
+
}
|
|
20980
|
+
function getRepoName(cwd) {
|
|
20981
|
+
try {
|
|
20982
|
+
const repoRoot = execSync2("git rev-parse --show-toplevel", {
|
|
20983
|
+
cwd,
|
|
20984
|
+
encoding: "utf-8",
|
|
20985
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
20986
|
+
}).trim();
|
|
20987
|
+
return path5.basename(repoRoot);
|
|
20988
|
+
} catch {
|
|
20989
|
+
return path5.basename(cwd);
|
|
20990
|
+
}
|
|
20991
|
+
}
|
|
20992
|
+
async function loadSettings(cwd) {
|
|
20993
|
+
const settingsPath = path5.join(cwd, ".claude", "codewalk.local.md");
|
|
20994
|
+
try {
|
|
20995
|
+
const content = await fs4.readFile(settingsPath, "utf-8");
|
|
20996
|
+
const parsed = parseYamlFrontmatter(content);
|
|
20997
|
+
if (!parsed) {
|
|
20998
|
+
return { ...DEFAULT_SETTINGS, globalDir: expandTilde(DEFAULT_SETTINGS.globalDir) };
|
|
20999
|
+
}
|
|
21000
|
+
return {
|
|
21001
|
+
storage: parsed.storage === "global" ? "global" : "local",
|
|
21002
|
+
autoCommit: parsed.autoCommit !== false,
|
|
21003
|
+
globalDir: expandTilde(String(parsed.globalDir || DEFAULT_SETTINGS.globalDir))
|
|
21004
|
+
};
|
|
21005
|
+
} catch {
|
|
21006
|
+
return { ...DEFAULT_SETTINGS, globalDir: expandTilde(DEFAULT_SETTINGS.globalDir) };
|
|
21007
|
+
}
|
|
21008
|
+
}
|
|
21009
|
+
function getTrackingDirectory(cwd, settings) {
|
|
21010
|
+
if (settings.storage === "global") {
|
|
21011
|
+
const repoName = getRepoName(cwd);
|
|
21012
|
+
return path5.join(settings.globalDir, repoName);
|
|
21013
|
+
}
|
|
21014
|
+
return path5.join(cwd, ".codewalk");
|
|
21015
|
+
}
|
|
21016
|
+
|
|
20812
21017
|
// src/tui/app.ts
|
|
20813
|
-
function createAppState(branch, reasoningGroups) {
|
|
21018
|
+
function createAppState(branch, reasoningGroups, trackingDir) {
|
|
20814
21019
|
return {
|
|
20815
21020
|
branch,
|
|
20816
21021
|
reasoningGroups,
|
|
21022
|
+
trackingDir,
|
|
20817
21023
|
selectedIndex: 0,
|
|
20818
21024
|
expandedReasonings: new Set,
|
|
20819
21025
|
expandedFiles: new Set
|
|
@@ -21018,14 +21224,26 @@ class TreeView {
|
|
|
21018
21224
|
for (const child of headerChildren) {
|
|
21019
21225
|
this.headerBox.remove(child.id);
|
|
21020
21226
|
}
|
|
21227
|
+
const headerContainer = new BoxRenderable(this.renderer, {
|
|
21228
|
+
width: "100%",
|
|
21229
|
+
flexDirection: "row",
|
|
21230
|
+
paddingLeft: 1,
|
|
21231
|
+
paddingRight: 1
|
|
21232
|
+
});
|
|
21021
21233
|
const totalChanges = this.state.reasoningGroups.length;
|
|
21022
21234
|
const headerText = new TextRenderable(this.renderer, {
|
|
21023
|
-
content: `
|
|
21235
|
+
content: ` codewalk - ${this.state.branch} (${totalChanges} logical changes)`,
|
|
21024
21236
|
fg: "#88ccff",
|
|
21025
|
-
|
|
21026
|
-
|
|
21237
|
+
flexGrow: 1
|
|
21238
|
+
});
|
|
21239
|
+
headerContainer.add(headerText);
|
|
21240
|
+
const trackingPath = this.state.trackingDir.replace(process.env.HOME || "", "~");
|
|
21241
|
+
const trackingText = new TextRenderable(this.renderer, {
|
|
21242
|
+
content: trackingPath,
|
|
21243
|
+
fg: "#666666"
|
|
21027
21244
|
});
|
|
21028
|
-
|
|
21245
|
+
headerContainer.add(trackingText);
|
|
21246
|
+
this.headerBox.add(headerContainer);
|
|
21029
21247
|
}
|
|
21030
21248
|
buildContent() {
|
|
21031
21249
|
if (this.state.reasoningGroups.length === 0) {
|
|
@@ -21312,13 +21530,13 @@ class TreeView {
|
|
|
21312
21530
|
}
|
|
21313
21531
|
|
|
21314
21532
|
// src/commands/visualize.ts
|
|
21315
|
-
async function loadBranchData(cwd) {
|
|
21533
|
+
async function loadBranchData(cwd, trackingDir) {
|
|
21316
21534
|
const branch = getCurrentBranch(cwd);
|
|
21317
21535
|
const commits = getBranchCommits(cwd);
|
|
21318
21536
|
if (commits.length === 0) {
|
|
21319
21537
|
return { branch, reasoningGroups: [] };
|
|
21320
21538
|
}
|
|
21321
|
-
const allTrackedCommits = await loadTrackingFiles(
|
|
21539
|
+
const allTrackedCommits = await loadTrackingFiles(trackingDir, commits);
|
|
21322
21540
|
const trackedCommits = getTrackedCommits(allTrackedCommits);
|
|
21323
21541
|
if (trackedCommits.length === 0) {
|
|
21324
21542
|
return { branch, reasoningGroups: [] };
|
|
@@ -21332,8 +21550,11 @@ async function visualizeCommand(options) {
|
|
|
21332
21550
|
console.error(import_picocolors2.default.red("Error: Not a git repository"));
|
|
21333
21551
|
process.exit(1);
|
|
21334
21552
|
}
|
|
21553
|
+
const repoRoot = getRepoRoot(cwd);
|
|
21554
|
+
const settings = await loadSettings(repoRoot);
|
|
21555
|
+
const trackingDir = getTrackingDirectory(repoRoot, settings);
|
|
21335
21556
|
console.log(import_picocolors2.default.dim("Loading tracking data..."));
|
|
21336
|
-
const { branch, reasoningGroups } = await loadBranchData(
|
|
21557
|
+
const { branch, reasoningGroups } = await loadBranchData(repoRoot, trackingDir);
|
|
21337
21558
|
console.log(import_picocolors2.default.dim("Starting visualizer..."));
|
|
21338
21559
|
const renderer = await createCliRenderer({
|
|
21339
21560
|
exitOnCtrlC: true,
|
|
@@ -21341,16 +21562,15 @@ async function visualizeCommand(options) {
|
|
|
21341
21562
|
useMouse: true,
|
|
21342
21563
|
backgroundColor: "#0f0f1a"
|
|
21343
21564
|
});
|
|
21344
|
-
const state = createAppState(branch, reasoningGroups);
|
|
21565
|
+
const state = createAppState(branch, reasoningGroups, trackingDir);
|
|
21345
21566
|
const treeView = new TreeView(renderer, state);
|
|
21346
21567
|
let currentBranch = branch;
|
|
21347
|
-
const
|
|
21348
|
-
const gitHeadPath = path5.join(cwd, ".git", "HEAD");
|
|
21568
|
+
const gitHeadPath = path7.join(repoRoot, ".git", "HEAD");
|
|
21349
21569
|
let trackingWatcher = null;
|
|
21350
21570
|
let branchWatcher = null;
|
|
21351
21571
|
let debounceTimer = null;
|
|
21352
21572
|
const reloadData = async (branchChanged = false) => {
|
|
21353
|
-
const { branch: newBranch, reasoningGroups: newGroups } = await loadBranchData(
|
|
21573
|
+
const { branch: newBranch, reasoningGroups: newGroups } = await loadBranchData(repoRoot, trackingDir);
|
|
21354
21574
|
if (branchChanged || newBranch !== currentBranch) {
|
|
21355
21575
|
currentBranch = newBranch;
|
|
21356
21576
|
treeView.updateData(newGroups, newBranch);
|
|
@@ -21359,7 +21579,8 @@ async function visualizeCommand(options) {
|
|
|
21359
21579
|
}
|
|
21360
21580
|
};
|
|
21361
21581
|
try {
|
|
21362
|
-
|
|
21582
|
+
await fs5.promises.mkdir(trackingDir, { recursive: true });
|
|
21583
|
+
trackingWatcher = fs5.watch(trackingDir, (eventType, filename) => {
|
|
21363
21584
|
if (filename && filename.endsWith(".json")) {
|
|
21364
21585
|
if (debounceTimer)
|
|
21365
21586
|
clearTimeout(debounceTimer);
|
|
@@ -21368,7 +21589,7 @@ async function visualizeCommand(options) {
|
|
|
21368
21589
|
});
|
|
21369
21590
|
} catch {}
|
|
21370
21591
|
try {
|
|
21371
|
-
branchWatcher =
|
|
21592
|
+
branchWatcher = fs5.watch(gitHeadPath, () => {
|
|
21372
21593
|
if (debounceTimer)
|
|
21373
21594
|
clearTimeout(debounceTimer);
|
|
21374
21595
|
debounceTimer = setTimeout(() => reloadData(true), 100);
|
|
@@ -21415,8 +21636,8 @@ async function visualizeCommand(options) {
|
|
|
21415
21636
|
|
|
21416
21637
|
// src/index.ts
|
|
21417
21638
|
var program2 = new Command;
|
|
21418
|
-
program2.name("
|
|
21419
|
-
program2.command("init").description("Initialize
|
|
21639
|
+
program2.name("codewalk").description("CLI tool for visualizing AI-assisted code changes").version("0.1.0");
|
|
21640
|
+
program2.command("init").description("Initialize codewalk in the current project").action(async () => {
|
|
21420
21641
|
try {
|
|
21421
21642
|
await initCommand({ cwd: process.cwd() });
|
|
21422
21643
|
} catch (error) {
|