Skip to content

Commit c518815

Browse files
committed
Touch up GM Api's for release
1 parent 3db8d75 commit c518815

30 files changed

+1049
-461
lines changed

README.md

Lines changed: 53 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,79 @@
11
# CodeTweak
22

3-
**CodeTweak** is a modern user script manager and JavaScript editor, designed as a modern alternative to Tampermonkey. It is fully open source and built with privacy in mind.
3+
CodeTweak is a Manifest V3 userscript manager with a built-in editor.
44

5-
---
5+
## What it does
66

7-
## Description
7+
- Create, edit, enable, and disable userscripts.
8+
- Run scripts by URL pattern and run timing.
9+
- Support common GM APIs (`GM_getValue`, `GM_setValue`, `GM_xmlhttpRequest`, etc).
10+
- Import scripts from Greasy Fork.
811

9-
CodeTweak provides full support for **Manifest V3**, offering a modern code editor with linting, formatting, basic autocomplete, and syntax highlighting. It supports all safe GM APIs and URL matching. Users can install scripts directly from **Greasy Fork** and manage them via the dashboard.
12+
## Install
1013

11-
We prioritize privacy: **no tracking, no analytics, no selling of user data**. All permissions are only requested for GM API support.
14+
### Chrome / Chromium (manual)
1215

13-
---
16+
```bash
17+
npm install
18+
npm run build:chrome
19+
```
1420

15-
## Features
21+
Then:
1622

17-
* **Code Editor** — Customizable editor with linting, formatting, autocomplete, and syntax highlighting.
18-
* **GM API Support** — Supports all safe GM APIs.
19-
* **Regex URLs** — Modern regex support for URL matching.
20-
* **Greasy Fork Integration** — Install scripts directly from CodeTweak or the Greasy Fork website.
21-
* **Privacy First** — No tracking, no analytics, only necessary permissions.
23+
1. Open `chrome://extensions`.
24+
2. Enable `Developer mode`.
25+
3. Click `Load unpacked`.
26+
4. Select `build/chrome`.
2227

23-
---
28+
### Firefox (manual)
2429

25-
## Contributing
30+
```bash
31+
npm install
32+
npm run build:firefox
33+
```
2634

27-
We welcome contributions from the community! Whether fixing bugs, adding features, or improving documentation, your help is appreciated.
35+
Use the generated package:
2836

29-
### Development
37+
- `build/codetweak-firefox.zip`
3038

31-
#### Prerequisites
39+
## Development
3240

33-
* Node.js 16+
34-
* npm
35-
* Chrome/Chromium browser
41+
```bash
42+
npm install
43+
npm run lint
44+
npm run build:chrome
45+
npm run build:firefox
46+
```
3647

37-
#### Build
48+
Docs:
3849

3950
```bash
40-
npm install
41-
npm build.js
51+
npm run docs:dev
52+
npm run docs:build
4253
```
4354

44-
---
55+
## Project structure
56+
57+
- `src/` extension source
58+
- `buildScripts/` browser build scripts
59+
- `docs-src/` VitePress documentation source
4560

46-
## Acknowledgments
61+
## Example userscript
4762

