tabctl 0.3.1 → 0.5.0
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/README.md +9 -7
- package/dist/cli/lib/client.js +3 -3
- package/dist/cli/lib/commands/doctor.js +134 -0
- package/dist/cli/lib/commands/index.js +5 -1
- package/dist/cli/lib/commands/meta.js +12 -12
- package/dist/cli/lib/commands/params-groups.js +8 -0
- package/dist/cli/lib/commands/params.js +6 -6
- package/dist/cli/lib/commands/setup.js +37 -136
- package/dist/cli/lib/constants.js +1 -1
- package/dist/cli/lib/options-commands.js +16 -1
- package/dist/cli/lib/output.js +39 -0
- package/dist/cli/lib/policy-filter.js +2 -2
- package/dist/cli/lib/policy.js +3 -3
- package/dist/cli/lib/response.js +11 -11
- package/dist/cli/tabctl.js +9 -1
- package/dist/extension/background.js +431 -133
- package/dist/extension/lib/content.js +0 -30
- package/dist/extension/lib/groups.js +89 -3
- package/dist/extension/lib/inspect.js +3 -67
- package/dist/extension/lib/screenshot.js +2 -2
- package/dist/extension/lib/tabs.js +97 -36
- package/dist/extension/lib/undo-handlers.js +8 -0
- package/dist/extension/manifest.json +2 -2
- package/dist/host/host.bundle.js +45 -43
- package/dist/host/host.js +11 -11
- package/dist/host/lib/handlers.js +7 -5
- package/dist/host/lib/undo.js +6 -6
- package/dist/shared/config.js +19 -19
- package/dist/shared/extension-sync.js +20 -20
- package/dist/shared/profiles.js +5 -5
- package/dist/shared/version.js +2 -2
- package/dist/shared/wrapper-health.js +132 -0
- package/package.json +8 -4
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Wrapper health checks — parse, validate, and repair profile wrapper scripts.
|
|
4
|
+
*
|
|
5
|
+
* Wrappers are generated by `tabctl setup` and launch the native messaging host.
|
|
6
|
+
* They hardcode absolute paths to Node and the host bundle, which can break when
|
|
7
|
+
* Node is upgraded (e.g., via mise/nvm). This module detects and fixes stale paths.
|
|
8
|
+
*/
|
|
9
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.parseWrapper = parseWrapper;
|
|
14
|
+
exports.checkWrapper = checkWrapper;
|
|
15
|
+
exports.resolveWrapperPath = resolveWrapperPath;
|
|
16
|
+
exports.resolveWrapperTextPath = resolveWrapperTextPath;
|
|
17
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
18
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
19
|
+
// Unix: exec "nodePath" "hostPath"
|
|
20
|
+
const SH_EXEC_RE = /^exec\s+"([^"]+)"\s+"([^"]+)"$/m;
|
|
21
|
+
// Unix: export TABCTL_PROFILE="name"
|
|
22
|
+
const SH_PROFILE_RE = /^export\s+TABCTL_PROFILE="([^"]+)"$/m;
|
|
23
|
+
// Windows .cmd: "nodePath" "hostPath" %*
|
|
24
|
+
const CMD_EXEC_RE = /^"([^"]+)"\s+"([^"]+)"\s+%\*$/m;
|
|
25
|
+
// Windows .cmd: set TABCTL_PROFILE=name
|
|
26
|
+
const CMD_PROFILE_RE = /^set\s+TABCTL_PROFILE=(.+)$/m;
|
|
27
|
+
// Windows .cfg (Go launcher): line 1 = node, line 2 = host, optional TABCTL_PROFILE=name
|
|
28
|
+
const CFG_PROFILE_RE = /^TABCTL_PROFILE=(.+)$/m;
|
|
29
|
+
/**
|
|
30
|
+
* Parse a wrapper script to extract Node path, host path, and profile name.
|
|
31
|
+
* Supports .sh (Unix), .cmd (Windows fallback), and .cfg (Go launcher) formats.
|
|
32
|
+
*/
|
|
33
|
+
function parseWrapper(wrapperPath) {
|
|
34
|
+
try {
|
|
35
|
+
const ext = node_path_1.default.extname(wrapperPath).toLowerCase();
|
|
36
|
+
// .cfg: Go launcher config (host-launcher.cfg next to .exe)
|
|
37
|
+
if (ext === ".cfg") {
|
|
38
|
+
const content = node_fs_1.default.readFileSync(wrapperPath, "utf-8");
|
|
39
|
+
const lines = content.split(/\r?\n/).filter(l => l.trim());
|
|
40
|
+
if (lines.length < 2)
|
|
41
|
+
return null;
|
|
42
|
+
const profileMatch = content.match(CFG_PROFILE_RE);
|
|
43
|
+
return {
|
|
44
|
+
nodePath: lines[0].trim(),
|
|
45
|
+
hostPath: lines[1].trim(),
|
|
46
|
+
profileName: profileMatch ? profileMatch[1].trim() : null,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// .exe: look for host-launcher.cfg in the same directory
|
|
50
|
+
if (ext === ".exe") {
|
|
51
|
+
const cfgPath = node_path_1.default.join(node_path_1.default.dirname(wrapperPath), "host-launcher.cfg");
|
|
52
|
+
if (node_fs_1.default.existsSync(cfgPath)) {
|
|
53
|
+
return parseWrapper(cfgPath);
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
const content = node_fs_1.default.readFileSync(wrapperPath, "utf-8");
|
|
58
|
+
// .cmd: Windows batch
|
|
59
|
+
if (ext === ".cmd") {
|
|
60
|
+
const execMatch = content.match(CMD_EXEC_RE);
|
|
61
|
+
if (!execMatch)
|
|
62
|
+
return null;
|
|
63
|
+
const profileMatch = content.match(CMD_PROFILE_RE);
|
|
64
|
+
return {
|
|
65
|
+
nodePath: execMatch[1],
|
|
66
|
+
hostPath: execMatch[2],
|
|
67
|
+
profileName: profileMatch ? profileMatch[1].trim() : null,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
// .sh or extensionless: Unix shell
|
|
71
|
+
const execMatch = content.match(SH_EXEC_RE);
|
|
72
|
+
if (!execMatch)
|
|
73
|
+
return null;
|
|
74
|
+
const profileMatch = content.match(SH_PROFILE_RE);
|
|
75
|
+
return {
|
|
76
|
+
nodePath: execMatch[1],
|
|
77
|
+
hostPath: execMatch[2],
|
|
78
|
+
profileName: profileMatch ? profileMatch[1] : null,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check wrapper health: parse it and verify all referenced paths exist.
|
|
87
|
+
*/
|
|
88
|
+
function checkWrapper(wrapperPath) {
|
|
89
|
+
const issues = [];
|
|
90
|
+
if (!node_fs_1.default.existsSync(wrapperPath)) {
|
|
91
|
+
return { ok: false, wrapperPath, info: null, issues: [`Wrapper not found: ${wrapperPath}`] };
|
|
92
|
+
}
|
|
93
|
+
const info = parseWrapper(wrapperPath);
|
|
94
|
+
if (!info) {
|
|
95
|
+
return { ok: false, wrapperPath, info: null, issues: [`Could not parse wrapper: ${wrapperPath}`] };
|
|
96
|
+
}
|
|
97
|
+
if (!node_fs_1.default.existsSync(info.nodePath)) {
|
|
98
|
+
issues.push(`Node path not found: ${info.nodePath}`);
|
|
99
|
+
}
|
|
100
|
+
if (!node_fs_1.default.existsSync(info.hostPath)) {
|
|
101
|
+
issues.push(`Host path not found: ${info.hostPath}`);
|
|
102
|
+
}
|
|
103
|
+
return { ok: issues.length === 0, wrapperPath, info, issues };
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Resolve the wrapper path for a profile data directory.
|
|
107
|
+
* Returns the path (may not exist yet).
|
|
108
|
+
*/
|
|
109
|
+
function resolveWrapperPath(profileDataDir) {
|
|
110
|
+
if (process.platform === "win32") {
|
|
111
|
+
const exePath = node_path_1.default.join(profileDataDir, "tabctl-host.exe");
|
|
112
|
+
if (node_fs_1.default.existsSync(exePath))
|
|
113
|
+
return exePath;
|
|
114
|
+
const cmdPath = node_path_1.default.join(profileDataDir, "tabctl-host.cmd");
|
|
115
|
+
if (node_fs_1.default.existsSync(cmdPath))
|
|
116
|
+
return cmdPath;
|
|
117
|
+
return exePath; // default to .exe
|
|
118
|
+
}
|
|
119
|
+
return node_path_1.default.join(profileDataDir, "tabctl-host.sh");
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Resolve the text-editable config path for a wrapper.
|
|
123
|
+
* For .exe wrappers, this is the adjacent host-launcher.cfg.
|
|
124
|
+
* For .sh/.cmd, it's the wrapper itself.
|
|
125
|
+
*/
|
|
126
|
+
function resolveWrapperTextPath(wrapperPath) {
|
|
127
|
+
const ext = node_path_1.default.extname(wrapperPath).toLowerCase();
|
|
128
|
+
if (ext === ".exe") {
|
|
129
|
+
return node_path_1.default.join(node_path_1.default.dirname(wrapperPath), "host-launcher.cfg");
|
|
130
|
+
}
|
|
131
|
+
return wrapperPath;
|
|
132
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tabctl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "CLI tool to manage and analyze browser tabs",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"chrome"
|
|
16
16
|
],
|
|
17
17
|
"engines": {
|
|
18
|
-
"node": ">=
|
|
18
|
+
"node": ">=24"
|
|
19
19
|
},
|
|
20
20
|
"bin": {
|
|
21
21
|
"tabctl": "dist/cli/tabctl.js"
|
|
@@ -31,10 +31,11 @@
|
|
|
31
31
|
"bump:major": "node scripts/bump-version.js major",
|
|
32
32
|
"bump:minor": "node scripts/bump-version.js minor",
|
|
33
33
|
"bump:patch": "node scripts/bump-version.js patch",
|
|
34
|
-
"test": "npm run build && node --test --test-timeout=5000 dist/tests/unit/*.js",
|
|
34
|
+
"test": "npm run build && node --test --test-timeout=5000 dist/tests/unit/*.js && node dist/scripts/integration-test.js",
|
|
35
35
|
"test:unit": "npm run build && node --test --test-timeout=5000 dist/tests/unit/*.js",
|
|
36
36
|
"test:integration": "node dist/scripts/integration-test.js",
|
|
37
|
-
"clean": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\" "
|
|
37
|
+
"clean": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\" ",
|
|
38
|
+
"prepare": "git rev-parse --git-dir >/dev/null 2>&1 && git config core.hooksPath .githooks || true"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"@types/chrome": "^0.0.277",
|
|
@@ -44,5 +45,8 @@
|
|
|
44
45
|
},
|
|
45
46
|
"optionalDependencies": {
|
|
46
47
|
"tabctl-win32-x64": "0.3.0"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"normalize-url": "^8.1.1"
|
|
47
51
|
}
|
|
48
52
|
}
|