@silbercue/chrome 0.2.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.
Files changed (129) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +229 -0
  3. package/build/cache/a11y-tree.d.ts +252 -0
  4. package/build/cache/a11y-tree.js +1956 -0
  5. package/build/cache/index.d.ts +8 -0
  6. package/build/cache/index.js +4 -0
  7. package/build/cache/selector-cache.d.ts +47 -0
  8. package/build/cache/selector-cache.js +119 -0
  9. package/build/cache/session-defaults.d.ts +27 -0
  10. package/build/cache/session-defaults.js +130 -0
  11. package/build/cache/tab-state-cache.d.ts +39 -0
  12. package/build/cache/tab-state-cache.js +171 -0
  13. package/build/cdp/cdp-client.d.ts +25 -0
  14. package/build/cdp/cdp-client.js +146 -0
  15. package/build/cdp/chrome-launcher.d.ts +85 -0
  16. package/build/cdp/chrome-launcher.js +502 -0
  17. package/build/cdp/console-collector.d.ts +53 -0
  18. package/build/cdp/console-collector.js +147 -0
  19. package/build/cdp/debug.d.ts +1 -0
  20. package/build/cdp/debug.js +6 -0
  21. package/build/cdp/dialog-handler.d.ts +54 -0
  22. package/build/cdp/dialog-handler.js +129 -0
  23. package/build/cdp/dom-watcher.d.ts +45 -0
  24. package/build/cdp/dom-watcher.js +195 -0
  25. package/build/cdp/emulation.d.ts +12 -0
  26. package/build/cdp/emulation.js +17 -0
  27. package/build/cdp/index.d.ts +11 -0
  28. package/build/cdp/index.js +6 -0
  29. package/build/cdp/network-collector.d.ts +77 -0
  30. package/build/cdp/network-collector.js +257 -0
  31. package/build/cdp/protocol.d.ts +20 -0
  32. package/build/cdp/protocol.js +1 -0
  33. package/build/cdp/session-manager.d.ts +62 -0
  34. package/build/cdp/session-manager.js +205 -0
  35. package/build/cdp/settle.d.ts +16 -0
  36. package/build/cdp/settle.js +71 -0
  37. package/build/cli/license-commands.d.ts +19 -0
  38. package/build/cli/license-commands.js +199 -0
  39. package/build/cli/top-level-commands.d.ts +49 -0
  40. package/build/cli/top-level-commands.js +222 -0
  41. package/build/hooks/index.d.ts +2 -0
  42. package/build/hooks/index.js +1 -0
  43. package/build/hooks/pro-hooks.d.ts +126 -0
  44. package/build/hooks/pro-hooks.js +17 -0
  45. package/build/index.d.ts +4 -0
  46. package/build/index.js +86 -0
  47. package/build/license/free-tier-config.d.ts +14 -0
  48. package/build/license/free-tier-config.js +18 -0
  49. package/build/license/index.d.ts +4 -0
  50. package/build/license/index.js +2 -0
  51. package/build/license/license-status.d.ts +15 -0
  52. package/build/license/license-status.js +9 -0
  53. package/build/overlay/session-overlay.d.ts +22 -0
  54. package/build/overlay/session-overlay.js +372 -0
  55. package/build/plan/index.d.ts +7 -0
  56. package/build/plan/index.js +4 -0
  57. package/build/plan/plan-conditions.d.ts +12 -0
  58. package/build/plan/plan-conditions.js +242 -0
  59. package/build/plan/plan-executor.d.ts +49 -0
  60. package/build/plan/plan-executor.js +259 -0
  61. package/build/plan/plan-state-store.d.ts +24 -0
  62. package/build/plan/plan-state-store.js +43 -0
  63. package/build/plan/plan-variables.d.ts +16 -0
  64. package/build/plan/plan-variables.js +71 -0
  65. package/build/registry.d.ts +124 -0
  66. package/build/registry.js +884 -0
  67. package/build/server.d.ts +1 -0
  68. package/build/server.js +245 -0
  69. package/build/tools/click.d.ts +34 -0
  70. package/build/tools/click.js +293 -0
  71. package/build/tools/configure-session.d.ts +15 -0
  72. package/build/tools/configure-session.js +45 -0
  73. package/build/tools/console-logs.d.ts +18 -0
  74. package/build/tools/console-logs.js +44 -0
  75. package/build/tools/dom-snapshot.d.ts +13 -0
  76. package/build/tools/dom-snapshot.js +259 -0
  77. package/build/tools/element-utils.d.ts +23 -0
  78. package/build/tools/element-utils.js +133 -0
  79. package/build/tools/error-utils.d.ts +8 -0
  80. package/build/tools/error-utils.js +27 -0
  81. package/build/tools/evaluate.d.ts +34 -0
  82. package/build/tools/evaluate.js +217 -0
  83. package/build/tools/file-upload.d.ts +20 -0
  84. package/build/tools/file-upload.js +174 -0
  85. package/build/tools/fill-form.d.ts +39 -0
  86. package/build/tools/fill-form.js +256 -0
  87. package/build/tools/handle-dialog.d.ts +15 -0
  88. package/build/tools/handle-dialog.js +48 -0
  89. package/build/tools/index.d.ts +35 -0
  90. package/build/tools/index.js +18 -0
  91. package/build/tools/navigate.d.ts +18 -0
  92. package/build/tools/navigate.js +111 -0
  93. package/build/tools/network-monitor.d.ts +18 -0
  94. package/build/tools/network-monitor.js +66 -0
  95. package/build/tools/observe.d.ts +44 -0
  96. package/build/tools/observe.js +339 -0
  97. package/build/tools/press-key.d.ts +33 -0
  98. package/build/tools/press-key.js +155 -0
  99. package/build/tools/read-page.d.ts +22 -0
  100. package/build/tools/read-page.js +100 -0
  101. package/build/tools/run-plan.d.ts +205 -0
  102. package/build/tools/run-plan.js +215 -0
  103. package/build/tools/screenshot.d.ts +16 -0
  104. package/build/tools/screenshot.js +283 -0
  105. package/build/tools/scroll.d.ts +28 -0
  106. package/build/tools/scroll.js +143 -0
  107. package/build/tools/switch-tab.d.ts +26 -0
  108. package/build/tools/switch-tab.js +355 -0
  109. package/build/tools/tab-status.d.ts +7 -0
  110. package/build/tools/tab-status.js +50 -0
  111. package/build/tools/type.d.ts +31 -0
  112. package/build/tools/type.js +247 -0
  113. package/build/tools/virtual-desk.d.ts +7 -0
  114. package/build/tools/virtual-desk.js +108 -0
  115. package/build/tools/visual-constants.d.ts +3 -0
  116. package/build/tools/visual-constants.js +10 -0
  117. package/build/tools/wait-for.d.ts +26 -0
  118. package/build/tools/wait-for.js +323 -0
  119. package/build/transport/index.d.ts +3 -0
  120. package/build/transport/index.js +2 -0
  121. package/build/transport/pipe-transport.d.ts +18 -0
  122. package/build/transport/pipe-transport.js +63 -0
  123. package/build/transport/transport.d.ts +8 -0
  124. package/build/transport/transport.js +1 -0
  125. package/build/transport/websocket-transport.d.ts +22 -0
  126. package/build/transport/websocket-transport.js +200 -0
  127. package/build/types.d.ts +21 -0
  128. package/build/types.js +1 -0
  129. package/package.json +62 -0
