@codewithdan/zingit 0.14.0 → 0.16.1
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 +13 -1
- package/CHANGELOG.md +26 -0
- package/client/dist/zingit-client.js +1 -1
- package/package.json +5 -2
- package/server/dist/services/git-manager.js +4 -4
package/AGENTS.md
CHANGED
|
@@ -299,4 +299,16 @@ Automated release and deployment on commits starting with "release:":
|
|
|
299
299
|
1. Runs `npm run release` - versions, builds, and publishes to npm
|
|
300
300
|
2. Runs `npm run deploy` - deploys demo site to GitHub Pages
|
|
301
301
|
|
|
302
|
-
|
|
302
|
+
**Setup Requirements:**
|
|
303
|
+
- `NPM_TOKEN` secret in repository settings (for npm publishing)
|
|
304
|
+
- `GITHUB_TOKEN` is automatically provided by GitHub Actions (for gh-pages deployment)
|
|
305
|
+
|
|
306
|
+
**Authentication:**
|
|
307
|
+
The workflow configures git with an authenticated remote URL before deploying:
|
|
308
|
+
```bash
|
|
309
|
+
git remote set-url origin https://x-access-token:$GITHUB_TOKEN@github.com/${{ github.repository }}.git
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
This allows `gh-pages` to push to the repository without prompting for credentials.
|
|
313
|
+
|
|
314
|
+
**Workflow File:** `.github/workflows/release.yml`
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
|
+
|
|
5
|
+
### [0.16.1](https://github.com/danwahlin/zingit/compare/v0.16.0...v0.16.1) (2026-01-29)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* integrate standard-version for versioning and changelog management ([69c9f4e](https://github.com/danwahlin/zingit/commit/69c9f4ee5a025d845c4ea6bfb9185c8cee306a2f))
|
|
11
|
+
|
|
12
|
+
## [0.16.0](https://github.com/danwahlin/zingit/compare/v0.15.0...v0.16.0) (2026-01-28)
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* **security**: Fix command injection vulnerability in git operations ([server/src/services/git-manager.ts](server/src/services/git-manager.ts))
|
|
17
|
+
* Replaced `execAsync` with `execFileAsync` using array arguments to prevent shell injection
|
|
18
|
+
* Affected commands: git diff, git reset --hard
|
|
19
|
+
* **security**: Fix XSS vulnerability in agent response rendering ([client/src/components/agent-response-panel.ts](client/src/components/agent-response-panel.ts))
|
|
20
|
+
* Implemented safe Lit templating instead of `.innerHTML`
|
|
21
|
+
* All user content is now automatically HTML-escaped by Lit's template system
|
|
22
|
+
* Markdown formatting (bold, italic, code) preserved while preventing script injection
|
|
23
|
+
|
|
24
|
+
### Features
|
|
25
|
+
|
|
26
|
+
* Add 'prompts' keyword to package.json for improved discoverability
|
|
@@ -1442,7 +1442,7 @@
|
|
|
1442
1442
|
<div class="spinner"></div>
|
|
1443
1443
|
<div>Waiting for response${A}...</div>
|
|
1444
1444
|
</div>
|
|
1445
|
-
`}return $`<div class="text-block" style="color: #6b7280;">Add annotations or type a message below to get started.</div>`}return this._parseContent(this.content).map(A=>"code"===A.type?$`<div class="code-block">${A.content}</div>`:this._renderTextAsSteps(A.content))}_renderTextAsSteps(A){const e=A.split(/(?<=\.)\s+(?=[A-Z][a-z])|(?=\n##\s)/).map(A=>A.trim()).filter(A=>A.length>0);return 0===e.length?$``:e.map(A=>{const e=this._classifyStep(A)
|
|
1445
|
+
`}return $`<div class="text-block" style="color: #6b7280;">Add annotations or type a message below to get started.</div>`}return this._parseContent(this.content).map(A=>"code"===A.type?$`<div class="code-block">${A.content}</div>`:this._renderTextAsSteps(A.content))}_renderTextAsSteps(A){const e=A.split(/(?<=\.)\s+(?=[A-Z][a-z])|(?=\n##\s)/).map(A=>A.trim()).filter(A=>A.length>0);return 0===e.length?$``:e.map(A=>{const e=this._classifyStep(A);return $`<div class="action-step ${e}">${this._parseMarkdownToTemplate(A)}</div>`})}_parseMarkdownToTemplate(A){const e=[];let t=0;const n=/(\*\*(.+?)\*\*)|(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)|`([^`]+)`/g;let s;for(;null!==(s=n.exec(A));)s.index>t&&e.push(this._textWithLineBreaks(A.slice(t,s.index))),s[2]?e.push($`<strong>${s[2]}</strong>`):s[3]?e.push($`<em>${s[3]}</em>`):s[4]&&e.push($`<code style="background: rgba(59, 130, 246, 0.15); padding: 2px 6px; border-radius: 3px; font-family: monospace;">${s[4]}</code>`),t=s.index+s[0].length;return t<A.length&&e.push(this._textWithLineBreaks(A.slice(t))),e}_textWithLineBreaks(A){const e=A.split("\n"),t=[];return e.forEach((A,n)=>{t.push(A),n<e.length-1&&t.push($`<br>`)}),t}_classifyStep(A){const e=A.toLowerCase();return e.startsWith("let me check")||e.startsWith("let me look")||e.startsWith("let me run")||e.startsWith("let me also")||e.startsWith("looking at")||e.startsWith("checking")?"check":e.startsWith("added")||e.startsWith("updated")||e.startsWith("created")||e.startsWith("removed")||e.startsWith("fixed")||e.startsWith("changed")?"result":e.startsWith("i don't see")||e.startsWith("i can see")||e.startsWith("there's no")||e.startsWith("there is no")||e.startsWith("the ")||e.startsWith("it's possible")||e.startsWith("perhaps")||e.startsWith("however")?"observation":""}_stopPropagation(A){A.stopPropagation()}_handleClose(A){A.preventDefault(),A.stopPropagation(),this.dispatchEvent(new CustomEvent("close",{bubbles:!0,composed:!0}))}_handleStop(A){A.preventDefault(),A.stopPropagation(),this.dispatchEvent(new CustomEvent("stop",{bubbles:!0,composed:!0}))}_handleRefresh(){window.location.reload()}_handleInputChange(A){this.followUpMessage=A.target.value}_handleInputKeydown(A){"Enter"!==A.key||A.shiftKey||(A.preventDefault(),this._handleSendFollowUp())}_handleSendFollowUp(){this.followUpMessage.trim()&&!this.processing&&(this.dispatchEvent(new CustomEvent("followup",{bubbles:!0,composed:!0,detail:{message:this.followUpMessage}})),this.followUpMessage="")}};$a.styles=o`
|
|
1446
1446
|
:host {
|
|
1447
1447
|
display: block;
|
|
1448
1448
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codewithdan/zingit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.1",
|
|
4
4
|
"description": "AI-powered UI annotation tool - point, annotate, and let AI fix it",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"client/dist",
|
|
16
16
|
"README.md",
|
|
17
17
|
"AGENTS.md",
|
|
18
|
+
"CHANGELOG.md",
|
|
18
19
|
"LICENSE"
|
|
19
20
|
],
|
|
20
21
|
"main": "client/dist/zingit-client.js",
|
|
@@ -29,7 +30,7 @@
|
|
|
29
30
|
"test": "cd client && npm run test",
|
|
30
31
|
"test:watch": "cd client && npm run test:watch",
|
|
31
32
|
"test:ui": "cd client && npm run test:ui",
|
|
32
|
-
"release": "
|
|
33
|
+
"release": "standard-version && npm run build && npm publish --access public"
|
|
33
34
|
},
|
|
34
35
|
"keywords": [
|
|
35
36
|
"ui",
|
|
@@ -40,6 +41,7 @@
|
|
|
40
41
|
"copilot",
|
|
41
42
|
"codex",
|
|
42
43
|
"development",
|
|
44
|
+
"prompts",
|
|
43
45
|
"tool"
|
|
44
46
|
],
|
|
45
47
|
"author": "Dan Wahlin",
|
|
@@ -68,6 +70,7 @@
|
|
|
68
70
|
"@types/ws": "^8.18.1",
|
|
69
71
|
"concurrently": "^9.1.2",
|
|
70
72
|
"gh-pages": "^6.3.0",
|
|
73
|
+
"standard-version": "^9.5.0",
|
|
71
74
|
"tsx": "^4.21.0",
|
|
72
75
|
"typescript": "^5.9.3"
|
|
73
76
|
}
|
|
@@ -145,7 +145,7 @@ export class GitManager {
|
|
|
145
145
|
// Get list of changed files since checkpoint
|
|
146
146
|
let diffStat = '';
|
|
147
147
|
try {
|
|
148
|
-
const result = await
|
|
148
|
+
const result = await execFileAsync('git', ['diff', '--name-status', checkpoint.commitHash], {
|
|
149
149
|
cwd: this.projectDir,
|
|
150
150
|
});
|
|
151
151
|
diffStat = result.stdout;
|
|
@@ -166,7 +166,7 @@ export class GitManager {
|
|
|
166
166
|
let linesAdded = 0;
|
|
167
167
|
let linesRemoved = 0;
|
|
168
168
|
try {
|
|
169
|
-
const { stdout: numstat } = await
|
|
169
|
+
const { stdout: numstat } = await execFileAsync('git', ['diff', '--numstat', checkpoint.commitHash, '--', filePath], { cwd: this.projectDir });
|
|
170
170
|
const parts = numstat.trim().split('\t');
|
|
171
171
|
linesAdded = parseInt(parts[0]) || 0;
|
|
172
172
|
linesRemoved = parseInt(parts[1]) || 0;
|
|
@@ -222,7 +222,7 @@ export class GitManager {
|
|
|
222
222
|
throw new GitManagerError('Checkpoint is not in applied state', 'INVALID_CHECKPOINT_STATE');
|
|
223
223
|
}
|
|
224
224
|
// Reset to the checkpoint's original commit
|
|
225
|
-
await
|
|
225
|
+
await execFileAsync('git', ['reset', '--hard', checkpoint.commitHash], { cwd: this.projectDir });
|
|
226
226
|
// Get files that were reverted
|
|
227
227
|
const filesReverted = [];
|
|
228
228
|
// We could compute this but for now just return empty - the checkpoint has the info
|
|
@@ -245,7 +245,7 @@ export class GitManager {
|
|
|
245
245
|
throw new GitManagerError(`Checkpoint not found: ${checkpointId}`, 'CHECKPOINT_NOT_FOUND');
|
|
246
246
|
}
|
|
247
247
|
// Reset to that commit
|
|
248
|
-
await
|
|
248
|
+
await execFileAsync('git', ['reset', '--hard', checkpoint.commitHash], { cwd: this.projectDir });
|
|
249
249
|
// Mark all checkpoints after this one as reverted
|
|
250
250
|
const checkpointIndex = history.checkpoints.findIndex((c) => c.id === checkpointId);
|
|
251
251
|
for (let i = checkpointIndex + 1; i < history.checkpoints.length; i++) {
|