48-
* Built with [CodeMirror](https://codemirror.net/)
49-
* Inspired by [Tampermonkey](https://www.tampermonkey.net/) and [Greasemonkey](https://www.greasespot.net/)
50-
* Icons from [Feather](https://feathericons.com/)
63+
```javascript
64+
// ==UserScript==
65+
// @name Demo: mark page ready
66+
// @match https://example.com/*
67+
// @run-at document-end
68+
// @grant GM_setValue
69+
// ==/UserScript==
5170

52-
---
71+
(async () => {
72+
document.body.setAttribute("data-codetweak", "ready");
73+
await GM_setValue("lastRun", Date.now());
74+
})();
75+
```
5376

5477
## License
5578

56-
This project is licensed under the **MIT License**. See the [LICENSE](LICENSE.txt) file for details.
79+
MIT. See `LICENSE.txt`.

buildScripts/build-firefox.js

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,17 @@ for (const dir of copyDirs) {
3838

3939
const chromeManifest = JSON.parse(readFileSync("src/manifest.json", "utf8"));
4040
const firefoxManifest = { ...chromeManifest };
41-
42-
// Firefox MV3 uses background.scripts instead of background.service_worker
4341
if (firefoxManifest.background?.service_worker) {
4442
firefoxManifest.background = {
4543
scripts: [firefoxManifest.background.service_worker],
4644
type: "module",
4745
};
4846
}
4947

50-
// Remove Chrome-specific permissions
5148
firefoxManifest.permissions = (firefoxManifest.permissions || []).filter(
5249
(p) => p !== "offscreen"
5350
);
5451

55-
// Remove the 'world' property from content_scripts (not supported in Firefox)
5652
if (firefoxManifest.content_scripts) {
5753
firefoxManifest.content_scripts = firefoxManifest.content_scripts.map(
5854
(cs) => {
@@ -66,9 +62,6 @@ firefoxManifest.browser_specific_settings = {
6662
gecko: {
6763
id: "codetweak@MrBlankCoding",
6864
strict_min_version: "128.0",
69-
data_collection_permissions: {
70-
required: ["none"],
71-
},
7265
},
7366
};
7467

@@ -89,20 +82,73 @@ await build({
8982
"src/popup/popup.js",
9083
"src/editor/editor.js",
9184
"src/dashboard/dashboard.js",
92-
"src/ai_dom_editor/ai_dom_content.js",
93-
"src/ai_dom_editor/ai_dom_sidebar.js",
94-
"src/ai_dom_editor/ai_dom_editor.js",
95-
"src/ai_dom_editor/ai_settings.js",
85+
"src/ai_dom_editor/editor/ai_dom_content.js",
86+
"src/ai_dom_editor/sidebar/ai_dom_sidebar.js",
87+
"src/ai_dom_editor/editor/ai_dom_editor.js",
88+
"src/ai_dom_editor/settings/ai_settings.js",
9689
],
9790
bundle: true,
9891
outdir,
9992
logLevel: "info",
10093
platform: "browser",
10194
define: {
10295
"process.env.BROWSER": JSON.stringify(browser),
96+
global: "window",
10397
},
10498
});
10599

100+
// --- POST-BUILD CLEANUP --- //
101+
// Remove eval and Function("return this") which violate CSP
102+
const filesToCleanup = [
103+
join(outdir, "ai_dom_editor/editor/ai_dom_editor.js"),
104+
join(outdir, "editor/editor.js"),
105+
join(outdir, "dashboard/dashboard.js"),
106+
join(outdir, "popup/popup.js"),
107+
join(outdir, "ai_dom_editor/settings/ai_settings.js"),
108+
join(outdir, "GM/gm_core.js"),
109+
];
110+
111+
for (const file of filesToCleanup) {
112+
try {
113+
let content = readFileSync(file, "utf8");
114+
let changed = false;
115+
116+
if (content.includes('Function("return this")')) {
117+
content = content.replace(/Function\("return this"\)/g, "(function() { return window; })");
118+
changed = true;
119+
}
120+
if (/new\s+Function\s*\(\s*['"]unsafeWindow['"]\s*,\s*userCode\s*\)/.test(content)) {
121+
content = content.replace(/new\s+Function\s*\(\s*['"]unsafeWindow['"]\s*,\s*userCode\s*\)/g, "(function(){ throw new EvalError('Function constructor is blocked in Firefox'); })");
122+
changed = true;
123+
}
124+
125+
const evalPatterns = [
126+
/eval\("this"\)/g,
127+
/\(1,\s*eval\)\("this"\)/g,
128+
];
129+
130+
for (const pattern of evalPatterns) {
131+
if (pattern.test(content)) {
132+
content = content.replace(pattern, "window");
133+
changed = true;
134+
}
135+
}
136+
137+
const iframeWritePattern = /iframeDocument\.write\([^;]*document\.F=Object[^;]*\);/g;
138+
if (iframeWritePattern.test(content)) {
139+
content = content.replace(iframeWritePattern, "iframeDocument.F = Object;");
140+
changed = true;
141+
}
142+
143+
if (changed) {
144+
writeFileSync(file, content);
145+
console.log(`Cleaned up CSP-violating patterns in ${file}`);
146+
}
147+
} catch (err) {
148+
console.warn(`Could not cleanup ${file}: ${err.message}`);
149+
}
150+
}
151+
106152
// --- ZIP IN PRODUCTION --- //
107153
if (isProduction) {
108154
const archiveName = `codetweak-firefox.zip`;

docs-src/README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
# CodeTweak Docs Source
1+
# Docs Source
22

3-
This folder contains VitePress source files.
3+
VitePress source files for CodeTweak docs.
44

5-
Build output is generated into `/docs` for GitHub Pages.
5+
## Commands
6+
7+
```bash
8+
npm run docs:dev
9+
npm run docs:build
10+
npm run docs:preview
11+
```

docs-src/guide/dashboard.md

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,25 @@
11
# Manage Scripts
22

3-
Use the dashboard to control all scripts.
3+
Use the dashboard to control scripts and global settings.
44

5-
## Script list
5+
## Script list actions
66

7-
You can:
7+
- Enable or disable scripts.
8+
- Search by script name.
9+
- Filter by status and run timing.
10+
- Open script in editor.
11+
- Delete script.
812

9-
- Enable or disable scripts
10-
- Search by name
11-
- Filter by website, status, and run timing
12-
- Edit or delete scripts
13+
## Settings that matter
1314

14-
## Settings tab
15+
- `Enable scripts by default`
16+
- `Show notifications`
17+
- `Enhanced debugging`
18+
- `Allow external resources`
19+
- `Confirm first run`
1520

16-
Main settings include:
21+
## Safe defaults
1722

18-
- Enable scripts by default
19-
- Show notifications
20-
- Enhanced debugging
21-
- Allow external resources
22-
- Confirm first run
23-
24-
## Best practices
25-
26-
- Keep unused scripts disabled.
27-
- Review scripts with broad `@match` rules.
28-
- Keep `allow external resources` off unless needed.
23+
- Keep `Allow external resources` off unless needed.
24+
- Keep URL scope tight in `@match`.
25+
- Disable scripts you are not using.

docs-src/guide/editor.md

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,57 @@
11
# Use the Editor
22

3-
The editor is where you write and save scripts.
3+
CodeTweak has two editing modes:
44

5-
## Create a script
5+
- Standard script editor
6+
- AI DOM Editor sidebar
67

7-
1. Open dashboard.
8-
2. Click `New Script`.
9-
3. Fill script name and metadata.
8+
## Standard editor workflow
109

11-
## Recommended metadata
10+
1. Set metadata.
11+
2. Write script code.
12+
3. Save.
13+
4. Test on a matching URL.
14+
15+
Minimal metadata template:
1216

1317
```javascript
1418
// ==UserScript==
15-
// @name My Script
16-
// @match *://example.com/*
17-
// @run-at document_end
19+
// @name My Script
20+
// @match https://app.example.com/*
21+
// @run-at document-end
22+
// @grant GM_getValue
23+
// @grant GM_setValue
1824
// ==/UserScript==
1925
```
2026

21-
## Run timing
27+
State example:
28+
29+
```javascript
30+
(async () => {
31+
const count = await GM_getValue("count", 0);
32+
await GM_setValue("count", count + 1);
33+
console.log("runs:", count + 1);
34+
})();
35+
```
36+
37+
## AI DOM Editor workflow
38+
39+
1. Open popup.
40+
2. Click `AI DOM Editor`.
41+
3. Click `Select Element` in sidebar.
42+
4. Click target element on page.
43+
5. Enter instruction.
44+
45+
Example instructions:
46+
47+
- `Hide this element`
48+
- `Change this button text to "Checkout"`
49+
- `Add red border to this card`
2250

23-
- `document_start`: runs early
24-
- `document_end`: runs when DOM is ready
25-
- `document_idle`: runs after page load
51+
Review generated code before saving.
2652

27-
## Tips
53+
## Common mistakes
2854

29-
- Keep one purpose per script.
30-
- Use clear names.
31-
- Keep match patterns narrow.
32-
- Test on one site before broad patterns.
55+
- `@match` too broad (`*://*/*`) or too narrow.
56+
- Wrong `@run-at` for the DOM state you expect.
57+
- Missing `@grant` for GM APIs.

0 commit comments

Comments
 (0)