@@ -0,0 +1,199 @@
1
+ /**
2
+ * CLI commands for license management.
3
+ * Story 9.4: Thin CLI layer — reads/deletes cache directly.
4
+ * Story 15.5: LicenseValidator entfernt, activate gibt Pro-Feature-Hinweis.
5
+ */
6
+ import * as fs from "fs";
7
+ import * as path from "path";
8
+ import * as os from "os";
9
+ /** Grace period constant (7 days). */
10
+ const GRACE_PERIOD_MS = 604_800_000;
11
+ /** Default cache directory. */
12
+ function getCacheDir() {
13
+ return path.join(os.homedir(), ".silbercuechrome");
14
+ }
15
+ /**
16
+ * Parses CLI args and dispatches to the correct subcommand.
17
+ * Exported for testability — `src/index.ts` calls this.
18
+ */
19
+ export async function runLicenseCommand(args) {
20
+ const subcommand = args[0];
21
+ switch (subcommand) {
22
+ case "status":
23
+ return licenseStatus();
24
+ case "activate":
25
+ return licenseActivate(args[1]);
26
+ case "deactivate":
27
+ return licenseDeactivate();
28
+ default:
29
+ printUsage();
30
+ process.exit(1);
31
+ }
32
+ }
33
+ /**
34
+ * Parses CLI arguments and returns the parsed command.
35
+ * Pure function — exported for unit-testing the routing logic
36
+ * without side effects.
37
+ */
38
+ export function parseLicenseCommand(argv) {
39
+ // argv is process.argv.slice(3), i.e. everything after "license"
40
+ const subcommand = argv[0];
41
+ const key = argv[1];
42
+ return { subcommand, key };
43
+ }
44
+ /**
45
+ * Masks a license key for display: first 4 + "..." + last 4.
46
+ * Keys shorter than 10 characters are fully masked.
47
+ */
48
+ export function maskKey(key) {
49
+ if (!key || key.length < 10)
50
+ return "****";
51
+ return `${key.slice(0, 4)}...${key.slice(-4)}`;
52
+ }
53
+ // ---------------------------------------------------------------------------
54
+ // Subcommands
55
+ // ---------------------------------------------------------------------------
56
+ /** `license status` — read-only, no remote call. */
57
+ async function licenseStatus() {
58
+ const cacheDir = getCacheDir();
59
+ const cache = readCacheDirectly(cacheDir);
60
+ console.log("SilbercueChrome License Status");
61
+ console.log("===============================");
62
+ if (!cache) {
63
+ console.log("Tier: Free");
64
+ console.log("License Key: Nicht konfiguriert");
65
+ console.log("");
66
+ console.log("Um Pro zu aktivieren: silbercuechrome license activate <key>");
67
+ return;
68
+ }
69
+ if (cache.valid) {
70
+ console.log("Tier: Pro");
71
+ console.log(`License Key: ${maskKey(cache.key)}`);
72
+ console.log(`Last Check: ${formatDate(cache.lastCheck)}`);
73
+ console.log(`Gueltig bis: ${formatValidUntil(cache)}`);
74
+ const gracePeriodInfo = formatGracePeriod(cache.lastCheck);
75
+ if (gracePeriodInfo) {
76
+ console.log(`Grace Period: ${gracePeriodInfo}`);
77
+ }
78
+ if (cache.features && cache.features.length > 0) {
79
+ console.log(`Features: ${cache.features.join(", ")}`);
80
+ }
81
+ }
82
+ else {
83
+ console.log("Tier: Free");
84
+ console.log(`License Key: ${maskKey(cache.key)}`);
85
+ console.log("Status: Key ungueltig");
86
+ console.log("");
87
+ console.log("Um Pro zu aktivieren: silbercuechrome license activate <key>");
88
+ }
89
+ }
90
+ /**
91
+ * `license activate <key>` — Pro-Feature: Hinweis auf SilbercueChrome Pro.
92
+ * Story 15.5: LicenseValidator ist im Pro-Repo, activate ist nur dort verfuegbar.
93
+ */
94
+ async function licenseActivate(_key) {
95
+ console.log("License-Aktivierung ist ein Pro-Feature.");
96
+ console.log("Installiere SilbercueChrome Pro fuer License-Key-Validierung:");
97
+ console.log(" npm install silbercuechrome-pro");
98
+ console.log("");
99
+ console.log("Mehr Infos: https://silbercuechrome.com/pro");
100
+ process.exit(1);
101
+ }
102
+ /** `license deactivate` — deletes cache file. */
103
+ function licenseDeactivate() {
104
+ const cacheDir = getCacheDir();
105
+ const cachePath = path.join(cacheDir, "license-cache.json");
106
+ try {
107
+ fs.unlinkSync(cachePath);
108
+ }
109
+ catch (err) {
110
+ const code = err.code;
111
+ if (code !== "ENOENT") {
112
+ console.log(`Fehler beim Loeschen der Cache-Datei: ${err.message}`);
113
+ process.exit(1);
114
+ return;
115
+ }
116
+ // ENOENT — file doesn't exist, that's fine (idempotent)
117
+ }
118
+ console.log("License deaktiviert — Server laeuft im Free-Tier.");
119
+ console.log("Um Pro wieder zu aktivieren: silbercuechrome license activate <key>");
120
+ process.exit(0);
121
+ }
122
+ /** Prints usage help for unknown subcommands. */
123
+ function printUsage() {
124
+ console.log("SilbercueChrome License Management");
125
+ console.log("");
126
+ console.log("Usage:");
127
+ console.log(" silbercuechrome license status Lizenz-Status anzeigen");
128
+ console.log(" silbercuechrome license activate <key> License-Key aktivieren");
129
+ console.log(" silbercuechrome license deactivate License-Key deaktivieren");
130
+ }
131
+ // ---------------------------------------------------------------------------
132
+ // Helpers
133
+ // ---------------------------------------------------------------------------
134
+ /** Reads the cache file directly (no remote call). */
135
+ function readCacheDirectly(cacheDir) {
136
+ try {
137
+ const raw = fs.readFileSync(path.join(cacheDir, "license-cache.json"), "utf-8");
138
+ const parsed = JSON.parse(raw);
139
+ // Runtime validation — reject structurally invalid cache
140
+ if (typeof parsed.valid !== "boolean" ||
141
+ typeof parsed.lastCheck !== "string" ||
142
+ typeof parsed.key !== "string") {
143
+ return null;
144
+ }
145
+ return parsed;
146
+ }
147
+ catch {
148
+ return null;
149
+ }
150
+ }
151
+ /** Formats an ISO date string for human-readable display. */
152
+ function formatDate(isoString) {
153
+ const ts = Date.parse(isoString);
154
+ if (Number.isNaN(ts))
155
+ return "Unbekannt";
156
+ const d = new Date(ts);
157
+ const yyyy = d.getUTCFullYear();
158
+ const mm = String(d.getUTCMonth() + 1).padStart(2, "0");
159
+ const dd = String(d.getUTCDate()).padStart(2, "0");
160
+ const hh = String(d.getUTCHours()).padStart(2, "0");
161
+ const min = String(d.getUTCMinutes()).padStart(2, "0");
162
+ return `${yyyy}-${mm}-${dd} ${hh}:${min} UTC`;
163
+ }
164
+ /**
165
+ * Formats the grace-period status for display.
166
+ * Returns null if lastCheck is invalid or not applicable.
167
+ */
168
+ function formatGracePeriod(lastCheck) {
169
+ const ts = Date.parse(lastCheck);
170
+ if (Number.isNaN(ts))
171
+ return null;
172
+ const age = Date.now() - ts;
173
+ if (age < 0)
174
+ return "Unbekannt (Systemzeit-Problem)";
175
+ const remaining = GRACE_PERIOD_MS - age;
176
+ if (remaining <= 0)
177
+ return "Abgelaufen";
178
+ const days = Math.floor(remaining / (24 * 60 * 60 * 1000));
179
+ const hours = Math.floor((remaining % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000));
180
+ if (days > 0) {
181
+ return `${days} Tag${days !== 1 ? "e" : ""} ${hours} Stunde${hours !== 1 ? "n" : ""} verbleibend`;
182
+ }
183
+ return `${hours} Stunde${hours !== 1 ? "n" : ""} verbleibend`;
184
+ }
185
+ /**
186
+ * Formats the "valid until" date from cache.
187
+ * If validUntil is present in the cache, uses that directly.
188
+ * Otherwise falls back to lastCheck + 7 days (grace period).
189
+ */
190
+ function formatValidUntil(cache) {
191
+ if (cache.validUntil) {
192
+ return formatDate(cache.validUntil);
193
+ }
194
+ // Fallback: lastCheck + grace period (7 days)
195
+ const ts = Date.parse(cache.lastCheck);
196
+ if (Number.isNaN(ts))
197
+ return "Unbekannt";
198
+ return formatDate(new Date(ts + GRACE_PERIOD_MS).toISOString());
199
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Anzahl Tools die der Free-Tier MCP-Server registriert.
3
+ *
4
+ * WICHTIG: Diese Konstante MUSS aktuell gehalten werden, wenn Tools im
5
+ * Registry hinzugefuegt oder entfernt werden. Quelle der Wahrheit ist der
6
+ * smoke-test (`test-hardest/smoke-test.mjs`) — bei Aenderungen muss die
7
+ * Zahl hier nachgezogen werden.
8
+ *
9
+ * Stand 2026-04-07 (nach Phase 1): 21 Free-Tools (3 Tools sind Pro-gated:
10
+ * dom_snapshot, switch_tab, virtual_desk → werden ueber featureGate
11
+ * geblockt aber trotzdem in tools/list angezeigt).
12
+ *
13
+ * Free-User sehen also 21 nutzbare + 3 gated = 22 Tools insgesamt.
14
+ * Pro-Zaehlung in der Pro-Variante: 22 + inspect_element = 23.
15
+ */
16
+ export declare const FREE_TIER_TOOL_COUNT = 21;
17
+ /**
18
+ * URL fuer Pro-Upgrade. Wird in `status`-Output und Aktivierungs-Hinweisen
19
+ * gezeigt.
20
+ */
21
+ export declare const UPGRADE_URL = "https://polar.sh/silbercuechrome/silbercuechrome-pro";
22
+ /**
23
+ * Liest die Version aus `package.json` relativ zur kompilierten JS-Datei.
24
+ *
25
+ * Robustness: Sucht von `import.meta.url` ausgehend nach oben — funktioniert
26
+ * sowohl im `build/`-Layout als auch im `src/`-Layout (Tests via vitest).
27
+ *
28
+ * SEA-Path (Phase 3b): In einem Single-Executable-Application-Bundle gibt es
29
+ * keinen filesystem-Pfad zur `package.json`. Stattdessen injiziert das
30
+ * Build-Skript Name + Version als esbuild `--define`-Konstanten. Diese werden
31
+ * via `typeof`-Guard erkannt — im Source-Mode bleibt die Konstante undefined
32
+ * und wir fallen auf den fs-Pfad zurueck.
33
+ */
34
+ export declare function readPackageVersion(currentFileUrl: string): {
35
+ name: string;
36
+ version: string;
37
+ };
38
+ /**
39
+ * Pruft das erste CLI-Argument und dispatcht zu einem Subcommand.
40
+ * Returns:
41
+ * - `true` → Subcommand wurde erkannt und ausgefuehrt (Caller MUSS exit-en).
42
+ * - `false` → Kein Subcommand erkannt, normaler Server-Start ist erlaubt.
43
+ *
44
+ * Side-effects: ruft `process.exit()` direkt am Ende eines Subcommands
45
+ * (zur Klarheit + um Server-Start zu verhindern).
46
+ */
47
+ export declare function dispatchTopLevelCli(argv: string[], currentFileUrl: string): Promise<boolean>;
48
+ /** Internal helper for tests — exposes the known subcommand list. */
49
+ export declare function getKnownSubcommands(): readonly string[];
@@ -0,0 +1,222 @@
1
+ /**
2
+ * Top-Level CLI Subcommands fuer SilbercueChrome (Free Tier).
3
+ *
4
+ * Phase 2 (Distribution-Setup): analog zum SilbercueSwift main.swift Pattern.
5
+ * Wird VOR `startServer()` in `src/index.ts` aufgerufen. Bei Match:
6
+ * Subcommand ausfuehren + `process.exit(0|1)`. Sonst: false zurueckgeben,
7
+ * damit der MCP-Server normal startet.
8
+ *
9
+ * Verfuegbare Subcommands (Free):
10
+ * silbercuechrome version — Version anzeigen
11
+ * silbercuechrome status — Free Tier Status + Tool-Anzahl
12
+ * silbercuechrome activate <KEY> — Pro-Feature-Hinweis (nur in Pro verfuegbar)
13
+ * silbercuechrome deactivate — Pro-Feature-Hinweis (nur in Pro verfuegbar)
14
+ * silbercuechrome --help / -h — Help-Text
15
+ *
16
+ * Diese Datei enthaelt KEINE Pro-Code-Imports — der Free-Repo darf NIEMALS
17
+ * vom Pro-Repo abhaengen (Story 15.x Constraint).
18
+ */
19
+ import * as fs from "fs";
20
+ import * as path from "path";
21
+ import * as os from "os";
22
+ import { fileURLToPath } from "node:url";
23
+ /**
24
+ * Anzahl Tools die der Free-Tier MCP-Server registriert.
25
+ *
26
+ * WICHTIG: Diese Konstante MUSS aktuell gehalten werden, wenn Tools im
27
+ * Registry hinzugefuegt oder entfernt werden. Quelle der Wahrheit ist der
28
+ * smoke-test (`test-hardest/smoke-test.mjs`) — bei Aenderungen muss die
29
+ * Zahl hier nachgezogen werden.
30
+ *
31
+ * Stand 2026-04-07 (nach Phase 1): 21 Free-Tools (3 Tools sind Pro-gated:
32
+ * dom_snapshot, switch_tab, virtual_desk → werden ueber featureGate
33
+ * geblockt aber trotzdem in tools/list angezeigt).
34
+ *
35
+ * Free-User sehen also 21 nutzbare + 3 gated = 22 Tools insgesamt.
36
+ * Pro-Zaehlung in der Pro-Variante: 22 + inspect_element = 23.
37
+ */
38
+ export const FREE_TIER_TOOL_COUNT = 21;
39
+ /**
40
+ * URL fuer Pro-Upgrade. Wird in `status`-Output und Aktivierungs-Hinweisen
41
+ * gezeigt.
42
+ */
43
+ export const UPGRADE_URL = "https://polar.sh/silbercuechrome/silbercuechrome-pro";
44
+ /** Liste der bekannten Free-Subcommands fuer Dispatch + Help. */
45
+ const KNOWN_SUBCOMMANDS = [
46
+ "version",
47
+ "--version",
48
+ "-v",
49
+ "status",
50
+ "activate",
51
+ "deactivate",
52
+ "license", // bestehender Subcommand (siehe license-commands.ts)
53
+ "help",
54
+ "--help",
55
+ "-h",
56
+ ];
57
+ /**
58
+ * Liest die Version aus `package.json` relativ zur kompilierten JS-Datei.
59
+ *
60
+ * Robustness: Sucht von `import.meta.url` ausgehend nach oben — funktioniert
61
+ * sowohl im `build/`-Layout als auch im `src/`-Layout (Tests via vitest).
62
+ *
63
+ * SEA-Path (Phase 3b): In einem Single-Executable-Application-Bundle gibt es
64
+ * keinen filesystem-Pfad zur `package.json`. Stattdessen injiziert das
65
+ * Build-Skript Name + Version als esbuild `--define`-Konstanten. Diese werden
66
+ * via `typeof`-Guard erkannt — im Source-Mode bleibt die Konstante undefined
67
+ * und wir fallen auf den fs-Pfad zurueck.
68
+ */
69
+ export function readPackageVersion(currentFileUrl) {
70
+ // Build-time constants (SEA / bundled mode)
71
+ if (typeof __SCC_VERSION__ === "string" &&
72
+ __SCC_VERSION__ !== "" &&
73
+ typeof __SCC_NAME__ === "string" &&
74
+ __SCC_NAME__ !== "") {
75
+ return { name: __SCC_NAME__, version: __SCC_VERSION__ };
76
+ }
77
+ try {
78
+ const here = fileURLToPath(currentFileUrl);
79
+ let dir = path.dirname(here);
80
+ // Hoch-Suche nach package.json (max 6 Ebenen, um Endlosschleifen
81
+ // bei symlink-Loops zu verhindern).
82
+ for (let i = 0; i < 6; i++) {
83
+ const candidate = path.join(dir, "package.json");
84
+ if (fs.existsSync(candidate)) {
85
+ const raw = fs.readFileSync(candidate, "utf-8");
86
+ const pkg = JSON.parse(raw);
87
+ return {
88
+ name: pkg.name ?? "@silbercue/chrome",
89
+ version: pkg.version ?? "0.0.0",
90
+ };
91
+ }
92
+ const parent = path.dirname(dir);
93
+ if (parent === dir)
94
+ break;
95
+ dir = parent;
96
+ }
97
+ }
98
+ catch {
99
+ // Fall through to fallback below.
100
+ }
101
+ return { name: "@silbercue/chrome", version: "0.0.0" };
102
+ }
103
+ /** Liest Cache-Datei direkt — kein Remote-Call. */
104
+ function readLicenseCache() {
105
+ try {
106
+ const cachePath = path.join(os.homedir(), ".silbercuechrome", "license-cache.json");
107
+ const raw = fs.readFileSync(cachePath, "utf-8");
108
+ const parsed = JSON.parse(raw);
109
+ if (typeof parsed.valid !== "boolean" ||
110
+ typeof parsed.lastCheck !== "string" ||
111
+ typeof parsed.key !== "string") {
112
+ return null;
113
+ }
114
+ return parsed;
115
+ }
116
+ catch {
117
+ return null;
118
+ }
119
+ }
120
+ /**
121
+ * Pruft das erste CLI-Argument und dispatcht zu einem Subcommand.
122
+ * Returns:
123
+ * - `true` → Subcommand wurde erkannt und ausgefuehrt (Caller MUSS exit-en).
124
+ * - `false` → Kein Subcommand erkannt, normaler Server-Start ist erlaubt.
125
+ *
126
+ * Side-effects: ruft `process.exit()` direkt am Ende eines Subcommands
127
+ * (zur Klarheit + um Server-Start zu verhindern).
128
+ */
129
+ export async function dispatchTopLevelCli(argv, currentFileUrl) {
130
+ const command = argv[2];
131
+ if (!command)
132
+ return false;
133
+ // Sub-Subcommand "license <...>" wird vom existierenden license-commands.ts
134
+ // Pfad in src/index.ts behandelt — hier NICHT abfangen.
135
+ if (command === "license")
136
+ return false;
137
+ switch (command) {
138
+ case "version":
139
+ case "--version":
140
+ case "-v": {
141
+ const { name, version } = readPackageVersion(currentFileUrl);
142
+ console.log(`${name} ${version}`);
143
+ process.exit(0);
144
+ // unreachable but keeps tsc happy in mocked-exit tests
145
+ return true;
146
+ }
147
+ case "status": {
148
+ const { name, version } = readPackageVersion(currentFileUrl);
149
+ const cache = readLicenseCache();
150
+ console.log(`${name} ${version}`);
151
+ console.log("");
152
+ // Free-Repo sieht IMMER Free-Tier (auch wenn ein Pro-Cache existiert,
153
+ // weil der Validator im Pro-Repo lebt). Wir zeigen aber, ob ein Cache
154
+ // existiert, damit der User Bescheid weiss.
155
+ console.log(`Tier: Free`);
156
+ console.log(`Tools: ${FREE_TIER_TOOL_COUNT} available`);
157
+ if (cache && cache.valid) {
158
+ console.log("");
159
+ console.log("A license cache was found, but license validation requires");
160
+ console.log("the Pro tier. Install @silbercue/chrome-pro to activate.");
161
+ }
162
+ console.log("");
163
+ console.log(`Upgrade to Pro: ${UPGRADE_URL}`);
164
+ process.exit(0);
165
+ return true;
166
+ }
167
+ case "activate": {
168
+ console.log("License activation requires the Pro tier.");
169
+ console.log("");
170
+ console.log("Install SilbercueChrome Pro to validate license keys:");
171
+ console.log(" npm install -g @silbercue/chrome-pro");
172
+ console.log("");
173
+ console.log(`More info: ${UPGRADE_URL}`);
174
+ process.exit(1);
175
+ return true;
176
+ }
177
+ case "deactivate": {
178
+ console.log("License deactivation requires the Pro tier.");
179
+ console.log("");
180
+ console.log("Install SilbercueChrome Pro to manage license keys:");
181
+ console.log(" npm install -g @silbercue/chrome-pro");
182
+ console.log("");
183
+ console.log(`More info: ${UPGRADE_URL}`);
184
+ process.exit(1);
185
+ return true;
186
+ }
187
+ case "help":
188
+ case "--help":
189
+ case "-h": {
190
+ printHelp();
191
+ process.exit(0);
192
+ return true;
193
+ }
194
+ default:
195
+ // Unbekannter Subcommand → Server-Start erlauben (z.B. fuer
196
+ // zukuenftige Subcommands oder MCP-Stdio-Modus ohne argv).
197
+ return false;
198
+ }
199
+ }
200
+ /** Druckt den Free-Tier Help-Text. */
201
+ function printHelp() {
202
+ console.log("SilbercueChrome MCP Server (Free Tier)");
203
+ console.log("");
204
+ console.log("Usage:");
205
+ console.log(" silbercuechrome [command]");
206
+ console.log("");
207
+ console.log("Commands:");
208
+ console.log(" version Show version information");
209
+ console.log(" status Show current tier and tool count");
210
+ console.log(" activate <KEY> Activate Pro license (requires Pro tier)");
211
+ console.log(" deactivate Deactivate Pro license (requires Pro tier)");
212
+ console.log(" license <subcommand> License management (status/activate/deactivate)");
213
+ console.log(" help Show this help text");
214
+ console.log("");
215
+ console.log("Without a command, starts the MCP server on stdio.");
216
+ console.log("");
217
+ console.log(`Upgrade to Pro: ${UPGRADE_URL}`);
218
+ }
219
+ /** Internal helper for tests — exposes the known subcommand list. */
220
+ export function getKnownSubcommands() {
221
+ return KNOWN_SUBCOMMANDS;
222
+ }
@@ -0,0 +1,2 @@
1
+ export type { ProHooks, ToolRegistryPublic, A11yTreePublic, A11yTreeDiffs, } from "./pro-hooks.js";
2
+ export { registerProHooks, getProHooks, proFeatureError } from "./pro-hooks.js";
@@ -0,0 +1 @@
1
+ export { registerProHooks, getProHooks, proFeatureError } from "./pro-hooks.js";
@@ -0,0 +1,126 @@
1
+ import type { ToolResponse } from "../types.js";
2
+ import type { LicenseStatus } from "../license/license-status.js";
3
+ import type { PlanStep, ErrorStrategy } from "../plan/plan-executor.js";
4
+ import type { VarsMap } from "../plan/plan-variables.js";
5
+ import type { CdpClient } from "../cdp/cdp-client.js";
6
+ import type { SessionManager } from "../cdp/session-manager.js";
7
+ import type { ElementClassification, SnapshotMap, DOMChange } from "../cache/a11y-tree.js";
8
+ /**
9
+ * Story 15.2: Minimales Public-Interface, das das Pro-Repo verwendet,
10
+ * um zusaetzliche MCP-Tools zu registrieren. Dependency Inversion — das
11
+ * Pro-Repo muss nicht die volle `ToolRegistry`-Klasse kennen.
12
+ */
13
+ export interface ToolRegistryPublic {
14
+ /**
15
+ * Registriert ein neues MCP-Tool in der Free-Repo-Registry.
16
+ * Wird vom Pro-Repo ueber den `registerProTools`-Hook aufgerufen.
17
+ */
18
+ registerTool(name: string, description: string, schema: Record<string, unknown>, handler: (params: Record<string, unknown>, sessionIdOverride?: string) => Promise<ToolResponse>): void;
19
+ /** Story 16.4: CDP-Client fuer Pro-Tool-Handler (z.B. inspect_element). */
20
+ readonly cdpClient: CdpClient;
21
+ /** Story 16.4: Aktuelle SessionId — aendert sich bei Tab-Wechsel/Reconnect. */
22
+ readonly sessionId: string;
23
+ /** Story 16.4: SessionManager fuer OOPIF-Support (optional). */
24
+ readonly sessionManager?: SessionManager;
25
+ }
26
+ /**
27
+ * Story 15.3: Public-Interface fuer den a11yTree-Cache.
28
+ * Das Pro-Repo verwendet diese Methoden im onToolResult-Hook fuer die
29
+ * 3-Stufen-Klick-Analyse (classifyRef → waitForAXChange → diffSnapshots → formatDomDiff).
30
+ *
31
+ * `diffSnapshots` und `formatDomDiff` sind logisch Static-Methoden des
32
+ * Tree-Processors, werden aber ZUSAETZLICH hier exponiert, damit das Pro-Repo
33
+ * die gesamte 3-Stufen-Analyse ueber ein einziges `context.a11yTree`-Objekt
34
+ * fahren kann (siehe AC #5).
35
+ */
36
+ export interface A11yTreePublic {
37
+ /** Klassifiziert ein Ref (widget-state/clickable/disabled/static). 0 CDP-Calls. */
38
+ classifyRef(ref: string): ElementClassification;
39
+ /** Leichtgewichtiger Snapshot fuer DOM-Diff. 0 CDP-Calls. */
40
+ getSnapshotMap(): SnapshotMap;
41
+ /** Compact Snapshot mit Headings/Alerts/Interaktiven Elementen. 0 CDP-Calls. */
42
+ getCompactSnapshot(maxTokens?: number): string | null;
43
+ /** Haelt den Tree frisch — liest via CDP Accessibility.getFullAXTree. */
44
+ refreshPrecomputed(client: CdpClient, sessionId: string, manager?: SessionManager): Promise<void>;
45
+ /** Setzt den Cache zurueck (bei Navigate oder SPA-Route-Wechsel). */
46
+ reset(): void;
47
+ /** Aktuelle URL des letzten Refreshs — fuer Diff-Header. */
48
+ readonly currentUrl: string;
49
+ /** Berechnet den Diff zweier Snapshots (delegiert an A11yTreeProcessor). */
50
+ diffSnapshots(before: SnapshotMap, after: SnapshotMap): DOMChange[];
51
+ /** Formatiert einen Diff als LLM-taugliche Kontextzeile. */
52
+ formatDomDiff(changes: DOMChange[], url?: string): string | null;
53
+ }
54
+ /**
55
+ * Story 15.3: Public-Interface fuer die Static-Methoden des Tree-Processors.
56
+ * `diffSnapshots` und `formatDomDiff` sind Static-Methoden auf `A11yTreeProcessor`;
57
+ * sie werden als separates Objekt im Hook-Context uebergeben, um die Instance-API
58
+ * (`A11yTreePublic`) sauber getrennt zu halten.
59
+ *
60
+ * Hinweis: Die gleichen Methoden sind auch direkt auf `A11yTreePublic`
61
+ * verfuegbar — `A11yTreeDiffs` bleibt als Backward-Compat-Alias erhalten.
62
+ */
63
+ export interface A11yTreeDiffs {
64
+ diffSnapshots(before: SnapshotMap, after: SnapshotMap): DOMChange[];
65
+ formatDomDiff(changes: DOMChange[], url?: string): string | null;
66
+ }
67
+ /** Erweiterungspunkte fuer Pro-Features. */
68
+ export interface ProHooks {
69
+ /** Prueft ob ein Tool im aktuellen Lizenz-Tier ausfuehrbar ist. */
70
+ featureGate?: (toolName: string) => {
71
+ allowed: boolean;
72
+ message?: string;
73
+ };
74
+ /** Modifiziert Tool-Parameter vor der Ausfuehrung. Null = keine Aenderung. */
75
+ enhanceTool?: (toolName: string, params: Record<string, unknown>) => Record<string, unknown> | null;
76
+ /**
77
+ * Story 15.3: Modifiziert die Tool-Response nach der Ausfuehrung —
78
+ * zentrales Ambient-Context-Enrichment-Hook. Async + Context-Parameter.
79
+ *
80
+ * Breaking Change gegenueber der alten Sync-Signatur `(name, result) => ToolResponse`.
81
+ * Der Pro-Repo implementiert hier die 3-Stufen-Klick-Analyse
82
+ * (classifyRef → waitForAXChange → diffSnapshots → formatDomDiff).
83
+ */
84
+ onToolResult?: (toolName: string, result: ToolResponse, context: {
85
+ a11yTree: A11yTreePublic;
86
+ a11yTreeDiffs: A11yTreeDiffs;
87
+ waitForAXChange?: (timeoutMs: number) => Promise<boolean>;
88
+ cdpClient: CdpClient;
89
+ sessionId: string;
90
+ sessionManager?: SessionManager;
91
+ }) => Promise<ToolResponse>;
92
+ /** Liefert den LicenseStatus — Pro-Repo injiziert hier den LicenseValidator. */
93
+ provideLicenseStatus?: () => Promise<LicenseStatus>;
94
+ /** Pro-Repo registriert hier die Multi-Tab-Parallel-Engine (Story 15.4). */
95
+ executeParallel?: (groups: Array<{
96
+ tab: string;
97
+ steps: PlanStep[];
98
+ }>, registryFactory: (tabTargetId: string) => Promise<{
99
+ executeTool: (name: string, params: Record<string, unknown>) => Promise<ToolResponse>;
100
+ }>, options?: {
101
+ vars?: VarsMap;
102
+ errorStrategy?: ErrorStrategy;
103
+ concurrencyLimit?: number;
104
+ }) => Promise<ToolResponse>;
105
+ /**
106
+ * Story 15.2: Pro-Repo registriert hier zusaetzliche MCP-Tools
107
+ * (z.B. inspect_element). Wird einmalig waehrend
108
+ * `ToolRegistry.registerAll()` aufgerufen.
109
+ */
110
+ registerProTools?: (registry: ToolRegistryPublic) => void;
111
+ /**
112
+ * Story 15.2: Pro-Repo modifiziert das evaluate-Result fuer
113
+ * Visual Feedback (Geometry-Diff + Clip-Screenshot). Wird nur
114
+ * fuer erfolgreiche Eval-Calls aufgerufen.
115
+ */
116
+ enhanceEvaluateResult?: (expression: string, result: ToolResponse, context: {
117
+ cdpClient: CdpClient;
118
+ sessionId?: string;
119
+ }) => Promise<ToolResponse>;
120
+ }
121
+ /** Registriert Pro-Hook-Implementierungen. Aufgerufen vom Pro-Repo vor startServer(). */
122
+ export declare function registerProHooks(hooks: ProHooks): void;
123
+ /** Gibt die aktuell registrierten Hooks zurueck. */
124
+ export declare function getProHooks(): ProHooks;
125
+ /** Einheitliche Pro-Feature Error-Response. */
126
+ export declare function proFeatureError(toolName: string): ToolResponse;
@@ -0,0 +1,17 @@
1
+ let _hooks = {};
2
+ /** Registriert Pro-Hook-Implementierungen. Aufgerufen vom Pro-Repo vor startServer(). */
3
+ export function registerProHooks(hooks) {
4
+ _hooks = hooks;
5
+ }
6
+ /** Gibt die aktuell registrierten Hooks zurueck. */
7
+ export function getProHooks() {
8
+ return _hooks;
9
+ }
10
+ /** Einheitliche Pro-Feature Error-Response. */
11
+ export function proFeatureError(toolName) {
12
+ return {
13
+ content: [{ type: "text", text: `${toolName} ist ein Pro-Feature — aktiviere mit 'silbercuechrome license activate <key>'` }],
14
+ isError: true,
15
+ _meta: { elapsedMs: 0, method: toolName },
16
+ };
17
+ }
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ export { startServer } from "./server.js";
3
+ export { runLicenseCommand } from "./cli/license-commands.js";
4
+ export { dispatchTopLevelCli } from "./cli/top-level-commands.js";