tabctl 0.2.0 → 0.3.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
CHANGED
|
@@ -27,7 +27,7 @@ If you haven't run `npm link`, you can always use `node ./cli/tabctl.js` instead
|
|
|
27
27
|
|
|
28
28
|
Run the interactive setup — it syncs the extension, tells you where to load it, and prompts for the extension ID:
|
|
29
29
|
|
|
30
|
-
<!-- test: "setup
|
|
30
|
+
<!-- test: "setup explicit --extension-id overrides auto-derived ID" -->
|
|
31
31
|
```bash
|
|
32
32
|
tabctl setup --browser chrome
|
|
33
33
|
```
|
|
@@ -194,10 +194,18 @@ async function runSetup(options, prettyOutput) {
|
|
|
194
194
|
catch {
|
|
195
195
|
extensionSync = null;
|
|
196
196
|
}
|
|
197
|
-
// Resolve extension ID:
|
|
197
|
+
// Resolve extension ID: explicit flag, derived from install path, or interactive prompt
|
|
198
198
|
let extensionId = resolveExtensionId(options, false);
|
|
199
199
|
if (!extensionId) {
|
|
200
|
-
//
|
|
200
|
+
// Auto-derive from the installed extension path (Chromium uses SHA256 of the path)
|
|
201
|
+
const installedDir = (0, extension_sync_1.resolveInstalledExtensionDir)(config.baseDataDir);
|
|
202
|
+
if (fs_1.default.existsSync(path_1.default.join(installedDir, "manifest.json"))) {
|
|
203
|
+
extensionId = (0, extension_sync_1.deriveExtensionId)(installedDir);
|
|
204
|
+
process.stderr.write(`Extension ID derived from: ${installedDir}\n`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (!extensionId) {
|
|
208
|
+
// Interactive mode: sync hadn't happened or path doesn't exist
|
|
201
209
|
if (extensionSync?.extensionDir) {
|
|
202
210
|
process.stderr.write(`\nExtension synced to: ${extensionSync.extensionDir}\n`);
|
|
203
211
|
try {
|
package/dist/cli/lib/output.js
CHANGED
|
@@ -23,7 +23,7 @@ function printJson(payload, pretty = true) {
|
|
|
23
23
|
function errorOut(message) {
|
|
24
24
|
const hints = {
|
|
25
25
|
"Unknown option: --format": "Use --json for JSON output. --format is only for report.",
|
|
26
|
-
"ENOENT": "Native host not running. Ensure the browser extension is loaded and active.",
|
|
26
|
+
"ENOENT": "Native host not running. Ensure the browser extension is loaded and active. If you recently upgraded, run: tabctl setup",
|
|
27
27
|
};
|
|
28
28
|
const hint = Object.entries(hints).find(([key]) => message.includes(key))?.[1];
|
|
29
29
|
if (hint) {
|
|
@@ -46,13 +46,13 @@ function setupStdoutErrorHandling() {
|
|
|
46
46
|
function emitVersionWarnings(response, fallbackAction) {
|
|
47
47
|
const hostVersion = typeof response.version === "string" ? response.version : null;
|
|
48
48
|
if (hostVersion && hostVersion !== version_1.VERSION) {
|
|
49
|
-
process.stderr.write(`[tabctl] version mismatch: cli ${version_1.VERSION}, host ${hostVersion}\n`);
|
|
49
|
+
process.stderr.write(`[tabctl] version mismatch: cli ${version_1.VERSION}, host ${hostVersion}. Run: tabctl setup\n`);
|
|
50
50
|
}
|
|
51
51
|
const data = response.data;
|
|
52
52
|
const extensionVersion = data && typeof data.extensionVersion === "string" ? data.extensionVersion : null;
|
|
53
53
|
const extensionComponent = data && typeof data.extensionComponent === "string" ? data.extensionComponent : null;
|
|
54
54
|
if (extensionVersion && hostVersion && extensionVersion !== hostVersion) {
|
|
55
|
-
process.stderr.write(`[tabctl] version mismatch: host ${hostVersion}, extension ${extensionVersion}\n`);
|
|
55
|
+
process.stderr.write(`[tabctl] version mismatch: host ${hostVersion}, extension ${extensionVersion}. Reload the extension in your browser\n`);
|
|
56
56
|
}
|
|
57
57
|
if (extensionComponent && extensionComponent !== "extension") {
|
|
58
58
|
process.stderr.write(`[tabctl] unexpected extension component: ${extensionComponent}\n`);
|
|
@@ -60,6 +60,6 @@ function emitVersionWarnings(response, fallbackAction) {
|
|
|
60
60
|
const action = response.action || fallbackAction;
|
|
61
61
|
const extensionExpected = !["history", "version"].includes(action);
|
|
62
62
|
if (extensionExpected && !extensionVersion) {
|
|
63
|
-
process.stderr.write("[tabctl] extension version unavailable
|
|
63
|
+
process.stderr.write("[tabctl] extension version unavailable. Reload the extension in your browser\n");
|
|
64
64
|
}
|
|
65
65
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"name": "Tab Control",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"description": "Archive and manage browser tabs with CLI support",
|
|
6
6
|
"permissions": [
|
|
7
7
|
"tabs",
|
|
@@ -19,5 +19,5 @@
|
|
|
19
19
|
"background": {
|
|
20
20
|
"service_worker": "background.js"
|
|
21
21
|
},
|
|
22
|
-
"version_name": "0.
|
|
22
|
+
"version_name": "0.3.0"
|
|
23
23
|
}
|
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.EXTENSION_DIR_NAME = void 0;
|
|
7
|
+
exports.deriveExtensionId = deriveExtensionId;
|
|
7
8
|
exports.resolveBundledExtensionDir = resolveBundledExtensionDir;
|
|
8
9
|
exports.resolveInstalledExtensionDir = resolveInstalledExtensionDir;
|
|
9
10
|
exports.readExtensionVersion = readExtensionVersion;
|
|
@@ -11,8 +12,17 @@ exports.syncExtension = syncExtension;
|
|
|
11
12
|
exports.checkExtensionSync = checkExtensionSync;
|
|
12
13
|
const path_1 = __importDefault(require("path"));
|
|
13
14
|
const fs_1 = __importDefault(require("fs"));
|
|
15
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
14
16
|
const config_1 = require("./config");
|
|
15
17
|
exports.EXTENSION_DIR_NAME = "extension";
|
|
18
|
+
/**
|
|
19
|
+
* Derive the Chrome/Edge extension ID for an unpacked extension path.
|
|
20
|
+
* Chromium computes: SHA256(absolute_path) → first 32 hex chars → map 0-f to a-p.
|
|
21
|
+
*/
|
|
22
|
+
function deriveExtensionId(extensionDir) {
|
|
23
|
+
const hash = crypto_1.default.createHash("sha256").update(extensionDir).digest("hex").slice(0, 32);
|
|
24
|
+
return hash.split("").map(c => String.fromCharCode("a".charCodeAt(0) + parseInt(c, 16))).join("");
|
|
25
|
+
}
|
|
16
26
|
function resolveBundledExtensionDir() {
|
|
17
27
|
const dir = path_1.default.resolve(__dirname, "../extension");
|
|
18
28
|
const manifest = path_1.default.join(dir, "manifest.json");
|
package/dist/shared/version.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DIRTY = exports.GIT_SHA = exports.VERSION = exports.BASE_VERSION = void 0;
|
|
4
|
-
exports.BASE_VERSION = "0.
|
|
5
|
-
exports.VERSION = "0.
|
|
4
|
+
exports.BASE_VERSION = "0.3.0";
|
|
5
|
+
exports.VERSION = "0.3.0";
|
|
6
6
|
exports.GIT_SHA = null;
|
|
7
7
|
exports.DIRTY = false;
|